MCP(Model Context Protocol)は、AI エージェントを外部のツールやデータソースにつなぐためのオープンな標準です。Claude Agent SDK で MCP サーバーに接続すると、ツールを自前で実装しなくても、データベースへの問い合わせや GitHub・Slack などの API 連携をエージェントに任せられます。
この記事では、公式ドキュメント「Connect to external tools with MCP」に沿って、mcpServers オプションと .mcp.json によるサーバーの追加、stdio・HTTP・SSE の使い分け、mcp__ で始まるツール名と allowedTools による許可、認証情報の渡し方、init メッセージでの接続確認を整理します。CLI の Claude Code に MCP サーバーを追加する方法は「Claude Code を MCP で外部ツールに接続する」を、アプリ内で動く自作ツールは「Agent SDK のカスタムツール」を参照してください。
まず動かす:最小構成
公式のクイックスタートは、Claude Code のドキュメントを検索できる MCP サーバーに HTTP で接続し、そのサーバーのツールをワイルドカードでまとめて許可する例です。query() のオプションに mcpServers と allowedTools の2つを書くだけで動きます。
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Use the docs MCP server to explain what hooks are in Claude Code",
options: {
mcpServers: {
"claude-code-docs": {
type: "http",
url: "https://code.claude.com/docs/mcp"
}
},
allowedTools: ["mcp__claude-code-docs__*"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
Python では ClaudeAgentOptions(mcp_servers={...}, allowed_tools=["mcp__claude-code-docs__*"]) と書きます。エージェントはドキュメントサーバーに接続してフックについて調べ、その結果を返します。
MCP サーバーの動かし方は3通りあります。ローカルのプロセスとして起動する、HTTP で接続する、そして SDK アプリケーションの中で直接動かす、のいずれかです。
サーバーの追加方法とトランスポート
コードで渡すか、.mcp.json に書くか
サーバーは query() 呼び出し時に mcpServers オプションで渡すか、プロジェクトのルートに置いた .mcp.json に書きます。.mcp.json は設定ソース project が有効なときに読み込まれ、既定の query() オプションでは有効です。settingSources を明示的に指定する場合は、"project" を含めないとこのファイルは読まれません。
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
}
}
}
トランスポートの選び方
どのトランスポートを使うかはサーバーのドキュメントで確認します。公式の目安は次のとおりです。
| サーバーのドキュメントにあるもの | 使うトランスポート | 主な設定項目 |
|---|---|---|
実行するコマンド(npx @modelcontextprotocol/server-filesystem など) | stdio(標準入出力でやり取りするローカルプロセス) | command・args・env |
| URL | HTTP(type: "http")または SSE(type: "sse") | url・headers |
| 自分でコードにツールを書く | SDK MCP サーバー(アプリ内で動く) | createSdkMcpServer() で作成 |
TypeScript リファレンスでは、mcpServers の値の型 McpServerConfig は stdio・SSE・HTTP・SDK の4つの設定型の合併型です。stdio は type を省略でき、SSE と HTTP は type と url が必須です。
// stdio:ローカルのプロセスを起動する
mcpServers: {
filesystem: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
}
}
// SSE:URL とヘッダーで接続する(ストリーミング HTTP なら type: "http")
mcpServers: {
"remote-api": {
type: "sse",
url: "https://api.example.com/mcp/sse",
headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
}
}
ストリーミング HTTP のトランスポートには "type": "http" を使います。.mcp.json などの JSON 設定ファイルでは "streamable-http" も "http" の別名として受け付けられますが、SDK の McpHttpServerConfig 型が宣言しているのは "http" だけなので、コードで渡すときは "http" と書きます。
ツールが多い場合、ツール定義がコンテキストを大きく消費します。これを抑えるツール検索(tool search)は既定で有効で、ツール定義を前もって載せず、各ターンで必要なものだけを読み込みます。
MCP ツールを許可する
ツール名の規則
MCP ツールは使う前に明示的な許可が必要です。許可がないと、Claude はツールがあることは分かっても呼び出せません。MCP ツールの名前は mcp__<サーバー名>__<ツール名> という形になり、たとえば "github" という名前のサーバーの list_issues ツールは mcp__github__list_issues です。
allowedTools で自動承認する
allowedTools: [
"mcp__github__*", // github サーバーのすべてのツール
"mcp__db__query", // db サーバーの query だけ
"mcp__slack__send_message" // slack サーバーの send_message だけ
]
ワイルドカード * を使うと、サーバーのツールを1つずつ並べずにまとめて許可できます。
公式は、MCP へのアクセスには権限モードより allowedTools を使うよう勧めています。permissionMode: "acceptEdits" が自動承認するのはファイル編集とファイルシステム系の Bash コマンドだけで、MCP ツールは対象外です。permissionMode: "bypassPermissions" は MCP ツールも承認しますが、他の多くの安全確認も無効にするため必要以上に広くなります。allowedTools のワイルドカードなら、許可したいサーバーだけに絞れます。権限まわりの全体像は「Agent SDK の権限設定」で扱っています。
使えるツールを調べる
サーバーがどんなツールを持つかは、サーバーのドキュメントを見るか、system の init メッセージにある tools 配列を調べます。
for await (const message of query({ prompt: "...", options })) {
if (message.type === "system" && message.subtype === "init") {
const mcpTools = message.tools.filter((name) => name.startsWith("mcp__"));
console.log("Available MCP tools:", mcpTools);
}
}
この一覧に載るのは、init メッセージの時点で接続済みのサーバーと、ツール一覧がキャッシュされているサーバーのツールです。まだ接続していないサーバーのツールは含まれません。
認証情報の渡し方
多くの MCP サーバーは外部サービスへの認証を必要とします。認証情報はサーバー設定の中で渡します。
| サーバーの種類 | 渡し方 |
|---|---|
| stdio | env フィールドで API キーやトークンを環境変数として渡す |
| HTTP / SSE | headers フィールドに Authorization ヘッダーなどを書く |
mcpServers: {
"api-server": {
command: "npx",
args: ["-y", "@your-org/api-mcp-server"],
env: { API_KEY: process.env.API_KEY }
}
}
.mcp.json に書く場合は "API_KEY": "${API_KEY}" や "Authorization": "Bearer ${API_TOKEN}" のように書くと、実行時に環境変数が展開されます。キーそのものをファイルに書かずに済みます。
OAuth が必要なサーバー
MCP の仕様は認可に OAuth 2.1 をサポートしていますが、SDK はブラウザを開かず、対話型の OAuth フローも実行しません。認可を求められて保存済みのトークンがない場合、エージェントはそのサーバーのツール抜きで実行を続け、サーバーの状態は needs-auth になります。OAuth フローは自分のアプリケーション側で済ませ、得たアクセストークンを headers の Authorization: Bearer ... に入れて渡します。
公式の例では、GitHub の個人アクセストークンを GITHUB_TOKEN に設定し、リモートの GitHub MCP サーバー(https://api.githubcopilot.com/mcp/)に headers で渡して、allowedTools: ["mcp__github__list_issues"] で最新の issue を一覧させています。
接続状態の確認とトラブル対処
init メッセージの status を見る
Claude Code は各 query の最初に、サブタイプ init の system メッセージを出します。その mcp_servers に各サーバーの接続状態が入り、status は "pending"・"connected"・"failed"・"needs-auth"・"disabled" のいずれかです。使えないサーバーを見つけるには "failed" と "needs-auth" を調べます。
if (message.type === "system" && message.subtype === "init") {
const unavailableServers = message.mcp_servers.filter(
(s) => s.status === "failed" || s.status === "needs-auth"
);
if (unavailableServers.length > 0) {
console.warn("Unavailable MCP servers:", unavailableServers);
}
}
MCP サーバーの接続失敗は例外になりません。サーバーが使えないと Claude が組み込みツールで代用することもあるので、結果を信用する前にこの状態を確認するよう公式は注意しています。また "pending" はそれだけで失敗を意味しません。まだ接続中の場合、キャッシュ済みのツール一覧を使っていて最初の呼び出し時に接続する場合、接続期限が切れた場合のいずれもありえます。後から状態を確かめるには、TypeScript ではクエリの mcpServerStatus()、Python では ClaudeSDKClient.get_mcp_status() を呼びます。手動で再接続したいときは reconnectMcpServer()(Python は reconnect_mcp_server())を使います。
よくある原因と調整できる値
- failed になる:必要な環境変数が未設定、
npxのパッケージが存在しないか Node.js が PATH にない、接続文字列の誤り、URL に届かない(ファイアウォールなど) - ツールが見えているのに呼ばれない:
allowedToolsで許可していない - 起動が遅くて失敗する:接続は既定で30秒でタイムアウトする。環境変数
MCP_TIMEOUT(ミリ秒)で延ばせる。実行中のツール呼び出しの上限はMCP_TOOL_TIMEOUTで変える - ツールの出力が大きすぎる:画像を含まない成功結果が 25,000 トークンを超えると、出力はファイルに保存され、そのパスを示すエラーに置き換わる。上限は
MAX_MCP_OUTPUT_TOKENSで変えられる
本ページは Connect to external tools with MCP の内容に基づく非公式の日本語解説で、設定の型とメソッド名は Agent SDK reference - TypeScript と照合しています(確認日 2026-10-16)。オプション名・フィールド名は公式表記のまま記載しています。最新の仕様は公式ドキュメントを確認してください。