mcp-development について
MCP 開発者向けの実践ガイドです。ツール、リソース、プロンプトテンプレートを備えたサーバーの構築、トランスポート設定、入力検証、エラー処理を扱い、クライアント設定とチェック項目も含みます。
主な機能
- 01ツールを備えた MCP サーバーの構築
- 02リソースとプロンプトテンプレートの定義
- 03Stdio と SSE のトランスポート設定
- 04Zod による入力検証
- 05エラー処理と安全な終了
- 06クライアント設定の記述
活用シーン
- 01クライアントが呼び出すツールの実装
- 02クライアントへの読み取り専用リソースの提供
- 03一般的なタスク向けプロンプトテンプレートの設計
- 04MCP サーバーの実装と設定の確認
MCP 対応
MCP サーバー開発を中心に、クライアント設定も扱います。Stdio または SSE を通じて、ツール、リソース、プロンプトを MCP クライアントに公開する方法を説明します。
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ rohitg00/ awesome-claude-code-toolkit --skill mcp-developmentインストール後、Claude Code で/mcp-developmentを入力して読み込まれたか確認します。
詳細
MCP の開発
ツールを備えた MCP サーバー
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: "project-tools",
version: "1.0.0",
});
server.tool(
"search_files",
"Search for files matching a glob pattern in the project directory",
{
pattern: z.string().describe("Glob pattern (e.g., '**/*.ts')"),
directory: z.string().optional().describe("Base directory to search from"),
},
async ({ pattern, directory }) => {
const files = await glob(pattern, { cwd: directory ?? process.cwd() });
return {
content: [
{
type: "text",
text: files.length > 0
? files.join("\n")
: `No files found matching ${pattern}`,
},
],
};
}
);
server.tool(
"run_query",
"Execute a read-only SQL query against the application database",
{
query: z.string().describe("SQL SELECT query to execute"),
limit: z.number().default(100).describe("Maximum rows to return"),
},
async ({ query, limit }) => {
if (!query.trim().toUpperCase().startsWith("SELECT")) {
return {
content: [{ type: "text", text: "Only SELECT queries are allowed" }],
isError: true,
};
}
const rows = await db.query(`${query} LIMIT ${limit}`);
return {
content: [{ type: "text", text: JSON.stringify(rows, null, 2) }],
};
}
);
リソース
server.resource(
"schema",
"db://schema",
"Current database schema with all tables, columns, and relationships",
async () => {
const schema = await db.query(`
SELECT table_name, column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position
`);
return {
contents: [
{
uri: "db://schema",
mimeType: "application/json",
text: JSON.stringify(schema, null, 2),
},
],
};
}
);
server.resource(
"config",
"config://app",
"Application configuration (secrets redacted)",
async () => {
const config = await loadConfig();
const safe = redactSecrets(config);
return {
contents: [
{
uri: "config://app",
mimeType: "application/json",
text: JSON.stringify(safe, null, 2),
},
],
};
}
);
プロンプトテンプレート
server.prompt(
"review-code",
"Review code changes for bugs, security issues, and style",
{
diff: z.string().describe("Git diff or code to review"),
focus: z.enum(["security", "performance", "style", "all"]).default("all"),
},
async ({ diff, focus }) => ({
messages: [
{
role: "user",
content: {
type: "text",
text: `Review this code diff. Focus: ${focus}\n\n${diff}`,
},
},
],
})
);
クライアントの設定
{
"mcpServers": {
"project-tools": {
"command": "node",
"args": ["./mcp-server/dist/index.js"],
"env": {
"DATABASE_URL": "postgres://localhost:5432/app"
}
},
"remote-server": {
"url": "https://mcp.example.com/sse",
"headers": {
"Authorization": "Bearer ${MCP_TOKEN}"
}
}
}
}
トランスポートの設定
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const transport = new StdioServerTransport();
await server.connect(transport);
HTTP ベースのサーバーでは、クライアントにストリーミングレスポンスを送信するために SSE トランスポートを使用します。
アンチパターン
- 使用するタイミングを説明していない、曖昧な説明のツールを作成する
- 処理前に Zod スキーマで入力を検証しない
- エラーの生のスタックトレースをクライアントに返す
- エラーレスポンスに
isError: trueフラグがない - 組み合わせて使えるツールではなく、細かすぎるツールを作りすぎる
- リソースのレスポンスでシークレットをマスキングしない
チェックリスト
- 各ツールに、使用するタイミングと理由を説明する明確な説明がある
- 入力パラメーターが Zod スキーマとわかりやすいメッセージで検証されている
- エラーレスポンスに
isError: trueとユーザーにわかりやすいメッセージが含まれている - リソースがシークレットをマスキングした読み取り専用データを公開している
- プロンプトテンプレートが一般的なタスク向けに、構造化された出発点を提供している
- サーバーが SIGINT/SIGTERM で正常にシャットダウンする
- ツールがモノリシックではなく、組み合わせて使える(1つの機能を適切に実行する)
- 必要な環境変数を含めて、クライアントの設定が文書化されている
コメント
Markdown 対応