次に、不互換性の問題から、Model Context Protocol(MCP)が誕生しました。私たちの日常生活において、不互換性はさまざまな形で不便をもたらします。
海外旅行にヘアアイロンや電子機器を持参した際、そのプラグがコンセントと合わないことに気付いた経験はありませんか?開発者の視点から見ると、この問題は、AIエージェント用にAPIや開発ツールを構築したものの、正しく接続できなかったり、正しく呼び出せなかったりするのと同じくらい、もどかしいものです。まさにここで、MCPがこの不互換性の問題を軽減します。
2024年にAnthropic社によって導入されたModel Context Protocol(MCP)は、AIアプリケーションが、 ツール、データ・ソース/データ・セット、定義済みテンプレートなどの外部サービスと効果的に通信するための標準化レイヤーとして機能します。MCPは本質的に、AIとツールの相互作用のためのオープン標準およびコネクターとして機能します。MCPアーキテクチャーは、3つの主要なアーキテクチャー・コンポーネントに分解できます。
まず、 IBM Bobとは何でしょうか。IBM Bobは、生成AIを活用した 統合開発環境(IDE)およびモダナイゼーション・アシスタントです。Bobを、お客様のAIファーストのIDEおよびペア開発者として捉えてください。これは、お客様の意図、コードベース、および組織の標準を理解するツールです。
独自のMCPサーバーをスクラッチから構築することは、特に初心者の開発者にとって時間がかかる場合があります。代わりに、このチュートリアルでは、いくつかのシンプルな自然言語プロンプトを使用して、IBM Bobでこのワークフローをクイックスタートする方法について説明します。
MCP統合は、外部のツールやサービスに接続することでBobの機能を拡張し、グローバル(すべてのワークスペースに適用)またはプロジェクト(.Bob/mcp.jsonを通じてチームで共有可能)レベルで構成できます。MCPは2つのトランスポート・タイプをサポートしています。ローカルの低遅延サーバー用の標準入出力(STDIO)と、HTTP/HTTPS経由でアクセス可能なリモートMCPサーバー用のサーバー送信イベント(SSE)です。ユーザーは、Bobの設定メニューにあるJSONファイルを使用してサーバーを構成し、コマンド、環境変数、および自動承認されたツールを定義できます。どちらのトランスポート・タイプでも、サーバーの有効化または無効化、特定のツールの自動承認、およびBobのMCP設定パネルを通じたそれらの運用の管理が可能です。
始めましょう。GitHub上でこのチュートリアルに沿って進める場合は、私たちの リポジトリーを確認してください。
1. 前提条件としてインストールしたIBM Bob IDEを開き、新しいAIコーディング・コンパニオンのレイアウトに慣れてください。
2. MCP設定パネルにアクセスするには、チャット・ウィンドウの右上の歯車アイコンの横にある3つのドットをクリックします。次に、ドロップダウン・メニューから「MCP servers」を選択します。
ここでは、グローバルまたはサーバーごとにMCPを有効化または無効化し、ツール(例えば、自動承認、削除、または再起動)を管理できます。Bob Marketplaceを通じてコミュニティー・サーバーを探索したり、MCP SDKを使用して独自のサーバーを構築したりすることもできます。
Bobマーケットプレイスからサーバーをインストールすることを選択した場合、構成を2つのレベルで設定できることに気が付きます。それは、グローバル(
プロジェクト・レベルの設定はグローバルな設定を上書きするため、さまざまなユースケースに合わせてMCPの動作を柔軟にカスタマイズできます。これらの構成を管理するには、Bobの「設定」メニューからJSONファイルを直接編集できます。ここで、コマンド、環境変数、および自動承認ツールなどのサーバーの詳細を定義します。このチュートリアルでは、SDKを使用します。
3. BobでカスタムMCPサーバーを作成するために、「MCPサーバー作成の有効化」設定が有効になっていることを確認してください。
4. プロジェクトをセットアップする優先ディレクトリーがある場合は、ご自身でIDE内で開くか、チャット・ウィンドウでBobに開かせることができます。
3. プロジェクトの依存関係を隔離して異なるプロジェクト間で競合が発生しないようにするために、仮想Python環境を作成するのが一般的な方法です。これを行うには、「In this directory, activate a Python virtual environment.」というプロンプトを入力します。
4. Bobが端末コマンドの一連の処理を実行するのが表示されるはずです。これらのコマンドは、通常以下のようになります:
Bobがリアルタイムで実行する前に各コマンドを承認または拒否できるように、自動承認トグルは無効のままにしておくことをお勧めします。
Bobは
仮想環境がセットアップされたので、MCPサーバーの作成に進むことができます。Bob、あるいはそのことについてはすべてのAIモデルやAIアシスタントにコードの生成を指示する際、重要な詳細を含めることが役立ちます。稼働中のBobを確認するために、以下のプロンプトを送信してみましょう。
「arXivへの読み取り専用アクセスを提供するMCPサーバーを作成してください。サーバーは以下を行う必要があります。
この1つのシンプルなプロンプトによって、Bobはタスクを理解し、タスクを完了するための一連のステップの「To-Doリスト」を作成するのに十分な情報を得られます。リストには、MCPサーバーの作成だけでなく、その構成とテストも含まれていることに注目してください。素晴らしいです。
注:このチュートリアルでは、開始するのにAPIキーや認証を必要としないシンプルな例として、arXiv APIを使用します。ただし、これは一例であり、Bobは必要な権限を伴うより複雑なサーバーを処理するための機能も十分に備えています。
各コマンドが実行される前に、そのアクションを承認または拒否できます。コマンドが自動的に実行されていることに気付いた場合は、自動承認トグルが有効になっている可能性があります。
2. 次に、Bobは
{
"name": "arxiv-server",
"version": "0.1.0",
"description": "MCP server for read-only access to arXiv papers",
"type": "module",
"bin": {
"arxiv-server": "./build/index.js"
},
"files": [
"build"
],
"scripts": {
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
"prepare": "npm run build",
"watch": "tsc --watch"
},
"keywords": [
"mcp",
"arxiv",
"research",
"papers"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.4",
"axios": "^1.7.9",
"zod": "^3.24.1"
},
"devDependencies": {
"@types/node": "^22.10.5",
"typescript": "^5.7.3"
}
}
arxiv-server/tsconfig.json{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "build"]
}
4.次に、arXiv検索機能を備えたメイン・サーバー実装は
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import axios from 'axios';
// Define types for arXiv API responses
interface ArxivEntry {
id: string;
title: string;
summary: string;
authors: Array<{ name: string }>;
published: string;
updated: string;
categories: string[];
primary_category: string;
links: Array<{ href: string; rel: string; type?: string }>;
}
interface ArxivSearchResult {
entries: ArxivEntry[];
totalResults: number;
startIndex: number;
itemsPerPage: number;
}
// Create an MCP server
const server = new McpServer({
name: "arxiv-server",
version: "0.1.0"
});
// Create axios instance for arXiv API
const arxivApi = axios.create({
baseURL: 'http://export.arxiv.org/api',
timeout: 30000,
});
/**
* Parse arXiv API XML response to JSON
*/
function parseArxivXML(xmlData: string): ArxivSearchResult {
const entries: ArxivEntry[] = [];
// Extract total results
const totalResultsMatch = xmlData.match(/<opensearch:totalResults[^>]*>(\d+)<\/opensearch:totalResults>/);
const totalResults = totalResultsMatch ? parseInt(totalResultsMatch[1]) : 0;
const startIndexMatch = xmlData.match(/<opensearch:startIndex[^>]*>(\d+)<\/opensearch:startIndex>/);
const startIndex = startIndexMatch ? parseInt(startIndexMatch[1]) : 0;
const itemsPerPageMatch = xmlData.match(/<opensearch:itemsPerPage[^>]*>(\d+)<\/opensearch:itemsPerPage>/);
const itemsPerPage = itemsPerPageMatch ? parseInt(itemsPerPageMatch[1]) : 0;
// Extract entries
const entryRegex = /<entry>([\s\S]*?)<\/entry>/g;
let entryMatch;
while ((entryMatch = entryRegex.exec(xmlData)) !== null) {
const entryXml = entryMatch[1];
// Extract ID
const idMatch = entryXml.match(/<id>([^<]+)<\/id>/);
const id = idMatch ? idMatch[1] : '';
// Extract title
const titleMatch = entryXml.match(/<title>([^<]+)<\/title>/);
const title = titleMatch ? titleMatch[1].trim().replace(/\s+/g, ' ') : '';
// Extract summary
const summaryMatch = entryXml.match(/<summary>([^<]+)<\/summary>/);
const summary = summaryMatch ? summaryMatch[1].trim().replace(/\s+/g, ' ') : '';
// Extract authors
const authors: Array<{ name: string }> = [];
const authorRegex = /<author>\s*<name>([^<]+)<\/name>/g;
let authorMatch;
while ((authorMatch = authorRegex.exec(entryXml)) !== null) {
authors.push({ name: authorMatch[1].trim() });
}
// Extract published date
const publishedMatch = entryXml.match(/<published>([^<]+)<\/published>/);
const published = publishedMatch ? publishedMatch[1] : '';
// Extract updated date
const updatedMatch = entryXml.match(/<updated>([^<]+)<\/updated>/);
const updated = updatedMatch ? updatedMatch[1] : '';
// Extract categories
const categories: string[] = [];
const categoryRegex = /<category[^>]+term="([^"]+)"/g;
let categoryMatch;
while ((categoryMatch = categoryRegex.exec(entryXml)) !== null) {
categories.push(categoryMatch[1]);
}
const primary_category = categories[0] || '';
// Extract links
const links: Array<{ href: string; rel: string; type?: string }> = [];
const linkRegex = /<link[^>]+href="([^"]+)"[^>]+rel="([^"]+)"(?:[^>]+type="([^"]+)")?/g;
let linkMatch;
while ((linkMatch = linkRegex.exec(entryXml)) !== null) {
links.push({
href: linkMatch[1],
rel: linkMatch[2],
type: linkMatch[3]
});
}
entries.push({
id,
title,
summary,
authors,
published,
updated,
categories,
primary_category,
links
});
}
return {
entries,
totalResults,
startIndex,
itemsPerPage
};
}
/**
* Format search results for display
*/
function formatSearchResults(result: ArxivSearchResult): string {
let output = `Found ${result.totalResults} results (showing ${result.entries.length})\n\n`;
result.entries.forEach((entry, index) => {
output += `${index + 1}. ${entry.title}\n`;
output += ` ID: ${entry.id}\n`;
output += ` Authors: ${entry.authors.map(a => a.name).join(', ')}\n`;
output += ` Published: ${entry.published}\n`;
output += ` Categories: ${entry.categories.join(', ')}\n`;
output += ` Abstract: ${entry.summary.substring(0, 300)}${entry.summary.length > 300 ? '...' : ''}\n`;
// Find abstract link (not PDF)
const abstractLink = entry.links.find(l => l.rel === 'alternate');
if (abstractLink) {
output += ` URL: ${abstractLink.href}\n`;
}
output += '\n';
});
return output;
}
// Add a tool for searching arXiv papers
server.tool(
"search_arxiv",
{
query: z.string().describe("Search query (supports arXiv query syntax)"),
max_results: z.number().min(1).max(50).optional().describe("Maximum number of results to return (1-50, default: 10)"),
start: z.number().min(0).optional().describe("Starting index for pagination (default: 0)"),
sort_by: z.enum(["relevance", "lastUpdatedDate", "submittedDate"]).optional().describe("Sort order (default: relevance)"),
sort_order: z.enum(["ascending", "descending"]).optional().describe("Sort direction (default: descending)")
},
async ({ query, max_results = 10, start = 0, sort_by = "relevance", sort_order = "descending" }) => {
try {
// Enforce reasonable limits
const limitedMaxResults = Math.min(max_results, 50);
const limitedStart = Math.max(start, 0);
// Build query parameters
const params: Record<string, string | number> = {
search_query: query,
start: limitedStart,
max_results: limitedMaxResults,
};
if (sort_by) {
params.sortBy = sort_by;
}
if (sort_order) {
params.sortOrder = sort_order;
}
const response = await arxivApi.get('/query', { params });
// Parse XML response
const result = parseArxivXML(response.data);
// Format results
const formattedResults = formatSearchResults(result);
return {
content: [
{
type: "text",
text: formattedResults,
},
],
};
} catch (error) {
if (axios.isAxiosError(error)) {
return {
content: [
{
type: "text",
text: `arXiv API error: ${error.response?.data?.message ?? error.message}`,
},
],
isError: true,
};
}
throw error;
}
}
);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('arXiv MCP server running on stdio');
// Bobで作成
この段階で、サーバーが何らかのAPIキーを必要とする場合、Bobはお客様にそれらを求めます。
5. 次のステップとして、Bobは以下のコマンドを実行してarxiv-serverディレクトリー内の依存関係をインストールします。
mcp_settings.json.Bob/mcp.json{
"mcpServers": {}
"mcpServers": {
"arxiv": {
"command": "node",
"args": [ "/here/is/the/path/to/arxiv-server/build/index.js"
],
"disabled": false,
"alwaysAllow": [],
"disabledTools": []
}
}
}
この情報は、BobがMCPサーバーをセットアップするために行う一連のステップを完了するものです。
一連の「To-Doリスト」タスクを完了するために、BobはMCPサーバーをテストします。前のスクリーンショットに示されているように、BobはMCPサーバー内の
ウィンドウを展開するために下向きのカレットをクリックすることで確認できる、実行の成功後、Bobは別のテストを実行しました。今回は、提出日の降順でソートされた2本の機械学習論文を対象としたクエリーです。異なるパラメーターを使用した場合でも、このMCPツールの呼び出しは正常に実行されました。
テストが成功したため、Bobはすべてのサブタスクを完了しました。
Bobは既に私たちのためにMCPサーバーをテストしてくれています。ただし、Bobが正確な検索語句や必要なパラメーターを推定できるかどうかを確認するために、チャット・ウィンドウで独自のクエリーをいくつか試してみましょう。
Bobに「What are the latest papers on LLM agent tracing?」と質問します。
Bobは自律的に、プロンプトから正確なクエリーを抽出し、検索を改善するためにいくつかの追加キーワードを付加しました。また、Bobは結果の最大数を10に設定し、論文を関連度順にソートしました。素晴らしいです。
もう1つクエリーを試してみましょう。
興味深いことに、Bobは望ましくない結果に気付くと、検索クエリーを自動的に微調整しました。Bobはツール呼び出しを盲目的に実行しているのではなく、むしろ役立つエージェントとしてユーザーと協調しています。これを2回繰り返した後、Bobは最初のタスクによく一致するいくつかの論文を返しました。
多くのオープンソースMCPサーバーには、他のユーザーが簡単に開始できるようにするためのドキュメントも含まれています。チャット・ウィンドウに以下のプロンプトを貼り付けてみましょう。
「このディレクトリーに、このMCPサーバーをドキュメント化するためのREADME.mdファイルを作成してください。セットアップと使用方法の手順を含めてください。」
一つの単純なプロンプトで、BobはarXiv MCPサーバーの理解、インストール、構成、トラブルシューティング、使用に必要なすべてを含む包括的な
このMCPサーバーにアクセスできる、研究に特化したAIエージェントをwatsonx Orchestrateで構築することに興味はありませんか?Bobは、シンプルなプロンプトを1つ入力するだけでエージェントを作成できます。まず、ステップ1で確認したMCP設定パネル内にあるマーケットプレイスから、事前に構築されたwatsonx Orchestrate ADKサーバーをインストールします。次に、以下のコマンドを送信します:
「Create a watsonx Orchestrate agent that uses this arxiv MCP server.」
ローカル環境でwatsonx Orchestrateサービスが実行されている場合、Bobが必要なコマンドを実行します。後でコマンドを自分で実行することを希望する場合は、Bobがスクリプトを作成し、必要なコマンドを文書化します。
IBM Bobが生成した内容をより深く理解するために、各ファイルを確認しましょう。以下はtoolkit-config.yaml
種類:mcp
名称:arxiv-toolkit
説明:arXiv研究論文検索用のツールキット。arXivデータベースからの論文メタデータ、要約、出版情報へのアクセスを提供します。
package_root: /local/path/to/arxiv-server
language: node
command: node /local/path/to/arxiv-server/arxiv-server/build/index.js
tools:
- "*"
# Made with Bob
次に、research-assistant-agent.yaml
名称:研究アシスタント
種類:ネイティブ
説明:arXivの教育機関向け論文の検索と要約を支援するAI研究アシスタント。科学文献の検索、研究結果の説明、引用の提供を専門としています。
タイトル:研究アシスタント
の説明:|
あなたは、arXiv上の教育機関向け文献検索を専門とする専門家研究アシスタントです。
## Your Capabilities
- Search arXiv for papers on any scientific topic
- Summarize research findings from abstracts in plain language
- Identify key authors and research trends
- Suggest related papers and topics
- Provide proper citations with arXiv IDs and URLs
## When Responding to Users
1. Always provide arXiv IDs and direct URLs to papers
2. Summarize abstracts in accessible language
3. Highlight key contributions and findings
4. Suggest follow-up searches when relevant
5. Be concise but informative
## Using the search_arxiv Tool
Available parameters:
- query (required): Search query using arXiv syntax
- max_results (optional): 1-50 papers, default 10
- start (optional): Starting index for pagination, default 0
- sort_by (optional): "relevance", "submittedDate", or "lastUpdatedDate"
- sort_order (optional): "ascending" or "descending"
## Advanced Search Syntax
You can use these operators in queries:
- ti:keyword - Search in title
- au:author - Search by author name
- abs:keyword - Search in abstract
- cat:category - Filter by category (e.g., cs.AI, quant-ph, math.CO)
- AND, OR, ANDNOT - Boolean operators
Examples:
- "ti:transformer AND cat:cs.LG" - Transformer papers in machine learning
- "au:Hinton" - Papers by Geoffrey Hinton
- "quantum computing AND cat:quant-ph" - Quantum computing in quantum physics
## Common Categories
- cs.AI - Artificial Intelligence
- cs.LG - Machine Learning
- cs.CL - Computation and Language
- cs.CV - Computer Vision
- quant-ph - Quantum Physics
- math.CO - Combinatorics
- stat.ML - Machine Learning (Statistics)
## Response Format
When presenting papers, use this format:
**"Paper Title"**
- Authors: [Author names]
- Published: [Date]
- Categories: [Categories]
- Summary: [Brief summary of abstract]
- [View paper](arXiv URL)
## Handling Edge Cases
- If no results found: Suggest alternative search terms or broader queries
- If too many results: Recommend narrowing the search with categories or date filters
- If user asks for PDFs: Explain you provide metadata only, but include the URL where they can access the paper
- If unclear query: Ask clarifying questions about the research area or specific interests
tools:
- search_arxiv
config:
hidden: false
enable_cot: true
tags:
- research
- academic
- papers
- arxiv
- literature-search
# Made with Bob
このYAMLファイルは、arXivの検索、論文の要約、構造化された形式による引用の提供を通じて学術研究を効率化する、特化したAIエージェントであるリサーチ・アシスタントを構成します。ここには、クエリー構文やツールの使用法から、レスポンス・フォーマット、エッジ・ケースの処理に至るまで、エージェントの動作をガイドする詳細な指示が含まれています。科学文献を効率的に取得して提示するためにsearch_arxivsetup-instructions.md
このチュートリアルでは、AIファーストのIDEとペアの開発者であるIBM Bobを使用して、教育機関向けの研究のためのMCPの統合を合理化しました。arXiv.orgリポジトリーから論文を検索および取得できるスケーラブルなMCPサーバーを効率的に構築しました。これで、研究コミュニティー向けにオープンソースを選択する場合でも、知識発見を強化するためにエンタープライズ・アプリケーションにデプロイする場合でも、ソリューションは実稼働対応になります。
IBM Bobの真の魅力は、複雑な開発タスクを直感的でプロンプト駆動のワークフローに変換できることにあります。戦略的なインプットをいくつか行うだけで、Bobはプロトタイピングを加速し、定型コードを削減し、最適化まで提案して、実装ではなくイノベーションに集中できるようにします。
その機能を探索し続けるにあたり、BobがあなたのMCPサーバーをどのようにさらに洗練させることができるかを検討してください。メリットとしては、高度なフィルタリング、リアルタイム更新、またはPubMedやIEEE Xploreといった他の学術データベースとの統合の追加などが挙げられます。これらすべての可能性、そしてそれ以上のことが、IBM Bobを使用したいくつかのシンプルなプロンプトで実現可能です。
次のステップに進む準備はできましたか。MCPサーバーのカスタマイズを試してみたり、Bobの機能をさらに深く掘り下げて、自動化の可能性をより一層引き出してみましょう。楽しいコーディングを。
生成AIを使用してワークフローとプロセスを自動化する強力なAIアシスタントとエージェントを構築、デプロイ、管理しましょう。
信頼できるAIソリューションでビジネスの未来を構築します。
IBMコンサルティングAIサービスは、企業がAIをトランスフォーメーションに活用する方法を再考するのに役立ちます。