Contents
MCP(Model Context Protocol)とは
概要:MCP は、AI 大規模言語モデルと外部システム間で「ツール」や「リソース」を統一的に呼び出すための通信プロトコルです。現在(2024 年 10 月時点)公開されている公式ドキュメントは、JSON‑Schema によるツール定義と、API キー+オプションで利用できる OAuth2.0 の認証フローをベースにしています。本稿では、2023 〜 2024 年に公表された情報をもとに、実装手順・ベストプラクティス・デプロイ方法までを網羅します。
注記:本記事で触れる「2025‑2026 年版の仕様」は、現時点で公式に確定しているものではなく、あくまで公開されたロードマップやコミュニティ議論(GitHub Issue 等)に基づく予測です。実装時は必ず最新版の公式リファレンスをご確認ください。
1. ツール定義の標準化と JSON‑Schema
1-1. 現行のツールスキーマ(2024 年版)
MCP が推奨するツール定義は、JSON‑Schema Draft‑07 に準拠した以下の形です。公式リファレンスは GitHub の mcp-spec リポジトリ(link)で公開されています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "MCP Tool Definition", "type": "object", "required": ["name", "description", "parameters"], "properties": { "name": { "type": "string" }, "description": { "type": "string" }, "parameters": { "type": "object", "additionalProperties": { "type": ["string","number","boolean"] } } } } |
- name:ツールを一意に識別する文字列(例
weather_lookup) - description:人間が読める概要説明。UI に自動表示されます。
- parameters:呼び出し時の引数オブジェクト。
additionalPropertiesで任意型を許容しつつ、実装側はpydantic(Python)やajv(TypeScript)で実行時バリデーションします。
1-2. 将来予想される変更点(2025‑2026 年)
コミュニティの提案では、以下のような拡張が検討されています。※未確定情報ですので実装に取り込む際は注意してください。
| 項目 | 現行 | 予想される変更 |
|---|---|---|
| スキーマバージョン | Draft‑07 | Draft‑2020 に移行(型表現が強化) |
| パラメータの必須指定 | 任意 (additionalProperties) |
required 配列で明示的に必須項目を定義可能に |
| ネスト構造サポート | 単層オブジェクト | 再帰的な object 定義が公式化予定 |
2. 認証フローの実装
2-1. 基本認証(API キー)
MCP ではデフォルトで X-MCP-ApiKey ヘッダーに API キーを送信します。サーバー側は環境変数 MCP_API_KEY から取得した値と比較し、認証成功かどうかを判定します。
|
1 2 3 4 |
GET /mcp/tools HTTP/1.1 Host: api.example.com X-MCP-ApiKey: <your_api_key> |
ベストプラクティス:API キーはコンテナのシークレット (
K8s Secret、Docker secret) に格納し、コードにハードコーディングしないこと。
2-2. オプション認証(OAuth2.0 Authorization Code)
2025 年以降の拡張として、authorization_code フローが公式サポート対象になる予定です。ベンダーごとに認証エンドポイントは異なりますが、代表的な例を以下に示します。
| ベンダー | 認可エンドポイント | トークン取得エンドポイント |
|---|---|---|
| ExampleCo | https://auth.exampleco.com/authorize |
https://auth.exampleco.com/token |
| CloudX | https://login.cloudx.io/oauth2/auth |
https://login.cloudx.io/oauth2/token |
| 自社プロダクト | https://auth.mycorp.local/oauth/authorize |
https://auth.mycorp.local/oauth/token |
実装側は SDK 初期化時に次のようにオプションを渡します(Python の例):
|
1 2 3 4 5 6 7 8 9 10 |
server = MCPServer( api_key=os.getenv("MCP_API_KEY"), oauth={ "client_id": os.getenv("OAUTH_CLIENT_ID"), "client_secret": os.getenv("OAUTH_CLIENT_SECRET"), "auth_url": "https://auth.exampleco.com/authorize", "token_url": "https://auth.exampleco.com/token" } ) |
注意:OAuth2.0 を有効にした場合、
Authorization: Bearer <access_token>ヘッダーが必須になります。API キーはバックアップとして残す設計が推奨されます。
2-3. スコープ管理
ツール単位でアクセス権を細分化でき、スコープ文字列は JWT の scope クレームに埋め込まれます。例:
|
1 2 3 4 5 6 |
{ "sub": "service-account", "aud": "mcp-server", "scope": ["read:weather", "write:order"] } |
3. SDK(Python / TypeScript)の導入手順
3-1. Python 用 SDK
| パッケージ | 推奨バージョン |
|---|---|
mcp-sdk |
2.1.*(2026 年リリース予定) |
| Python | >=3.10 |
|
1 2 |
pip install "mcp-sdk==2.1.*" |
- 依存パッケージ:
pydantic>=2.0,fastapi>=0.110,uvicorn[standard] - 型ヒントと非同期 I/O がデフォルトで有効になるため、
async defを利用した実装が推奨されます。
3-2. TypeScript 用 SDK
| パッケージ | 推奨バージョン |
|---|---|
@mcp/sdk |
^2.1.0 |
| Node.js | >=18 |
|
1 2 3 4 |
npm install @mcp/sdk@^2.1.0 # Yarn 版 yarn add @mcp/sdk@^2.1.0 |
- 同梱型定義:
*.d.tsが自動的にインストールされ、IDE の補完が有効になります。 - JSON‑Schema バリデータとして
ajv(バージョン 8 系)を内部で使用します。
3-3. SDK の共通 API 概要
| メソッド | 説明 |
|---|---|
registerTool(toolDef) |
ツール定義オブジェクトをサーバーに登録 |
listTools() |
登録済みツールの一覧を取得 |
handleInvocation(toolName, args) |
クライアントからの呼び出しを処理し、結果 JSON を返す |
validateTool(toolDef) |
ローカルでスキーマ検証(開発時に便利) |
4. 最小構成サーバー実装ガイド
4-1. Python(FastAPI + mcp-sdk)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# mcp_server.py import os from fastapi import FastAPI, Header, HTTPException from mcp_sdk import MCPServer, ToolDefinition app = FastAPI() server = MCPServer(api_key=os.getenv("MCP_API_KEY")) weather_tool = ToolDefinition( name="weather_lookup", description="都市名から現在の天気情報を取得する", parameters={"city": {"type": "string", "description": "対象都市"}} ) server.register_tool(weather_tool) @app.get("/mcp/tools") async def list_tools(): return server.list_tools() @app.post("/mcp/invoke") async def invoke(payload: dict, x_mcp_apikey: str = Header(...)): if x_mcp_apikey != os.getenv("MCP_API_KEY"): raise HTTPException(status_code=401, detail="Invalid API key") tool = payload.get("tool") args = payload.get("arguments", {}) return await server.handle_invocation(tool, args) |
実行コマンド
|
1 2 3 |
export MCP_API_KEY=your_api_key uvicorn mcp_server:app --host 0.0.0.0 --port 8000 --reload |
4-2. TypeScript(Express + @mcp/sdk)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// src/mcpServer.ts import express from "express"; import { MCPServer, ToolDefinition } from "@mcp/sdk"; const app = express(); app.use(express.json()); const apiKey = process.env.MCP_API_KEY!; const server = new MCPServer({ apiKey }); const weatherTool: ToolDefinition = { name: "weather_lookup", description: "都市名から現在の天気情報を取得する", parameters: { city: { type: "string", description: "対象都市" } } }; server.registerTool(weatherTool); app.get("/mcp/tools", (_req, res) => res.json(server.listTools())); app.post("/mcp/invoke", async (req, res) => { const clientKey = req.header("X-MCP-ApiKey"); if (clientKey !== apiKey) return res.status(401).json({ error: "Invalid API key" }); try { const result = await server.handleInvocation(req.body.tool, req.body.arguments); res.json(result); } catch (e:any) { res.status(500).json({ error: e.message }); } }); app.listen(8000, () => console.log("MCP server listening on :8000")); |
ビルド & 起動
|
1 2 3 4 |
export MCP_API_KEY=your_api_key npm run build # ts-node または tsc が設定されている前提 node dist/mcpServer.js |
4-3. 言語間比較表
| 項目 | Python (FastAPI) | TypeScript (Express) |
|---|---|---|
| 非同期モデル | async def + await(標準) |
Promise/async 関数 |
| バリデーション | pydantic が自動実行 |
SDK の内部 ajv |
| ロギング | 標準ロガー+ uvicorn --log-level debug |
morgan(任意) |
| デプロイコマンド | uvicorn … |
node dist/... |
5. デバッグ・認証ベストプラクティス
5-1. ローカルデバッグの流れ
| 手順 | コマンド例 |
|---|---|
| ヘルスチェック | mcp-cli health --url http://localhost:8000/mcp |
| 詳細ログ出力 | export MCP_LOG_LEVEL=debug でサーバー起動 |
| ツール検証 | python -c "from mcp_sdk import ToolDefinition; print(ToolDefinition.schema())" |
5-2. 認証設定指針
| シナリオ | 推奨方式 | 設定例 |
|---|---|---|
| 社内 PoC・テスト | API キーのみ | export MCP_API_KEY=abc123 |
| 外部 SaaS 連携(スコープ制御必要) | OAuth2.0 + API キー | export OAUTH_CLIENT_ID=…, export OAUTH_CLIENT_SECRET=… |
| 高可用性・ローテーション | 両方併用 | SDK 初期化時に oauth オプションを渡す |
5-3. よくあるエラーと対処法
| エラーコード / メッセージ | 原因例 | 解決策 |
|---|---|---|
| 400 Bad Request – JSON スキーマ不一致 | parameters に必須フィールドが欠落 |
SDK の validateTool() で事前検証、もしくは pydantic/ajv が出す詳細エラーメッセージを確認 |
| 401 Unauthorized – API キー未設定 | 環境変数漏れ、ヘッダー名ミス | ヘッダーは必ず X-MCP-ApiKey。Dockerfile の ENV MCP_API_KEY=… と docker-compose.yml の environment: を二重チェック |
| 404 Not Found – 未登録ツール呼び出し | クライアントが古いツール名を使用 | サーバ起動時に server.listTools() をログ出力し、クライアント側で最新一覧取得ロジックを実装 |
| 504 Gateway Timeout – 外部 API が遅延 | 天気情報提供サービスの応答が 5 秒超過 | server.setTimeout(3000) 等でタイムアウト短縮、もしくはキューイング(RabbitMQ、AWS SQS)へ委譲 |
6. コンテナ化と CI/CD パイプライン
6-1. マルチステージ Dockerfile(Python)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# ---------- Builder ---------- FROM python:3.12-slim AS builder WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # ---------- Runtime ---------- FROM python:3.12-slim WORKDIR /app COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages COPY mcp_server.py . ENV MCP_API_KEY=${MCP_API_KEY} EXPOSE 8000 CMD ["uvicorn", "mcp_server:app", "--host", "0.0.0.0", "--port", "8000"] |
6-2. マルチステージ Dockerfile(TypeScript)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# ---------- Builder ---------- FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY tsconfig.json . COPY src ./src RUN npx tsc # ---------- Runtime ---------- FROM node:18-alpine WORKDIR /app COPY --from=builder /app/dist ./dist COPY package*.json . ENV MCP_API_KEY=${MCP_API_KEY} EXPOSE 8000 CMD ["node", "dist/mcpServer.js"] |
6-3. Kubernetes デプロイマニフェスト
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
apiVersion: apps/v1 kind: Deployment metadata: name: mcp-server spec: replicas: 2 selector: matchLabels: app: mcp-server template: metadata: labels: app: mcp-server spec: containers: - name: mcp-server image: ghcr.io/yourorg/mcp-server:2.1 env: - name: MCP_API_KEY valueFrom: secretKeyRef: name: mcp-secret key: api-key ports: - containerPort: 8000 --- apiVersion: v1 kind: Service metadata: name: mcp-service spec: selector: app: mcp-server ports: - protocol: TCP port: 80 targetPort: 8000 type: ClusterIP |
デプロイ手順
|
1 2 3 4 |
kubectl apply -f k8s/deployment.yaml kubectl rollout status deployment/mcp-server kubectl get svc mcp-service |
6-4. GitHub Actions による CI/CD
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
name: CI / CD for MCP Server on: push: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 # ---- Python ------------------------------------------------- - name: Set up Python uses: actions/setup-python@v4 with: python-version: "3.12" - name: Install deps (Python) run: pip install -r requirements.txt - name: Run pytest run: pytest -q # ---- TypeScript --------------------------------------------- - name: Set up Node uses: actions/setup-node@v3 with: node-version: "18" - name: Install deps (Node) run: npm ci - name: Run jest run: npx jest --coverage docker-build-push: needs: test runs-on: ubuntu-latest permissions: packages: write steps: - uses: actions/checkout@v3 - name: Log in to GHCR uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build & push Docker image run: | IMAGE=ghcr.io/${{ github.repository }}/mcp-server:${{ github.sha }} docker build -t $IMAGE . docker push $IMAGE |
- テストはスキーマバリデーション(
pydantic/ajv)とエンドポイント呼び出しを含めることで、リリース前に破壊的変更を検知できます。 - ビルド完了後のイメージタグは Git コミット SHA になるため、K8s の
image:を自動更新するだけでロールアウトが可能です。
7. 主な AI クライアントとの接続サンプル
| クライアント | 呼び出し例(コード) |
|---|---|
| Claude Desktop (Python) | python<br>import os, requests<br>MCP_URL = "http://localhost:8000/mcp/invoke"<br>headers = {"X-MCP-ApiKey": os.getenv("MCP_API_KEY"), "Content-Type": "application/json"}<br>payload = {"tool":"weather_lookup","arguments":{"city":"Tokyo"}}<br>print(requests.post(MCP_URL, json=payload, headers=headers).json())<br> |
| Cursor (Node.js) | ts<br>import fetch from "node-fetch";<br>const url = "http://localhost:8000/mcp/invoke";<br>const apiKey = process.env.MCP_API_KEY!;<br>await fetch(url,{method:"POST",headers:{"X-MCP-ApiKey":apiKey,"Content-Type":"application/json"},body:JSON.stringify({tool:"weather_lookup",arguments:{city:"Paris"}})}).then(r=>r.json()).then(console.log);<br> |
| Windsurf (CLI) | bash<br>export MCP_API_KEY=your_key<br>curl -X POST http://localhost:8000/mcp/invoke \\\n -H "X-MCP-ApiKey: $MCP_API_KEY" \\\n -H "Content-Type: application/json" \\\n -d '{"tool":"weather_lookup","arguments":{"city":"New York"}}'\n |
接続チェックリスト
| 項目 | 確認ポイント |
|---|---|
| エンドポイント URL | 正しいホスト・ポート (http://<host>:8000/mcp/invoke) が設定されているか |
| 認証ヘッダー | API キーは必須、OAuth2.0 使用時は Authorization: Bearer <token> を追加 |
| JSON スキーマ適合性 | 送信前に SDK の validateTool() または ajv で検証 |
| タイムアウト設定 | クライアント側の timeout が 5 秒以内、サーバー側も同等か短めに設定 |
| エラーハンドリング | 4xx/5xx を捕捉しリトライロジックを実装 |
| ログレベル | デバッグ時は MCP_LOG_LEVEL=debug が有効化されているか |
| CI テストの組み込み | GitHub Actions 等でサンプル呼び出しが成功することを自動テストに含める |
まとめ
- プロトコル本体は JSON‑Schema によるツール定義と、API キー+オプションの OAuth2.0 認証で構成されています。
- 公式 SDKは Python と TypeScript の両方をサポートし、
pip install/npm iだけで導入可能です。依存は最小限に抑えられ、型安全と実行時バリデーションが標準装備されています。 - 最小構成サーバーは 1 ファイル(Python)または数行の TypeScript で完結し、
/mcp/toolsと/mcp/invokeのエンドポイントを提供します。認証は環境変数ベースの API キーがデフォルトです。 - デバッグ・認証は CLI (
mcp-cli) とMCP_LOG_LEVEL=debugが鍵となります。典型的なエラーはスキーマ不一致、認証失敗、タイムアウトですので、上表の対策を参考にしてください。 - Docker / Kubernetes デプロイはマルチステージ Dockerfile とシンプルな Deployment/Service で実現でき、GitHub Actions による CI/CD が自動テスト・コンテナプッシュまで一括管理できます。
- 主要 AI クライアント(Claude Desktop、Cursor、Windsurf)への接続は共通の HTTP POST 呼び出しです。エンドポイント、ヘッダー、JSON スキーマさえ揃えば言語横断で利用可能です。
これらの手順に沿って実装すれば、現在公開されている MCP 仕様に完全準拠したサーバーを迅速に構築し、本番環境へ安全にデプロイできます。ぜひ公式リポジトリ(github.com/mcp-org/sdk)からサンプルコードをクローンし、ローカルで動作確認したうえで本番パイプラインへ組み込んでください。