mcp-ops について
mcp-opsは、PythonとTypeScriptでMCPサーバーを構築、テスト、デプロイする開発者向けのガイドです。アーキテクチャや実装資料に加え、変化するエコシステムの事実を検証するスクリプトを備えています。
主な機能
- 01PythonとTypeScriptのサーバーガイド
- 02トランスポートと認証の資料
- 03ツール、リソース、プロンプトの設計指針
- 04テスト、デバッグ、問題解決の解説
- 05MCP情報のドリフト検出スクリプト
活用シーン
- 01ローカルまたはリモートサーバーの方式選定
- 02MCPツールとリソースの設計
- 03サーバー動作のテストとトラブル対応
MCP 対応
MCPサーバーの構築、テスト、デプロイの手法を扱い、PythonとTypeScriptのSDK例を掲載しています。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ 0xdarkmatter/ claude-mods --skill mcp-opsインストール後、Claude Code で/mcp-opsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/.gitkeepmcp-facts.jsonreferences/resources-prompts.mdserver-architecture.mdtesting-debugging.mdtool-handlers.mdtransport-auth.mdscripts/.gitkeepcheck-mcp-facts.pytests/run.sh詳細
MCP オペレーション
Python と TypeScript で Model Context Protocol サーバーを構築、テスト、デプロイするための包括的なパターンです。
エコシステムに関する情報は、2026-07-05 時点で検証済みです(スタンドアロンの FastMCP はメジャーバージョン 3)。
MCP アーキテクチャ早見表
┌─────────────────────────────────────────────────────────┐
│ MCP Host │
│ (Claude Desktop, Claude Code, Custom App) │
│ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Client A │ │ Client B │ │ Client C │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
└────────┼───────────────┼───────────────┼────────────────┘
│ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│Transport│ │Transport│ │Transport│
│ (stdio) │ │ (SSE) │ │ (HTTP) │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────────┴──┐ ┌──────┴────┐ ┌──────┴────┐
│ Server A │ │ Server B │ │ Server C │
│ │ │ │ │ │
│ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │
│ │ Tools │ │ │ │Resources│ │ │ │Prompts │ │
│ └────────┘ │ │ └────────┘ │ │ └────────┘ │
│ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │
│ │Resources│ │ │ │Prompts │ │ │ │ Tools │ │
│ └────────┘ │ │ └────────┘ │ │ └────────┘ │
└────────────┘ └────────────┘ └────────────┘
Protocol: JSON-RPC 2.0 over chosen transport
Flow: Client → request → Server → response → Client
サーバーの種類を選ぶ判断ツリー
What transport does your MCP server need?
│
├─ Local CLI tool / single-user desktop integration?
│ └─ stdio
│ - Simplest setup, no networking
│ - Claude Desktop, Claude Code native support
│ - Process lifecycle managed by host
│
├─ Web dashboard / browser-based client?
│ └─ SSE (Server-Sent Events)
│ - HTTP-based, works through firewalls
│ - Persistent connection for server→client events
│ - Good for development and internal tools
│
└─ Production API / multi-tenant / cloud deployment?
└─ Streamable HTTP
- HTTP POST for requests, SSE for streaming responses
- Supports stateless and stateful modes
- Full auth support, load balancer friendly
- Recommended for production deployments
ツール、リソース、プロンプトを選ぶ判断ツリー
What does the LLM need to do?
│
├─ Perform an action or computation?
│ └─ TOOL
│ - Has side effects (API calls, file writes, DB mutations)
│ - Accepts structured input, returns results
│ - Examples: run_query, create_issue, send_email
│
├─ Read data or context?
│ └─ RESOURCE
│ - Read-only data retrieval
│ - Identified by URI (file://, db://, api://)
│ - Examples: config://app, schema://users, file://readme.md
│
└─ Guide the LLM's behavior or workflow?
└─ PROMPT
- Templated instructions with arguments
- Suggests conversation starters or workflows
- Examples: code_review(language, file), summarize(topic)
Python SDK クイックスタート
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-server")
@mcp.tool()
def search_docs(query: str) -> str:
"""Search documentation by keyword."""
results = perform_search(query)
return "\n".join(f"- {r.title}: {r.snippet}" for r in results)
@mcp.tool()
def create_ticket(title: str, body: str, priority: str = "medium") -> str:
"""Create a support ticket."""
ticket = api.create(title=title, body=body, priority=priority)
return f"Created ticket #{ticket.id}: {ticket.url}"
@mcp.resource("config://app")
def get_config() -> str:
"""Return current application configuration."""
return json.dumps(load_config(), indent=2)
@mcp.resource("schema://db/{table}")
def get_table_schema(table: str) -> str:
"""Return the schema for a database table."""
return json.dumps(get_schema(table), indent=2)
@mcp.prompt()
def code_review(language: str, filepath: str) -> str:
"""Generate a code review prompt for the given file."""
return f"Review this {language} code in {filepath} for bugs, style issues, and performance."
if __name__ == "__main__":
mcp.run() # Defaults to stdio transport
インストールして実行する:
uv init my-mcp-server && cd my-mcp-server
uv add mcp[cli]
# Run with: uv run python server.py
# Or: uv run mcp run server.py
Python の FastMCP は 2 種類あります。どちらを使っているか確認してください。 公式の mcp SDK には、1.x 時代の FastMCP が同梱されています(from mcp.server.fastmcp import FastMCP。上記のサンプルで使用しています。安定しており、最小限の機能を備えています)。スタンドアロンの fastmcp パッケージ(gofastmcp.com)では活発に開発が進められており、メジャーバージョン 3 です。同じデコレーターのインターフェースに加え、認証、プロキシ、OpenAPI の生成、テストクライアントが利用できます。使用するには、次のようにします。
uv add fastmcp
from fastmcp import FastMCP # standalone FastMCP 3 — not mcp.server.fastmcp
mcp = FastMCP("my-server") # v3: constructor is identity/behaviour only;
# transport config moved to run()/serve time
FastMCP 3 の破壊的変更(2.x から):非推奨だったコンストラクターのキーワード引数 16 個が削除されました(トランスポート設定はサーブ時に渡すようになりました)。ui= は app= に置き換えられました。ctx.set_state()/ctx.get_state() はセッションスコープの永続化に対応した非同期メソッドになりました。また、メタデータの名前空間が _fastmcp から fastmcp に変更されました。
TypeScript SDK クイックスタート
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: "my-server",
version: "1.0.0",
});
// Register a tool
server.tool(
"search_docs",
"Search documentation by keyword",
{ query: z.string().describe("Search query") },
async ({ query }) => {
const results = await performSearch(query);
return {
content: [{ type: "text", text: results.join("\n") }],
};
}
);
// Register a resource
server.resource(
"config",
"config://app",
{ description: "Current application configuration" },
async (uri) => ({
contents: [{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(loadConfig(), null, 2),
}],
})
);
// Register a prompt
server.prompt(
"code_review",
"Generate a code review prompt",
{ language: z.string(), filepath: z.string() },
async ({ language, filepath }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Review this ${language} code in ${filepath} for bugs and style issues.`,
},
}],
})
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch(console.error);
インストールして実行する:
npm init -y
npm install @modelcontextprotocol/sdk zod
npx tsx server.ts
トランスポート選択マトリクス
| 機能 | stdio | SSE | Streamable HTTP |
|---|---|---|---|
| 用途 | ローカルの CLI ツール、デスクトップ | Web ダッシュボード、開発 | 本番 API |
| プロトコル | stdin/stdout パイプ | HTTP + EventSource | HTTP POST + SSE |
| 認証サポート | 環境変数のみ | Bearer トークン | OAuth2/PKCE 全般 |
| デプロイ | ローカルプロセス | 単一サーバー | 負荷分散 |
| 再接続 | プロセスの再起動 | 自動再接続 | ステートレスで高い耐障害性 |
| 複数クライアント | 1 対 1 のみ | 複数クライアント | 水平スケーリング可能 |
| ファイアウォール | 該当なし(ローカル) | HTTP に適している | HTTP に適している |
| 状態 | プロセスの存続期間 | 接続の存続期間 | セッションまたはステートレス |
| 最適な用途 | Claude Desktop/Code | 内部ツール | クラウド/エンタープライズ |
認証パターン早見表
# Pattern 1: API keys from environment
import os
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("api-server")
@mcp.tool()
def call_api(endpoint: str) -> str:
"""Call external API with configured credentials."""
api_key = os.environ["MY_API_KEY"] # Set in client config
resp = httpx.get(f"https://api.example.com/{endpoint}",
headers={"Authorization": f"Bearer {api_key}"})
return resp.text
# Pattern 2: OAuth2 token refresh (in-memory cache)
import time
_token_cache: dict = {}
async def get_valid_token() -> str:
if _token_cache.get("expires_at", 0) > time.time() + 60:
return _token_cache["access_token"]
resp = await httpx.AsyncClient().post("https://auth.example.com/token", data={
"grant_type": "refresh_token",
"refresh_token": os.environ["REFRESH_TOKEN"],
"client_id": os.environ["CLIENT_ID"],
})
data = resp.json()
_token_cache.update({
"access_token": data["access_token"],
"expires_at": time.time() + data["expires_in"],
})
return data["access_token"]
// Claude Desktop config with env vars
{
"mcpServers": {
"my-server": {
"command": "uv",
"args": ["run", "--directory", "/path/to/server", "python", "server.py"],
"env": {
"MY_API_KEY": "sk-...",
"DATABASE_URL": "postgresql://..."
}
}
}
}
よくある落とし穴
| 落とし穴 | 原因 | 対処法 |
|---|---|---|
| クライアントにツールが表示されない | inputSchema が無効な JSON Schema になっている | jsonschema ライブラリでスキーマを検証し、Pydantic/Zod を使って生成する |
| ツールが生のオブジェクトを返す | 結果は型付きの項目を含む content リストでなければならない | 常に {"content": [{"type": "text", "text": "..."}]} を返す |
| 時間のかかる処理でタイムアウトする | クライアントのデフォルトのタイムアウトは、多くの場合 30~60 秒 | 進捗通知を追加し、処理を小さな単位に分割する |
| 同時リクエストが失敗する | ツールハンドラーが共有された変更可能な状態を使っている | asyncio ロックを使うか、ハンドラーをステートレスにする |
| 大きなレスポンスでクライアントがクラッシュする | MCP メッセージには実用上のサイズ上限がある | 結果をページ分割し、詳細を取得するツールと要約を返す |
| エラーが気付かれないまま握りつぶされる | ハンドラー内の例外は汎用エラーを返す | レスポンスで isError: true を設定し、コンテンツにエラーメッセージを含める |
| SSE 接続が切れる | キープアライブまたは再接続ロジックがない | ハートビートを実装する。クライアントは SSE で自動再接続する |
| クライアントが新しいツールを認識しない | ツール変更後にケイパビリティが更新されていない | server.request_context.session.send_resource_list_changed() を呼び出す |
| ツール名が衝突する | 2 つのサーバーが同じツール名を登録している | ツールを名前空間で分ける。search だけではなく myserver_search とする |
| リソース URI が曖昧すぎる | data://info では内容が特定できない | db://myapp/users、config://myapp/settings など、具体的なスキームを使う |
ハンドラーに async def がない | FastMCP ツールは同期でも非同期でもよいが、I/O は非同期にすべき | ネットワークまたはファイル I/O を行うハンドラーには async def を使う |
| ローカルでは動くが Claude Desktop では失敗する | 作業ディレクトリまたは PATH が異なる | 絶対パスを使い、起動時に os.getcwd() をログに記録する |
参照ファイル
| ファイル | 行数 | 内容 |
|---|---|---|
references/server-architecture.md | 約700 | サーバーのライフサイクル、FastMCP/TS SDK のセットアップ、機能、ミドルウェア、エラー処理 |
references/tool-handlers.md | 約650 | スキーマ設計、検証、戻り値の型、合成、副作用、例 |
references/resources-prompts.md | 約550 | リソース URI、静的/動的リソース、テンプレート、プロンプト、サブスクリプション |
references/transport-auth.md | 約550 | stdio/SSE/HTTP トランスポート、セッション管理、OAuth2、レート制限、TLS |
references/testing-debugging.md | 約550 | MCP Inspector、単体/統合テスト、プロトコルのデバッグ、CI、パフォーマンス |
古さの検証
このスキルには、変化の速い情報(MCP SDK のパッケージ名と仕様 URL)が含まれています。scripts/check-mcp-facts.py により、気づかないうちに情報が古くなるのを防ぎます。
# Structural (PR CI, no network): every catalogued package's prose_token is
# still named in this skill's prose, the spec URL is still cited, and the
# currency note still carries a year.
python scripts/check-mcp-facts.py --offline # exit 0 consistent, 10 drift
# Live (freshness job, never blocks a PR): each SDK still resolves on
# npm/PyPI, no tracked major has moved off the sampled major, spec URL 200.
python scripts/check-mcp-facts.py --live # exit 10 drift, 7 registries unreachable
正規の情報セットは assets/mcp-facts.json にあります。パッケージを追加または削除する場合は、それに合わせて更新してください。更新しないと、--offline で CI が失敗します。
関連項目
- MCP 仕様:https://modelcontextprotocol.io/specification/latest(古い spec.modelcontextprotocol.io サブドメインは、現在解決されません)
- Python SDK:https://github.com/modelcontextprotocol/python-sdk
- TypeScript SDK:https://github.com/modelcontextprotocol/typescript-sdk
- 公式 MCP サーバー:https://github.com/modelcontextprotocol/servers
- MCP Inspector:
npx @modelcontextprotocol/inspector - FastMCP ドキュメント:https://gofastmcp.com
- 関連スキル:
claude-code-hooks(Claude Code にフックします)、claude-code-debug(Claude Code の問題をデバッグします)