結論: MCP(Model Context Protocol)は、ClaudeやGPTなどのAIアシスタントが外部ツール・データ・テンプレートを標準プロトコルで呼び出すための仕様です。独自サーバーを実装することで、社内DBや業務APIをAIに接続できます。
この記事の要点:
- MCP Serverは「Tools(実行)」「Resources(データ提供)」「Prompts(テンプレート)」の3プリミティブで構成される
- Python SDK(FastMCP)またはTypeScript SDKで最短30分で動くサーバーを作れる
- Claude Code / Cursor / VS Code Continueの3つのクライアントに同一サーバーを接続できる
対象読者: MCPという言葉を聞いたことがある開発者・IT担当者で、「自社サービスをAIに接続したい」と考えている方
読了後にできること: ローカルでHello World MCP Serverを起動し、Claude Codeから呼び出すところまで完了できる
「MCPって結局何が違うの?」
Claude Codeを本格導入した際に、社内の開発チームから最初に飛んできた質問です。
当時は「AIのfunction callingをオープン標準にしたもの」と説明していましたが、実際に手を動かして10数本のMCP Serverを組んでみると、この説明では全然足りないと気づきました。
MCPは「AIが外部世界とつながる方法の標準化」であり、一度サーバーを実装するとClaude Code・Cursor・VS Code Continue・Claude Desktopの全クライアントで再利用できるという、エコシステム全体に影響するアーキテクチャです。
この記事では、Anthropic公式SDKと実際の実装経験をベースに、MCP Serverの構築方法をTools・Resources・Promptsの3プリミティブに分けて全解説します。
コードブロックはそのままコピペして動く形で用意しました。今日中に手元で動くものを作りたい方は、ぜひ手を動かしながら読んでみてください。
なお、AIエージェント・Claude Code全般の基礎については Claude Code Hooks完全ガイド もあわせて参照してください。AIエージェントの概念から実装まで体系的に理解したい方は AIエージェント導入完全ガイド もどうぞ。
MCPとは何か — AIと外部ツールをつなぐ標準プロトコル
Model Context Protocol(MCP)は、Anthropicが2024年11月に発表したオープン仕様です。JSON-RPC 2.0をベースに、LLMホストアプリ(Claude Code、Cursorなど)が外部サーバーのツール・データ・テンプレートを呼び出すための「共通言語」を定義しています。
もう少し噛み砕くと、こういうことです。
従来のfunction callingは「OpenAIのAPI仕様でしか動かない」「Anthropicの仕様に書き直さないといけない」という状況でした。MCPはそこを標準化しました。
1つのMCP Serverを作れば、MCPに対応したすべてのクライアント(Claude Code、Cursor、VS Code Continue、Claude Desktop、Zed等)から呼び出せます。
2026年現在、MCP Dev Summitには約1,200名の参加者が集まり(2026年4月、AAIF主催)、GitHub上のMCP Serverリポジトリは数百を超えています。標準として急速に普及が進んでいる状況です。
なぜMCPが必要か — 「AIの外部接続問題」を解決する
AIを業務に組み込もうとすると、必ずこの壁にぶつかります。
- 「社内の顧客DBをClaudeに参照させたい」
- 「Slackの未読メッセージをAIに要約させたい」
- 「GitHubのIssueを自動でトリアージさせたい」
これらはすべて「LLMの外部にあるデータ・システムへのアクセス」の問題です。MCP以前は、各クライアントの独自実装(プラグイン、カスタムコマンド等)に依存していました。
MCPは、このアクセスパターンをプロトコルレベルで標準化することで、「一度実装すれば、どのAIクライアントでも動く」状態を実現します。
MCP Server vs MCP Client — 用語の整理
実装を始める前に、用語を整理しておきます。ここが混乱ポイントなので丁寧に説明します。
| 役割 | 具体例 | あなたが作るもの |
|---|---|---|
| MCP Host | Claude Code / Cursor / VS Code | 作らない(既製品を使う) |
| MCP Client | HostがServerと通信するための内部コンポーネント | 基本的に作らない(SDKが実装済み) |
| MCP Server | ファイルシステムServer / Slackアクセス / 自社DBコネクタ | これを作る |
つまり、この記事で「MCP Serverを作る」とは、Claude CodeやCursorが呼び出せるバックエンドサービスを実装することです。
アーキテクチャとしては、1つのMCP Hostが複数のMCP Clientを持ち、各クライアントが独立したServerと1対1で接続します。VS CodeはSentryのMCP ServerとFilesystemのMCP Serverに同時接続できる、という形です。
環境構築 — Python SDKとTypeScript SDK
MCPの公式SDKはPythonとTypeScriptの両方が提供されています。どちらを選ぶかはチームの技術スタックで決めれば問題ありません。
Python SDK(FastMCP)のセットアップ
2026年時点でのPython環境構築はuvを推奨します。
# プロジェクト初期化(uvを使う場合)
uv init my-mcp-server
cd my-mcp-server
# MCP Python SDKのインストール
uv add "mcp[cli]"
# または pip を使う場合
pip install "mcp[cli]"FastMCPは公式Pythonのハイレベルラッパーで、デコレータベースの直感的なAPIを提供します。後述の実装例はすべてFastMCPを使います。
TypeScript SDKのセットアップ
# Node.js + TypeScriptプロジェクト初期化
mkdir my-mcp-server-ts && cd my-mcp-server-ts
npm init -y
# TypeScript + MCP SDKのインストール
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/node tsx
# tsconfig.json作成
npx tsc --init --target ES2022 --module NodeNext --moduleResolution NodeNextpackage.jsonのscriptsに以下を追加しておくと便利です。
{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}
}基本Server実装 — Hello World
まず、最小構成のMCP Serverを動かします。「これだけで動く」という構造を理解してから、各プリミティブに拡張していきます。
Python版 Hello World
from mcp.server.fastmcp import FastMCP
# サーバーインスタンスを作成
mcp = FastMCP("hello-world")
@mcp.tool()
def greet(name: str) -> str:
"""指定された名前で挨拶する"""
return f"Hello, {name}! MCPサーバーが動いています。"
if __name__ == "__main__":
# stdioトランスポートで起動(Claude Code / Cursorはこれを使う)
mcp.run(transport="stdio")TypeScript版 Hello World
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "hello-world",
version: "1.0.0",
});
server.registerTool(
"greet",
{
description: "指定された名前で挨拶する",
inputSchema: {
name: z.string().describe("挨拶する相手の名前"),
},
},
async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name}! MCPサーバーが動いています。` }],
})
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main();どちらの実装もJSON-RPC 2.0を使って標準入出力で通信します。Claude Codeがこのプロセスを起動し、stdioを通じてメッセージをやりとりします。
Tools実装 — AIが実行できる関数
ToolsはMCPの3プリミティブの中で最も使われます。「AIが外部世界に対して何かを実行できる」機能です。function callingの概念に近いですが、MCPクライアントすべてに対して汎用的に使える点が違います。
実際に使われた例として、社内CRMにアクセスするToolを実装したことがあります。営業チームが「このリードの過去の商談記録をClaudeに要約させたい」という要望で作ったものです。Claude Codeから呼び出せるようになった結果、商談準備の時間が大幅に短縮されました。
Python:実用的なTools実装例
from mcp.server.fastmcp import FastMCP
import httpx
import json
from typing import Optional
mcp = FastMCP("business-tools")
@mcp.tool()
async def search_web(query: str, max_results: int = 5) -> str:
"""
ウェブ検索を実行し、結果を返す。
最新情報の取得や、特定トピックの調査に使用。
不足情報があれば最初に質問してください。
"""
# 実際の実装では検索APIを呼び出す
# ここでは構造を示す擬似実装
results = [
f"[結果{i+1}] {query}に関する情報(実装時に実際のAPIに置き換え)"
for i in range(max_results)
]
return "n".join(results)
@mcp.tool()
def calculate_roi(
investment: float,
monthly_savings: float,
months: int
) -> dict:
"""
ROI(投資対効果)を計算する。
AI導入コストと期待される削減効果から投資回収期間を算出。
数字と固有名詞は必ず根拠とともに提示します。
"""
total_savings = monthly_savings * months
net_gain = total_savings - investment
roi_percent = (net_gain / investment) * 100
payback_months = investment / monthly_savings if monthly_savings > 0 else float('inf')
return {
"投資額": f"¥{investment:,.0f}",
"総削減額": f"¥{total_savings:,.0f}",
"純利益": f"¥{net_gain:,.0f}",
"ROI": f"{roi_percent:.1f}%",
"回収期間": f"{payback_months:.1f}ヶ月"
}
@mcp.tool()
async def send_slack_notification(
channel: str,
message: str,
mention_user: Optional[str] = None
) -> str:
"""
Slackにメッセージを送信する。
重要なアラートや作業完了通知に使用。
実行前に必ずユーザーに内容を確認すること。
"""
# Slack WebhookやAPIを呼び出す実装例
payload = {
"channel": channel,
"text": f"{f' ' if mention_user else ''}{message}"
}
# await send_to_slack(payload) # 実際のAPI呼び出し
return f"Slack通知送信完了: #{channel} へ '{message[:50]}...' を送信"
if __name__ == "__main__":
mcp.run(transport="stdio")TypeScript:非同期Toolsの実装パターン
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({ name: "async-tools", version: "1.0.0" });
// データベースクエリToolの例
server.registerTool(
"query_database",
{
description: "SQLクエリを安全に実行してデータを取得する。SELECT文のみ許可。",
inputSchema: {
sql: z.string().describe("実行するSELECT文"),
limit: z.number().optional().default(100).describe("最大取得件数"),
},
},
async ({ sql, limit }) => {
// SELECT文のみ許可(セキュリティ対策)
if (!sql.trim().toLowerCase().startsWith("select")) {
return {
content: [{ type: "text", text: "エラー: SELECT文のみ実行できます。" }],
isError: true,
};
}
// 実際のDB接続と実行(例:pg / mysql2等)
// const result = await db.query(`${sql} LIMIT ${limit}`);
const mockResult = [{ id: 1, name: "サンプルデータ" }];
return {
content: [
{
type: "text",
text: JSON.stringify(mockResult, null, 2),
},
],
};
}
);Resources実装 — 読み取り専用データの提供
Resourcesは「AIが参照できる読み取り専用のデータソース」です。ToolsとはAPIの設計思想が異なります。
| Tools | Resources | |
|---|---|---|
| 目的 | 何かを実行・変更する | 情報を読み取る・参照する |
| 副作用 | あり(APIコール、DB書き込み等) | なし(読み取り専用) |
| HTTP類比 | POST / PUT / DELETE | GET |
| 典型的な用途 | 検索実行、メール送信、計算 | ドキュメント参照、設定ファイル読み込み、スキーマ確認 |
企業向け研修でMCPを説明するとき、「Resourcesはナレッジベース、Toolsはアクション」と例えると伝わりやすいです。社内の設計書・規程・マニュアルをResourcesとして提供し、それを参照しながらToolsで実際の処理を実行するというパターンが実務では多いです。
Python:Resourcesの実装例
from mcp.server.fastmcp import FastMCP
from pathlib import Path
import json
mcp = FastMCP("knowledge-base")
# 静的Resourceの例:会社規程ドキュメント
@mcp.resource("docs://company-policy/{policy_name}")
def get_company_policy(policy_name: str) -> str:
"""
会社規程ドキュメントを返す。
policy_name: 'hr', 'security', 'expense' のいずれか
"""
policies = {
"hr": "人事規程:標準労働時間は1日8時間...",
"security": "情報セキュリティポリシー:外部クラウドの利用は事前申請...",
"expense": "経費精算規程:交通費は実費精算、領収書必須..."
}
return policies.get(policy_name, f"'{policy_name}'という規程は見つかりませんでした。")
# 動的Resourceの例:ファイルシステムアクセス
@mcp.resource("file://{path}")
def read_file(path: str) -> str:
"""
指定パスのファイルを読み取る。
セキュリティのため、許可されたディレクトリのみアクセス可能。
"""
allowed_dirs = ["/workspace/docs", "/workspace/configs"]
file_path = Path(path)
# パストラバーサル攻撃の防止
if not any(str(file_path).startswith(allowed) for allowed in allowed_dirs):
return f"アクセス拒否: '{path}'は許可されたディレクトリ外です。"
if not file_path.exists():
return f"ファイルが見つかりません: {path}"
return file_path.read_text(encoding="utf-8")
# DBスキーマResourceの例
@mcp.resource("db://schema/{table_name}")
def get_table_schema(table_name: str) -> str:
"""
データベーステーブルのスキーマ情報を返す。
クエリ作成前にこのResourceを参照して正確なカラム名を確認すること。
"""
# 実際の実装ではDBからINFORMATION_SCHEMAを取得
schemas = {
"customers": json.dumps({
"columns": [
{"name": "id", "type": "bigint", "nullable": False},
{"name": "company_name", "type": "varchar(255)", "nullable": False},
{"name": "email", "type": "varchar(255)", "nullable": True},
{"name": "created_at", "type": "timestamp", "nullable": False}
]
}, ensure_ascii=False, indent=2)
}
return schemas.get(table_name, f"テーブル '{table_name}' のスキーマが見つかりません。")
if __name__ == "__main__":
mcp.run(transport="stdio")TypeScript:URIテンプレートを使ったResources
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({ name: "resource-server", version: "1.0.0" });
// APIドキュメントをResourceとして提供
server.registerResource(
"api-docs",
new ResourceTemplate("apidocs://{endpoint}", {
list: async () => ({
resources: [
{ uri: "apidocs://users", name: "Users API", description: "ユーザー管理API仕様" },
{ uri: "apidocs://orders", name: "Orders API", description: "注文管理API仕様" },
],
}),
}),
async (uri) => {
const endpoint = uri.pathname.replace("//", "");
const docs: Record = {
users: "GET /api/users - ユーザー一覧取得nPOST /api/users - ユーザー作成n...",
orders: "GET /api/orders - 注文一覧取得nGET /api/orders/:id - 注文詳細取得n...",
};
return {
contents: [
{
uri: uri.href,
mimeType: "text/plain",
text: docs[endpoint] ?? "ドキュメントが見つかりません",
},
],
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);Prompts実装 — 再利用可能なテンプレートの提供
PromptsプリミティブはMCPの3つのうち最も見落とされがちですが、チーム開発での価値が高い機能です。「AIへの指示テンプレート」をServerに定義しておくことで、チーム全員が一貫した品質のAI活用ができます。
研修でよく使われる例として、「コードレビュープロンプトの標準化」があります。チームによってレビューの観点がバラバラだったのを、MCPのPromptsで統一したところ、レビュー品質が安定したという事例があります。
Python:Promptsの実装例
from mcp.server.fastmcp import FastMCP
from mcp import types
mcp = FastMCP("prompt-library")
@mcp.prompt()
def code_review_prompt(
language: str,
code: str,
review_level: str = "standard"
) -> list[types.Message]:
"""
コードレビュー用プロンプトテンプレート。
review_level: 'quick'(速読)/ 'standard'(標準)/ 'deep'(詳細)
"""
level_instructions = {
"quick": "5分以内で完了できる主要な問題のみを指摘してください。",
"standard": "セキュリティ・パフォーマンス・可読性の観点でレビューしてください。",
"deep": "アーキテクチャ・テスト・ドキュメント・セキュリティを網羅的にレビューし、改善案をコードで示してください。"
}
return [
types.UserMessage(
content=f"""以下の{language}コードをレビューしてください。
レビューレベル: {review_level}
指示: {level_instructions.get(review_level, level_instructions['standard'])}
指摘は以下の形式で行ってください:
- 🔴 重大(セキュリティ・バグ)
- 🟡 改善推奨
- 🟢 軽微・スタイル
```{language}
{code}
```
仮定した点は必ず「仮定」と明記してください。"""
)
]
@mcp.prompt()
def meeting_summary_prompt(transcript: str) -> list[types.Message]:
"""
会議の文字起こしから議事録を作成するプロンプト。
"""
return [
types.UserMessage(
content=f"""以下の会議文字起こしから、構造化された議事録を作成してください。
必須項目:
1. 決定事項(箇条書き)
2. アクションアイテム(担当者・期限付き)
3. 次回議題候補
4. 未解決の課題・懸念事項
文字起こし:
{transcript}
不足している情報(担当者名など)があれば、[要確認: ○○] という形で明記してください。"""
)
]
if __name__ == "__main__":
mcp.run(transport="stdio")TypeScript:引数付きPromptsの実装
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({ name: "prompt-server", version: "1.0.0" });
server.registerPrompt(
"documentation-writer",
{
description: "関数・クラスのドキュメントを生成するプロンプト",
argsSchema: {
function_name: z.string().describe("ドキュメントを作成する関数名"),
code: z.string().describe("対象のコード"),
doc_style: z.enum(["jsdoc", "tsdoc", "markdown"]).default("tsdoc"),
},
},
async ({ function_name, code, doc_style }) => ({
messages: [
{
role: "user" as const,
content: {
type: "text" as const,
text: `${function_name}のドキュメントを${doc_style}形式で作成してください。
コード:
```typescript
${code}
```
ドキュメントには以下を含めてください:
- 機能の概要(1-2文)
- 引数の説明(型・制約)
- 戻り値の説明
- 使用例(実行可能なコード)
- エラーが発生するケース
数字と固有名詞は根拠を添えてください。`,
},
},
],
})
);Transport — stdio / Streamable HTTP / SSEの使い分け
MCPのトランスポート選択は「ローカルで動かすか、リモートサーバーとして動かすか」で決まります。
| Transport | 用途 | 特徴 | 認証 |
|---|---|---|---|
| stdio | ローカル開発・CLI統合 | 標準入出力で通信。ネットワーク不要。低レイテンシ | なし(プロセス分離が保護) |
| Streamable HTTP | リモートサーバー・マルチクライアント | HTTP POST + Server-Sent Events。スケーラブル | Bearer Token / API Key / OAuth |
| SSE(非推奨) | 旧実装との互換性維持 | MCP仕様2025-03-26で非推奨。新規実装では使わない | — |
Streamable HTTPトランスポートの実装(Python)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("remote-server")
@mcp.tool()
def get_data(query: str) -> str:
"""リモートでデータを取得する"""
return f"データ: {query}"
if __name__ == "__main__":
# Streamable HTTPで起動(マルチクライアント対応)
mcp.run(
transport="streamable-http",
host="0.0.0.0",
port=8080
)Claude Codeとの接続 — .mcp.json設定
MCP Serverが動いたら、Claude Codeから接続します。設定ファイル(.mcp.json)を使います。
プロジェクトスコープの設定(チーム共有用)
{
"mcpServers": {
"business-tools": {
"type": "stdio",
"command": "python3",
"args": ["/path/to/my-mcp-server/main.py"],
"env": {
"DATABASE_URL": "${DATABASE_URL}",
"SLACK_WEBHOOK_URL": "${SLACK_WEBHOOK_URL}"
}
},
"typescript-server": {
"type": "stdio",
"command": "node",
"args": ["/path/to/my-mcp-server-ts/dist/index.js"]
}
}
}このファイルをプロジェクトルートに .mcp.json として保存するとチームで共有できます。~/.claude.json に書けばグローバル設定になります。
CLIでの追加方法
# stdioサーバーをCLIで追加
claude mcp add business-tools python3 /path/to/main.py
# HTTPサーバーを追加
claude mcp add --transport http remote-tools https://your-mcp-server.example.com/
# 追加されたサーバー一覧を確認
claude mcp list接続確認(MCP Inspector)
# MCP Inspectorで動作確認
npx @modelcontextprotocol/inspector python3 /path/to/main.py
# ブラウザで http://localhost:5173 を開く
# Tools / Resources / Prompts を手動テストできるCursor・VS Code Continueとの接続
同じMCP Serverを複数のクライアントから使えるのがMCPの最大の強みです。
Cursorへの接続
プロジェクトルートに .cursor/mcp.json(プロジェクトスコープ)、またはホームディレクトリに ~/.cursor/mcp.json(グローバル)を作成します。
{
"mcpServers": {
"business-tools": {
"command": "python3",
"args": ["/path/to/main.py"],
"env": {
"DATABASE_URL": "postgresql://localhost/mydb"
}
}
}
}Cursorの場合、GUIからも追加できます: Settings > Tools & MCP > New MCP Server
VS Code Continue拡張への接続
# .continue/mcpServers/ ディレクトリを作成してJSONを配置
mkdir -p .continue/mcpServers
# .continue/mcpServers/business-tools.json
{
"command": "python3",
"args": ["/path/to/main.py"]
}Continue拡張はこのディレクトリを自動スキャンしてサーバーを読み込みます。再起動不要です。
デプロイパターン — ローカル / Docker / クラウド
MCP Serverのデプロイ先は用途によって選びます。
ローカル実行(開発・個人利用)
stdio transportを使い、Claude Codeがプロセスを起動・管理します。サーバー側でポートを開く必要がなく、セキュリティ面でシンプルです。設定例は上記の通りです。
Dockerコンテナ(チーム共有・本番)
# Dockerfile(Python版の例)
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# Streamable HTTPで起動
CMD ["python3", "main.py"]
EXPOSE 8080# .mcp.jsonでDockerコンテナに接続
{
"mcpServers": {
"business-tools": {
"type": "stdio",
"command": "docker",
"args": ["run", "--rm", "-i",
"-e", "DATABASE_URL",
"my-mcp-server:latest"
]
}
}
}クラウドデプロイ(Streamable HTTP)
# Cloud Runへのデプロイ例
gcloud run deploy my-mcp-server
--source .
--port 8080
--set-env-vars DATABASE_URL=xxx
--allow-unauthenticated # 本番では認証必須# .mcp.jsonでリモートHTTPサーバーに接続
{
"mcpServers": {
"remote-business-tools": {
"type": "http",
"url": "https://my-mcp-server-xyz.run.app/",
"headers": {
"Authorization": "Bearer ${MCP_API_KEY}"
}
}
}
}セキュリティ — 権限設計と認証の実装
MCP Serverは会社の内部システムにアクセスできる強力なツールです。セキュリティを軽視すると、AIが本来アクセスすべきでないデータを読み書きするリスクがあります。
基本原則:最小権限の徹底
from mcp.server.fastmcp import FastMCP
from functools import wraps
import os
mcp = FastMCP("secure-server")
# 許可されたパスのみアクセス可能
ALLOWED_DIRECTORIES = [
"/workspace/public-docs",
"/workspace/shared-configs"
]
def check_path_permission(path: str) -> bool:
"""パストラバーサル攻撃を防ぐ"""
import pathlib
abs_path = pathlib.Path(path).resolve()
return any(
str(abs_path).startswith(allowed)
for allowed in ALLOWED_DIRECTORIES
)
@mcp.tool()
def read_document(file_path: str) -> str:
"""
承認されたディレクトリのドキュメントを読み取る。
セキュリティ: 許可ディレクトリ外のアクセスは拒否。
"""
if not check_path_permission(file_path):
return "アクセス拒否: 許可されたディレクトリ外のファイルは読み取れません。"
with open(file_path, 'r', encoding='utf-8') as f:
return f.read()APIキーによる認証(Streamable HTTP)
from mcp.server.fastmcp import FastMCP
import os
mcp = FastMCP("authenticated-server")
# 環境変数からAPIキーを取得(ハードコード禁止)
VALID_API_KEYS = set(os.environ.get("MCP_API_KEYS", "").split(","))
# FastMCPのmiddlewareフックでリクエスト認証
# 実際の認証はHTTPミドルウェア層(FastAPI等)で実装する
# 詳細はhttps://gofastmcp.com/deployment/authentication 参照機密情報の取り扱いルール
- APIキー・パスワード・トークンは絶対にコードにハードコードしない → 環境変数(
${VAR})を使う .mcp.jsonをGitにコミットする場合、secrets情報が含まれていないか確認する- ログにはユーザーデータ・認証情報を出力しない
- SQLクエリはパラメータバインディングを使い、インジェクション攻撃を防ぐ
【要注意】失敗パターン4選と回避策
失敗1: stdioとHTTPのトランスポートを混同する
❌ ローカルで動かしているのにHTTPトランスポートの設定を書く
⭕ ローカル開発では "type": "stdio" を使い、commandでプロセスを起動する
これは本当によくあるミスで、研修でも必ず引っかかる場所です。curl localhost:8080 で疎通できるのに、Claude Codeから接続できないと言われるパターンはたいていここです。stdio Serverはポートを開きません。
失敗2: JSONの構文エラーで無言で失敗する
❌ .mcp.jsonに末尾カンマやコメントを書く(JSONは無効)
⭕ JSONバリデーターで必ず検証してから保存する
# 検証方法
python3 -m json.tool .mcp.json
# または
cat .mcp.json | jq .失敗3: Tools・Resources・Promptsのどれを使うべきか迷う
❌ 何でもToolsに実装してしまう
⭕ 判断基準を持つ
- 副作用が必要 or 計算が必要 → Tools
- データを読み取るだけ → Resources
- AIへの指示テンプレートを再利用したい → Prompts
失敗4: エラーハンドリングを省略する
❌ 例外をそのままraise / uncaughtのまま
⭕ MCPのエラーレスポンス形式に合わせてエラーを返す
@mcp.tool()
def risky_operation(input_data: str) -> str:
try:
result = do_something_risky(input_data)
return result
except ValueError as e:
# 意味のあるエラーメッセージをAIに返す
return f"入力エラー: {str(e)}。正しい形式で再試行してください。"
except Exception as e:
# スタックトレースは返さず、操作的なメッセージのみ
return f"処理中にエラーが発生しました。管理者に連絡してください。(エラーID: {type(e).__name__})"Claude Code ピラーページへのリンク設計
MCP Serverを組んだ後、Claude CodeでAIエージェントとしてどう活用するかの全体像については Claude Code Hooks完全ガイド にまとめています。Hooksと組み合わせると、「MCPツールを呼んだ後に自動でログを取る」「特定のToolsが実行される前に確認を挟む」といった高度な運用が可能です。
また、Slash Commandと組み合わせると、チームで標準化したMCP操作を /slash-command で呼び出せるようになります。詳しくは Claude Code Slash Command完全ガイド を参照してください。
参考・出典
- Architecture Overview — Model Context Protocol公式ドキュメント(参照日: 2026-05-06)
- Model Context Protocol Python SDK — GitHub(参照日: 2026-05-06)
- Model Context Protocol TypeScript SDK — GitHub(参照日: 2026-05-06)
- Introducing the Model Context Protocol — Anthropic公式発表(参照日: 2026-05-06)
- MCP Specification 2025-11-25 — modelcontextprotocol.io(参照日: 2026-05-06)
まとめ:今日から始める3つのアクション
MCP Serverは「難しいもの」ではなく、「AIの外部接続を標準化するプロトコル」です。今日から段階的に試していけば、1週間以内に動くものが作れます。
- 今日やること: Python SDKをインストールして、Hello World ServerをClaude Codeから呼び出す(30分あればできます)
- 今週中: 自分の業務で「AIに参照させたいデータ」を1つ選び、Resourcesとして実装する
- 今月中: Tools・Resources・Promptsの3つをそれぞれ1つ以上実装し、Claude Code + Cursorの両方から呼び出してMCPの再利用性を体感する
次の記事では「MCP Server運用のベストプラクティス — ロギング・モニタリング・バージョン管理」をテーマに、本番運用に向けた実践的な内容をお届けします。
著者プロフィール: 佐藤傑(さとう・すぐる)
株式会社Uravation代表取締役。早稲田大学法学部在学中に生成AIの可能性に魅了され、X(旧Twitter)で活用法を発信(@SuguruKun_ai、フォロワー約10万人)。100社以上の企業向けAI研修・導入支援を展開。著書『AIエージェント仕事術』(SBクリエイティブ)。
あわせて読みたい: MCP ServerをPlugin内にバンドルしてチームに配布する方法は、Claude Code Plugin開発完全ガイド2026で解説しています。
ご質問・ご相談は お問い合わせフォーム からお気軽にどうぞ。




