チュートリアル

IBM BobでMCPサーバーを構築する

IBM Bobを使ってAIモデルを外部ツールやデータソースに接続するカスタムModel Context Protocol(MCP)サーバーを構築する方法を学ぼう。このハンズオンチュートリアルでは、アドバンストモード、承認ワークフロー、MCP設定を解説する。

このチュートリアルでは、IBM Bobを使って、科学論文のオープンアクセスリポジトリであるarXivへの読み取り専用アクセスを提供するカスタムMCPサーバーを構築する。オプションで、サーバーを拡張してwatsonx Orchestrate AIエージェントと連携させることもできる。

Model Context Protocol(MCP)は、大規模言語モデル(LLM)が統一されたクライアント・サーバーアーキテクチャを通じて外部ツール、データソース、コンテンツリポジトリと通信できるようにするオープン標準だ。MCP以前は、各AIアシスタントが外部ツールごとに独自の統合を必要とし、相互運用性のないファンクションコールを使っていた。代わりにMCPは、任意のMCPホストが任意のMCPサーバーに接続するために使える単一のJSON-RPC 2.0プロトコルを定義している。

前提条件

このチュートリアルでは、arXiv APIをクエリするTypeScript MCPサーバーを構築する。TypeScriptやMCP統合の事前経験は不要だ。

このチュートリアルを完了するには、以下が必要だ:

ワークスペースの設定

IBM Bobを起動し、MCP設定パネルを開いて、サーバープロジェクト用の作業ディレクトリを準備する。

IBM Bobの起動

コンピューターでIBM Bobアプリケーションを起動する。

Bobチャットパネルを開く

チャットパネルがまだ開いていない場合は、ナビゲーションバーの横にあるBobアイコンをクリックするか、ショートカットOption + Command + B(Mac)またはCtrl + Alt + B(Windows)を使う。

MCP設定パネルを開く

チャットウィンドウの右上隅にある歯車アイコンをクリックし、左のサイドバーからMCPを選択する。

MCP設定パネルでは、サーバーの有効・無効化、特定ツールの自動承認、MCP SDKを使ったカスタム統合の構築ができる。

  • グローバル: mcp_settings.jsonに保存され、すべてのワークスペースに適用される。
  • プロジェクト: プロジェクトルートの.bob/mcp.jsonに保存され、バージョン管理でチームと共有できる。プロジェクトレベルの設定はグローバル設定を上書きする。

自動承認の設定

Bobチャットで、チャット入力フィールドのすぐ下にある自動承認権限が「Read」(読み取り)のみに設定されていることを確認する。この設定により、BobはファイルとディレクトリのコンテンツをBobが閲覧できるようになり、各コマンドの実行前にレビューと承認を求めるようになる。

プロジェクトディレクトリを開く

プロジェクト用の優先ディレクトリがある場合は、IDEで開く。チャットウィンドウでBobに依頼することもできる。

Python仮想環境のセットアップ

プロジェクトの依存関係を分離して、異なるプロジェクト間の競合を防ぐために、Python仮想環境を作成するのが一般的だ。ターミナルコマンドの読み取り、書き込み、実行ができるAgentモードにBobを切り替えてから、環境を作成する。

仮想環境の作成と有効化

Bobチャットパネルに以下のプロンプトを入力する:

In this directory, activate a Python virtual environment.

Bobは一連のターミナルコマンドを実行する。プロンプトが表示されたら、それぞれを承認する。コマンドによりvenv/ディレクトリに新しい仮想環境が作成されて有効化される。

MCPサーバーのビルドプランの生成

Planモードへの切り替え

チャット入力フィールドのすぐ下にあるボタンをクリックして、インタラクションモードをPlanに変更する。このモードでは、コードを書く前にBobがMCPサーバーの構造化されたプランを生成できる。

サーバー要件の送信

仮想環境を有効化した状態で、以下のプロンプトをBobに送信する。具体的な要件を最初から提供することで、Bobはコードを書く前に完全なプランを策定するのに十分なコンテキストを得られる:

Create an MCP server named arxiv-server that provides read-only access to arXiv. The server should:
- Expose one tool, search_papers, for querying arXiv papers by keyword
- Accept a query string and an optional max_results parameter (default 5, max 20)
- Limit results to paper metadata and abstracts (no PDFs)
- Return title, authors, publication date, abstract, and arXiv URL for each result
- Normalize responses into a clean, structured JSON schema
- Handle API errors and empty results gracefully, returning a clear message instead of failing
- Use TypeScript/Node.js with the stdio transport
- Use the arXiv API v2, which requires no authentication

Bobは、プロジェクトのスキャフォールディング、MCPサーバーの実装、依存関係のインストール、サーバー設定、テストをカバーする構造化されたTodoリストを作成する。Bobはエラー処理と認証の考慮事項を自動的に計画することに注目してほしい。対象API(arXiv)がキーを必要としない場合でも、Bobはキーが必要なサーバーに対して認証情報をどこに注入するかを示す。

Bobが質問をしてきた場合は、できる限り答えるか、Bobに合理的な仮定を立てるよう指示する。

MCPサーバーの構築とレビュー

プランを確認して承認したら、Agentモードに切り替えて各ステップを実行する。Bobはリアルタイムでレスポンスを生成するため、出力と順序は以下の例と若干異なる場合がある。

以下のプロンプトでBobにサーバーの構築を開始するよう指示する:

Implement the plan.

最初に、Bobはプロジェクト構造のスキャフォールディングを行い、mkdir -p arxiv-server/srcを実行してプロジェクトディレクトリを作成する。

次に、Bobはプロジェクトのメタデータ、スクリプト、依存関係を宣言するNode.js設定ハブであるarxiv-server/package.jsonを生成する:

{
  "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"
  },
  "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"
  }
}

BobはTypeScriptコンパイラーを設定するための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"]
}

次に、Bobはarxiv-server/src/index.tsにメインサーバーファイルを作成する。このファイルはsearch_arxivツールをMCP SDKに登録し、arXiv APIレスポンスのXMLからJSONへのパースを実装し、結果の制限を適用し、MCPホストと同じマシン上で動作するサーバーに適したローカルの低レイテンシトランスポートタイプであるSTDIOトランスポートでサーバーを起動する。

MCP SDKのserver.tool()呼び出しが主要な統合ポイントだ。任意のMCPクライアントにツールを公開する。

#!/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';

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;
}

const server = new McpServer({ name: "arxiv-server", version: "0.1.0" });

const arxivApi = axios.create({
  baseURL: 'http://export.arxiv.org/api',
  timeout: 30000,
});

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 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(),
    sort_order: z.enum(["ascending", "descending"]).optional()
  },
  async ({ query, max_results = 10, start = 0, sort_by = "relevance", sort_order = "descending" }) => {
    try {
      const params: Record<string, string | number> = {
        search_query: query,
        start: Math.max(start, 0),
        max_results: Math.min(max_results, 50),
        ...(sort_by && { sortBy: sort_by }),
        ...(sort_order && { sortOrder: sort_order }),
      };
      const response = await arxivApi.get('/query', { params });
      return {
        content: [{ type: "text", text: formatSearchResults(parseArxivXML(response.data)) }],
      };
    } catch (error) {
      if (axios.isAxiosError(error)) {
        return {
          content: [{ type: "text", text: `arXiv API error: ${error.response?.data?.message ?? error.message}` }],
          isError: true,
        };
      }
      throw error;
    }
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);
console.error('arXiv MCP server running on stdio');

catchブロックのisError: trueフラグはMCPの標準エラー処理パターンだ。サーバープロセスをクラッシュさせずにツール呼び出しが失敗したことをMCPクライアントに通知する。

次のステップとして、Bobはcd arxiv-server && npm installを実行してarxiv-serverディレクトリ内に依存関係をインストールする。

プロジェクトスコープでのサーバーの登録

Bobは新しいサーバーを自動的に登録しない。Bobに明示的に追加するよう指示し、プロジェクトスコープを指定することで設定が.bob/mcp.jsonに保存され、バージョン管理でチームと共有できるようになる。

Bobにサーバーの登録を指示する

Bobチャットパネルに以下のプロンプトを入力する:

Register the arxiv-server as an MCP server at project scope. Build it first if needed, then add it to .bob/mcp.json.

生成された設定を確認する

Bobはプロジェクトルートの.bob/mcp.jsonに以下を書き込む。commandフィールドとargsフィールドは、STDIOトランスポートを使ってサーバープロセスを起動する方法をMCPクライアントに伝える。

{
  "mcpServers": {
    "arxiv-server": {
      "command": "node",
      "args": ["${workspaceFolder}/arxiv-server/build/index.js"]
    }
  }
}

サーバーが読み込まれていることを確認する

Bobはこのファイルを書き込んだ後、MCP設定を自動的に再読み込みする。続行する前に、MCP設定パネル(歯車アイコン > MCP)を開いてarxiv-serverサーバーが一覧表示されて有効化されていることを確認する。表示されない場合は、サーバーリストの横にある再読み込みアイコンをクリックする。

Bobを再起動する

サーバーが実行中でクエリを受け付ける準備ができていることを確認するために、Bobを再起動する。

MCPサーバーのテスト

サーバーが登録されると、Bobはsearch_arxivツールに対して2つの検証クエリを自動的に実行する。

最初のテストは、関連性でソートされた量子コンピューティング論文3本をクエリする。2番目は、提出日の降順でソートされた機械学習論文2本をクエリする。どちらも正常に実行され、ツールが到達可能であること、サーバーのエラー処理が異なるパラメータの組み合わせを適切に管理していることが確認できる。

次に、自然言語から正しいパラメータをBobが抽出することを確認するために、独自のクエリを実行する。Bobチャットパネルに貼り付けるプロンプトの例:

What are the latest papers on LLM agent tracing?

サーバーのドキュメント化

オープンソースのMCPサーバー実装には、通常、他の人がすぐに始められるようにドキュメントが含まれている。Bobに生成するよう依頼する:

In this directory, create a README.md file to document this MCP server.
Include setup and usage instructions.

Bobは、インストール、複数のMCPホスト(IBM Bob、Claude Desktop、Cursor、Claude Code)の設定、APIキーが必要なサーバーの認証ガイダンス、ローカルファイルアクセスパターン、トラブルシューティングのヒントをカバーする包括的なREADME.mdを作成する。

リソースのクリーンアップ

このチュートリアルではローカルファイルとサーバー登録が作成される。arXiv MCPサーバーを使い続けない場合は削除する。

Bob(歯車アイコン > MCP)でMCP設定パネルを開き、arxiv-serverエントリーを無効化または削除する。または、mcp_settings.json(グローバルスコープ)または.bob/mcp.json(プロジェクトスコープ)から直接arxiv-serverブロックを削除する。

次のステップ

このチュートリアルでは、IBM Bobを使ってTypeScript MCPサーバーを構築し、STDIOトランスポートで設定し、arXivへのライブクエリでテストした。すべて自然言語プロンプトを通じて行った。

同じワークフローが、より複雑なMCPサーバーの実装にも適用できる:データベース、ローカルファイル、またはその他の外部データソースに接続するサーバーだ。認証が必要なサーバーは、MCP設定JSONの環境変数として認証情報を注入する必要がある。リモートデプロイメントの場合は、STDIOトランスポートをSSEに置き換える。

  • サーバーコードをコミットする前に問題を発見するためのBobのコードレビュー機能について学ぼう。
  • Advanced、Code、Ask、その他のBobペルソナをいつ使うかを理解するためにモードについて学ぼう。
  • グローバルスコープとプロジェクトスコープ、自動承認ツール、SSEトランスポート設定の詳細についてはMCP設定を探索しよう。
  • 引き続き学習を進めるためにIBM Bob入門チュートリアルシリーズに取り組もう。
このトピックはいかがですか?