MCPは2024年11月にAnthropicが公開した仕様で、2025年6月18日版(spec 2025-06-18)が2026年時点の推奨バージョン。OpenAI、Google、Microsoftが公式クライアントを提供している。
プリミティブはTools・Resources・Prompts の3種類。Toolsは副作用ありの関数呼び出し、Resourcesは読み取り専用データ、Promptsはユーザー起動のテンプレート。
ローカル用途はstdio 、リモート配布はStreamable HTTP (旧HTTP+SSEはdeprecated)。
Python SDKには公式の低レベルmcpと、Pythonic APIを提供するFastMCP 2.xがあり、本番用途ではFastMCPが実質デファクト。
OAuth 2.1認可はspec 2025-03-26で標準化。リモートサーバーを公開する場合はほぼ必須。
MCPは関数呼び出し(Function Calling)を置き換えるものではなく、ツール定義の配布層 として上に載る。1つのMCPサーバーを書けば、Claude・Cursor・ChatGPTから同時に使える。
目次
MCP(Model Context Protocol)とは何か
2026年時点のMCP最新動向 ─ Streamable HTTPと認可
Python SDKとFastMCPで最小サーバーを実装する
Tools・Resources・Promptsの使い分け
Claude Desktop・Cursor・Zed・ChatGPTでの接続設定
MCP vs Function Calling ─ どちらを使うべきか
本番運用チェックリスト ─ ログ・エラー・認可
よくある質問
MCP(Model Context Protocol)とは何か
MCPは、LLMアプリケーション(ホスト)と外部データソース・ツールとの間の通信を標準化するオープンプロトコルです。公式仕様 ではJSON-RPC 2.0をベースにしたリクエスト・レスポンス・通知の3種類のメッセージを定義しており、トランスポート層に依存しない設計になっています。私が2025年に受けた仕事の半分は「既存のn8nカスタムノードやLangChain Toolを、MCPサーバーとして書き直してほしい」というもので、これは1回書けばClaude・Cursor・ChatGPT・Zedから使える という配布効率の高さが理由でした。
正直、初めてこの話を聞いたときは「また新しい標準か」と身構えたのですが、実装して2〜3週間触ってみて考えが変わりました。MCPが解決する問題を1文で言えば、「N個のLLMアプリケーションとM個のツールの間にN×Mの実装を書かなくて済む」ことです。従来はClaude用にAPI、ChatGPT用にプラグイン、Cursor用に別のツール定義、といったN×Mの組み合わせが必要でした。MCPが挟まることでN+Mに落ち、ツール開発者は仕様に従って1回書くだけ、クライアント開発者は仕様に従って1回パースするだけになります。この構造はUSB-Cが充電・データ・映像を標準化したのと同じ発想で、公式ドキュメントでも "USB-C for AI applications" という比喩が使われています。
2026年時点で対応済みのクライアントは Claude Desktop / Claude Code / Cursor / Zed / Continue / Cline / Windsurf / VS Code(組み込み)/ Sourcegraph Cody / ChatGPT Desktop / OpenAI Responses API / Google Gemini CLI など20以上あり、公式サーバーレジストリにはreference implementations として filesystem・github・postgres・puppeteer・slack など30以上が並んでいます。
2026年時点のMCP最新動向 ─ Streamable HTTPと認可
MCP仕様は年3〜4回改訂されており、2026年9月時点の最新はspec 2025-06-18 です。過去1年で本番運用に影響する変更が3つ入っているので、古いチュートリアルを見ながら実装すると詰みます。
1. HTTP+SSEの廃止、Streamable HTTPへの一本化
spec 2024-11-05では2種類のトランスポートが定義されていました:
stdio :ホストがサーバーを子プロセスとして起動し、標準入出力でJSON-RPCをやり取り。ローカル用途向け。
HTTP+SSE(旧) :GETでSSEチャネルを開き、POSTでメッセージ送信する双方向ストリーム。
2025-03-26でHTTP+SSEがdeprecatedとなり、Streamable HTTP に置き換わりました。単一のPOSTエンドポイントでリクエストを送り、レスポンスは通常のJSONか、必要ならSSEストリームとして返す方式です。1つのURLで済むためリバースプロキシ・認可・ロードバランサの設定が大幅に単純化されました。既存のHTTP+SSEサーバーは2026年内にStreamable HTTPへ移行しておくのが安全です。
2. OAuth 2.1認可の標準化
spec 2025-03-26で認可仕様が追加され、リモートMCPサーバーはOAuth 2.1 (PKCE必須、Implicit Flow禁止)に準拠することになりました。/.well-known/oauth-authorization-serverでメタデータを公開し、クライアントは動的クライアント登録(RFC 7591)で登録します。私が最近ヘルスケア系のSaaSに書いたMCPサーバーでは、既存のAuth0テナントをそのままAuthorization Serverとして使い、MCPサーバー側はリソースサーバーとしてBearerトークンを検証するだけで済みました。
3. 構造化ツール出力とエラーモデル
spec 2025-06-18では、ツールの返り値にJSON Schemaで型付けされた structuredContent フィールドが追加されました。従来はテキストブロックしか返せず、LLMが再パースする必要がありましたが、これでツール→ツールのパイプラインを組みやすくなっています。エラーも isError: true フラグとJSON-RPCエラーコードの2レイヤーで区別できるようになり、リトライ判断が明確になりました。
注意: 2025年前半のブログ記事やYouTubeチュートリアルは、ほぼ全てHTTP+SSEトランスポートで書かれています。mcp.run_sse_async()や@sse_endpointのようなAPIを見かけたら、それは古い実装です。2026年からはstreamable_http系のAPIを使ってください。
Python SDKとFastMCPで最小サーバーを実装する
Pythonでは2種類のSDKが実質標準です。公式 mcp パッケージ は仕様を直訳した低レベルAPIを提供し、fastmcp(jlowin氏開発、後に公式取り込み)はデコレータベースのPythonic APIを提供します。私は基本的にFastMCPを推奨します ─ 型ヒントからJSON Schemaを自動生成してくれるので、Pydanticモデルさえ書けばツール定義は完成します。
まずインストールと最小の"Hello Tools"サーバーを見てみましょう。以下の例は在庫管理APIをMCPサーバーとして公開する想定です。
# pyproject.toml or pip
# uv add "fastmcp>=2.3" httpx pydantic
# server.py
from typing import Annotated
from pydantic import BaseModel, Field
from fastmcp import FastMCP
import httpx
mcp = FastMCP(
name="inventory-mcp",
version="0.1.0",
instructions=(
"在庫SKUの検索と発注をサポートします。"
"search_skuでSKUを検索し、create_purchase_orderで発注してください。"
),
)
class SKU(BaseModel):
sku_id: str
name: str
on_hand: int = Field(description="現在の在庫数")
reorder_point: int
@mcp.tool()
async def search_sku(
query: Annotated[str, Field(description="SKU名の部分一致(日本語可)")],
limit: Annotated[int, Field(ge=1, le=50)] = 10,
) -> list[SKU]:
"""在庫SKUを名前で検索する。上位limit件を返す。"""
async with httpx.AsyncClient(timeout=10) as client:
r = await client.get(
"https://internal-erp.example.com/api/skus",
params={"q": query, "limit": limit},
)
r.raise_for_status()
return [SKU(**row) for row in r.json()["items"]]
@mcp.tool()
async def create_purchase_order(
sku_id: str,
quantity: Annotated[int, Field(ge=1, le=10_000)],
supplier_id: str,
) -> dict:
"""指定SKUの発注を作成する。返り値は発注番号を含むdict。"""
async with httpx.AsyncClient(timeout=30) as client:
r = await client.post(
"https://internal-erp.example.com/api/purchase_orders",
json={"sku_id": sku_id, "qty": quantity, "supplier": supplier_id},
)
r.raise_for_status()
return r.json()
if __name__ == "__main__":
# ローカル(Claude Desktop / Cursor / Zed 用)
mcp.run(transport="stdio")
これだけで、2つのツール(search_sku、create_purchase_order)を公開する完全なMCPサーバーが動きます。PydanticのFieldで書いたdescriptionやバウンドは、そのままJSON Schemaに翻訳されてクライアントに送られ、LLMがツールをいつ・どう呼ぶかの判断材料になります。私の経験上、このツール説明文とパラメータ説明の質 が、エージェントの成功率を決める最大の要因です。「searchする」と1語で書くか「SKU名の部分一致(日本語可)」と書くかで、Claude Sonnetの正答率が体感で30%変わります。
Streamable HTTPで公開する
リモートに配布する場合はトランスポートを切り替えます。FastMCPはASGIアプリを返せるので、UvicornやHypercornで直接動かせます。
# server_http.py
from server import mcp # 上のmcpインスタンスを再利用
import uvicorn
if __name__ == "__main__":
# Streamable HTTP を /mcp にマウント
app = mcp.streamable_http_app(path="/mcp")
uvicorn.run(app, host="0.0.0.0", port=8080, log_level="info")
これで https://mcp.example.com/mcp がMCPエンドポイントになります。認可を挟む場合は、UvicornではなくFastAPI/StarletteアプリでこのASGIをマウントし、ミドルウェアでBearerトークン検証をすればOKです。
MCPのプリミティブは3種類あり、それぞれ役割が明確に分かれています。ここを混同してTools一択で作ると、UXが劣化するので注意してください。
プリミティブ 制御者 典型的な用途 副作用 キャッシュ
Tools モデル(自動呼び出し) API呼び出し、DB書き込み、計算 あり 基本なし
Resources アプリ/ユーザー(明示添付) ファイル、DB行、ログ、ドキュメント なし(読み取り専用) あり(URI単位)
Prompts ユーザー(スラッシュコマンド) 定型ワークフローの起動テンプレート なし 該当なし
Resourcesを正しく使う
Resourcesはfile://、postgres://、jira://のような独自URIスキームで識別されるコンテキストデータです。Claude Desktopでは@ メンションでユーザーが明示的に会話に添付し、Cursorでは自動的にコンテキストに注入されます。「ユーザーがどのデータを渡すか選ぶ」性質があるため、社内ドキュメント検索やソースコード参照はToolsではなくResourcesで公開したほうがコスト効率が良くなります(不要なコンテキストがトークンに乗らない)。
@mcp.resource("jira://issue/{issue_key}")
async def get_jira_issue(issue_key: str) -> str:
"""Jira issue の Markdown 化された本文を返す。"""
async with httpx.AsyncClient() as client:
r = await client.get(f"https://internal-jira.example.com/api/issues/{issue_key}")
r.raise_for_status()
data = r.json()
return f"# {data['summary']}\n\n**Status:** {data['status']}\n\n{data['description']}"
Promptsでワークフローを配布する
Promptsは「/incident-review」のようなスラッシュコマンドとしてクライアントUIに現れます。私が書いた顧客サポート向けサーバーでは、"問い合わせトリアージ"というPromptを1つ用意し、それがResourcesで顧客履歴を読み、Toolsで社内KBを検索し、下書き返信を生成する、という一連の流れを1コマンドに閉じ込めています。エンジニアでないオペレーターが再現性のあるワークフローを起動する手段として非常に有効です。
Claude Desktop・Cursor・Zed・ChatGPTでの接続設定
MCPサーバーが書けても、クライアント側の設定ファイルの形式は微妙に違います。よく使う4クライアントの設定例をまとめます。
Claude Desktop(stdio)
~/Library/Application Support/Claude/claude_desktop_config.json(macOS)を編集します。
{
"mcpServers": {
"inventory": {
"command": "uv",
"args": ["run", "--project", "/Users/priya/mcp/inventory", "python", "server.py"],
"env": {
"ERP_API_KEY": "sk-xxxxxxxx"
}
}
}
}
Cursor(stdio または HTTP)
Cursorはプロジェクトルートの.cursor/mcp.jsonとグローバル設定の両方をサポートします。Streamable HTTPを使う場合はurlを指定します。
{
"mcpServers": {
"inventory": {
"url": "https://mcp.example.com/mcp",
"headers": { "Authorization": "Bearer ${INV_TOKEN}" }
}
}
}
ChatGPT / OpenAI Responses API
2025年3月にOpenAIが公式にMCPをサポートし、Responses APIで直接指定できるようになりました。認可付きリモートサーバーが前提です。
from openai import OpenAI
client = OpenAI()
resp = client.responses.create(
model="gpt-5.1",
input="在庫が10個以下のSKUを一覧して",
tools=[{
"type": "mcp",
"server_label": "inventory",
"server_url": "https://mcp.example.com/mcp",
"authorization": "Bearer xxxxxxxx",
"require_approval": "never", # 本番は "always" または フィルタ関数
}],
)
print(resp.output_text)
Tip: Responses API側で require_approval をデフォルトの"always"のままにすると、ツール呼び出しごとに承認プロンプトが返ります。本番のバッチジョブで動かすときは "never" にしつつ、MCPサーバー側でRBACとRate Limitingを固めておくのが安全です。
MCP vs Function Calling ─ どちらを使うべきか
「MCPは既存のFunction Callingを置き換えるのか?」とよく聞かれますが、答えはNo、MCPはFunction Callingの上に載る配布層 です。LLMプロバイダのAPIレベルで見ると、モデルが返すのは今もtool_useブロック(Anthropic)やtool_calls(OpenAI)であり、実行はホスト側の責務です。MCPはその「ホストが持つツール一覧をどこから取ってくるか」を標準化したにすぎません。
使い分けの目安は以下です。
単一アプリケーション、単一LLMプロバイダ、内製ツールのみ → 素のFunction Calling(またはPydanticAI のような型安全ラッパ)で十分。MCPの分散システム的複雑性を持ち込む価値はない。
ツールを複数クライアント(Claude Desktop、IDE、Web UIなど)から使いたい → MCPが最適。1回書けば全クライアントで動く。
サードパーティにツールを配布したい → MCP一択。プロバイダ固有のツール定義を配ってもエコシステムが育たない。
エージェントフレームワーク内部の内部ツール → LangGraphやOpenAI Agents SDKの@toolデコレータの方が軽い。
実際に本番で運用してみると、MCPを採用した価値は「新しいLLMプロバイダに移行するコストが下がる」ことでも実感できます。私が2025年後半に担当した案件では、GPT-5.1からClaude Opus 5に切り替える判断が下ったのが金曜午後、翌月曜には切替完了 ─ ツール定義をMCP経由で提供していたため、変更はプロバイダSDKの呼び出し部分だけでした。Claude Agent SDKの本番運用ガイド で紹介したHooksパターンとの併用も相性が良く、MCPで公開したツールの前後にHookを差し込んでレート制限や監査ログを追加する運用が定着しています。
本番運用チェックリスト ─ ログ・エラー・認可
ここまでは開発の話です。実際に本番運用に載せるとき、私がクライアントに必ず確認するチェックリストが以下の7項目です。SaaSにMCPサーバーを埋め込む場合、これを飛ばすと確実に事故ります。
1. 認可(Authorization)
Streamable HTTPで公開する時点で、認可なしはあり得ません。spec 2025-03-26に準拠したOAuth 2.1を実装するか、既存のBearer JWT検証を挟みます。Auth0/Okta/Keycloakを持っている組織なら、それをAuthorization Serverとして使うのが最短経路です。/.well-known/oauth-authorization-serverのメタデータURLをMCPクライアントに教えるだけで、動的クライアント登録が動きます。
2. Rate Limiting とサーキットブレーカ
LLMエージェントは「同じツールを100回連続で呼ぶ」ような失敗モードを持ちます。ツール実装側で必ずレート制限を入れてください。私はslowapi(FastAPI用)かaiolimiterで、ユーザーIDごとに10 req/秒、500 req/時 を最低ラインにしています。上流APIが落ちた時のサーキットブレーカ(purgatoryやcircuitbreaker)も入れておくと、深夜のRate Limit連鎖崩壊を防げます。
3. 構造化ログとトレース
MCPツール呼び出しは分散トレースの絶好の対象です。OpenTelemetry GenAI規約(2026時点でBeta)に従って、gen_ai.tool.name、gen_ai.tool.call.id、入出力トークン数を記録しておけば、後からLangfuseやArize Phoenixで分析できます。詳細はLLMオブザーバビリティの記事 でまとめました。
4. エラーの分類
ツールが失敗したとき、モデルにリトライ可能なエラー を伝えるか、ユーザーに戻すべきエラー を伝えるかを区別する必要があります。FastMCPではToolErrorと通常のPython例外で扱いが変わります。
from fastmcp.exceptions import ToolError
@mcp.tool()
async def transfer_funds(from_acct: str, to_acct: str, amount: int) -> dict:
if amount <= 0:
# モデルに戻す(モデルが再試行/修正可能)
raise ToolError("amountは正の整数である必要があります")
try:
return await banking_api.transfer(from_acct, to_acct, amount)
except InsufficientFunds as e:
# ビジネスエラー ─ モデルに戻して代替案を提示させる
raise ToolError(f"残高不足: {e.balance}円")
except httpx.HTTPStatusError as e:
if e.response.status_code >= 500:
# 内部エラー ─ MCPレイヤでリトライすべき
raise # そのままpropagate、isError=true + code=-32603
raise ToolError(f"銀行API拒否: {e.response.text}")
5. Idempotency
書き込み系ツールは冪等キーを取ることを強く推奨します。エージェントは平気で同じ発注を2回投げます。Idempotency-Keyヘッダを上流APIに渡すか、自前でRedisに{tool_name}:{args_hash}:{user_id}を24時間キャッシュしましょう。
6. MCP Inspectorでの手動テスト
公式のMCP Inspector (npx @modelcontextprotocol/inspector)は、ツール・リソース・プロンプトを対話的に叩けるデバッガです。CI/CDに組み込みにくいですが、リグレッションチェックには自動化されたeval harnessを別途組みます。エージェント評価の詳細はAIエージェントのEvals実践入門 で解説しています。
7. バージョニングと後方互換
ツール名やパラメータを変更するとき、既存クライアントのプロンプト・エージェント履歴が壊れます。「削除しない・リネームしない」を原則にして、新機能は新ツールとして追加し、旧ツールは deprecated: true(FastMCPの@mcp.tool(annotations={"deprecated": True}))でマークしましょう。3〜6ヶ月の移行期間を置いてから削除するのが安全です。
補足: 2026年内に予定されているspec更新では、Sampling(サーバーからLLM推論を要求するメカニズム)とElicitation(サーバーがユーザーに追加入力を要求する)の仕様が固まる見込みです。Anthropicの仕様リポジトリ のRoadmapを追いかけておくと良いでしょう。
よくある質問
MCPサーバーはPython以外の言語でも書けますか?
はい。公式SDKはTypeScript、Python、Kotlin、Java、C#、Swift、Ruby、Rustが提供されています(2026年9月時点)。仕様はJSON-RPC 2.0ベースなので、SDKが無い言語でも自前で実装できます。ただしFastMCP相当の高レベルAPIを持つのは現状Python(FastMCP)とTypeScript(公式SDKのServer class)だけで、他言語では低レベルAPIでの実装が中心になります。
MCPサーバーはどこにホストするのが一般的ですか?
ローカルツール(ファイル操作、ローカルDB)はstdio + ユーザーPC上で動かすのが標準です。SaaS的にチーム全体に配布する場合はStreamable HTTPで公開し、Cloudflare Workers、Fly.io、AWS Lambda(Function URL経由)、Google Cloud Runなどが定番のホスティング先です。CloudflareとMicrosoftはマネージドMCPホスティングを2025年に発表しており、認可・ログ・スケーリングを肩代わりしてくれます。
既存のOpenAPI仕様からMCPサーバーを自動生成できますか?
できます。FastMCPにはFastMCP.from_openapi()という関数があり、OpenAPI 3.x仕様を渡すと各エンドポイントをToolsまたはResourcesとして自動公開します。ただし自動生成されたツール名・説明文はLLMにとって不親切なことが多いので、本番運用では手動で説明文を上書きするか、AsyncAPI/OpenAPIのdescriptionを改善するのがおすすめです。
MCPサーバーからLLMを呼び出すことはできますか?
Sampling という仕組みで可能です。サーバーがクライアントに「このプロンプトをあなたのLLMで実行して結果を返してほしい」と依頼できます。これによりサーバー側でAPIキーを持たずに、ユーザーの契約しているLLMを間接的に使えます。ただし2026年9月時点でSamplingを完全サポートしているクライアントはClaude DesktopとClaude Codeのみで、Cursor・ChatGPT側は対応途中です。
MCPとLangChain Tools、どちらでツールを書くべきですか?
目的次第です。LangChain/LangGraph内部でのみ使うならLangChain Toolsが軽量です。同じツールを複数のクライアント(Claude Desktop、Cursor、社内Web UIなど)に配布したいならMCPが有利です。両者は排他ではなく、LangChainにはlangchain-mcp-adaptersというライブラリがあり、任意のMCPサーバーをLangChain Toolとしてマウントできます。私は「本番配布はMCP、社内エージェントの内部ツールはLangChain」のハイブリッドで運用しています。