mcp-creator について
mcp-creatorは、本番環境向けMCPサーバーの構築を支援する開発者向けスキルです。設計、セキュリティ、エラー処理、性能、テストを扱い、テンプレートとリファレンスも提供します。
主な機能
- 01MCPサーバーの構成とツール設計
- 02入力検証とシークレット管理
- 03レート制限と認証境界
- 04構造化エラーと縮退処理
- 05接続プール、キャッシュ、テスト
活用シーン
- 01新しいMCPサーバーの作成
- 02APIやデータベース連携の保護
- 03サーバーエラーやテスト失敗の調査
MCP 対応
ツール、リソース、プロンプトの設計を含め、MCPサーバーの作成とテストを案内します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ curiositech/ some_claude_skills --skill mcp-creatorインストール後、Claude Code で/mcp-creatorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
CHANGELOG.md.claude-plugin/plugin.jsonreferences/architecture-patterns.mdsecurity-hardening.mdtesting-debugging.mdtool-design.mdtemplates/authenticated-api.tsbasic-server.ts詳細
MCP Creator
本番環境に対応した Model Context Protocol サーバーの構築に精通しています。適切なセキュリティ境界、堅牢なエラー処理、優れた開発者エクスペリエンスを備えた、安全で高性能な MCP を作成します。
このスキルを使用するタイミング
次のような場合に MCP を使用します:
- 認証を伴う外部 API 統合
- ステートフルな接続(データベース、WebSocket、セッション)
- 設定を共有する複数の関連ツール
- Claude と外部サービス間のセキュリティ境界
- コネクションプーリングとリソース管理
次の用途には MCP を使用しないでください:
- 純粋なドメイン知識(Skill を使用)
- 複数ステップのオーケストレーション(Agent を使用)
- ローカルでステートレスな処理(Script を使用)
- 単純なファイル処理(Claude の組み込みツールを使用)
クイックスタート
# Scaffold new MCP server
npx @modelcontextprotocol/create-server my-mcp-server
# Install SDK
npm install @modelcontextprotocol/sdk
# Test with inspector
npx @modelcontextprotocol/inspector
MCP アーキテクチャの概要
┌─────────────────────────────────────────────────────────────┐
│ Claude │
└─────────────────────────┬───────────────────────────────────┘
│ MCP Protocol (JSON-RPC)
┌─────────────────────────┴───────────────────────────────────┐
│ MCP Server │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Tools │ │ Resources │ │ Prompts │ │
│ │ (actions) │ │ (read-only) │ │ (templates) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ │ │
│ ┌───────────────────────┴──────────────────────────────┐ │
│ │ Auth / Rate Limiting / Caching │ │
│ └───────────────────────┬──────────────────────────────┘ │
└──────────────────────────┼──────────────────────────────────┘
│
┌──────────────────────────┴──────────────────────────────────┐
│ External Services │
│ APIs │ Databases │ File Systems │ WebSockets │
└─────────────────────────────────────────────────────────────┘
MCP サーバーの基本テンプレート
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ErrorCode,
McpError,
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{ name: "my-mcp-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// Tool definitions
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "my_tool",
description: "Clear description of what this tool does",
inputSchema: {
type: "object",
properties: {
input: { type: "string", description: "Input description" },
},
required: ["input"],
},
},
],
}));
// Tool implementation
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "my_tool") {
try {
const result = await processInput(args.input);
return { content: [{ type: "text", text: JSON.stringify(result) }] };
} catch (error) {
throw new McpError(ErrorCode.InternalError, error.message);
}
}
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
ツール設計の原則
1. 分かりやすい名前
// ✅ Good: Action-oriented, specific
"get_user_profile"
"create_issue"
"analyze_sentiment"
// ❌ Bad: Vague, generic
"process"
"do_thing"
"handle"
2. 正確な入力スキーマ
// ✅ Good: Typed, constrained, documented
{
type: "object",
properties: {
userId: { type: "string", pattern: "^[a-f0-9]{24}$" },
action: { type: "string", enum: ["read", "write", "delete"] },
limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }
},
required: ["userId", "action"],
additionalProperties: false
}
// ❌ Bad: Untyped, unconstrained
{ type: "object" }
3. 構造化された出力
// ✅ Good: Consistent structure
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
data: result,
metadata: { requestId, timestamp }
}, null, 2)
}]
};
// ❌ Bad: Inconsistent, unstructured
return { content: [{ type: "text", text: "done" }] };
セキュリティの強化(重大)
入力の検証
import { z } from "zod";
const UserInputSchema = z.object({
userId: z.string().regex(/^[a-f0-9]{24}$/),
email: z.string().email(),
query: z.string().max(1000).refine(
(q) => !q.includes("--") && !q.includes(";"),
{ message: "Invalid characters in query" }
),
});
async function handleTool(args: unknown) {
const validated = UserInputSchema.parse(args); // Throws on invalid
// Safe to use validated data
}
シークレットの管理
// ✅ Good: Environment variables
const API_KEY = process.env.SERVICE_API_KEY;
if (!API_KEY) throw new Error("SERVICE_API_KEY required");
// ✅ Good: Secret manager integration
const secret = await secretManager.getSecret("service-api-key");
// ❌ NEVER: Hardcoded secrets
const API_KEY = "sk-abc123..."; // SECURITY VULNERABILITY
レート制限
class RateLimiter {
private requests: Map<string, number[]> = new Map();
canProceed(key: string, limit: number, windowMs: number): boolean {
const now = Date.now();
const timestamps = this.requests.get(key) || [];
const recent = timestamps.filter(t => now - t < windowMs);
if (recent.length >= limit) return false;
recent.push(now);
this.requests.set(key, recent);
return true;
}
}
const limiter = new RateLimiter();
// In tool handler
if (!limiter.canProceed(userId, 100, 60000)) {
throw new McpError(ErrorCode.InvalidRequest, "Rate limit exceeded");
}
認証境界
// Validate credentials before any operation
async function withAuth<T>(
credentials: Credentials,
operation: () => Promise<T>
): Promise<T> {
if (!await validateCredentials(credentials)) {
throw new McpError(ErrorCode.InvalidRequest, "Invalid credentials");
}
return operation();
}
エラー処理のパターン
構造化されたエラーレスポンス
// Define error types
enum ServiceError {
NOT_FOUND = "NOT_FOUND",
UNAUTHORIZED = "UNAUTHORIZED",
RATE_LIMITED = "RATE_LIMITED",
VALIDATION_ERROR = "VALIDATION_ERROR",
EXTERNAL_SERVICE_ERROR = "EXTERNAL_SERVICE_ERROR",
}
// Map to MCP errors
function toMcpError(error: unknown): McpError {
if (error instanceof z.ZodError) {
return new McpError(
ErrorCode.InvalidParams,
`Validation error: ${error.errors.map(e => e.message).join(", ")}`
);
}
if (error instanceof ServiceError) {
return new McpError(ErrorCode.InternalError, error.message);
}
return new McpError(ErrorCode.InternalError, "Unknown error occurred");
}
グレースフルデグラデーション
async function fetchWithFallback<T>(
primary: () => Promise<T>,
fallback: () => Promise<T>,
options: { retries?: number; timeout?: number } = {}
): Promise<T> {
const { retries = 3, timeout = 5000 } = options;
for (let i = 0; i < retries; i++) {
try {
return await Promise.race([
primary(),
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), timeout)
),
]);
} catch (error) {
if (i === retries - 1) {
console.error("Primary failed, trying fallback:", error);
return fallback();
}
await new Promise(r => setTimeout(r, 1000 * (i + 1))); // Backoff
}
}
throw new Error("All retries exhausted");
}
パフォーマンスの最適化
コネクションプーリング
// PostgreSQL pool
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
// Reuse connections
async function query(sql: string, params: unknown[]) {
const client = await pool.connect();
try {
return await client.query(sql, params);
} finally {
client.release();
}
}
キャッシュレイヤー
class Cache<T> {
private store: Map<string, { value: T; expires: number }> = new Map();
get(key: string): T | undefined {
const entry = this.store.get(key);
if (!entry) return undefined;
if (Date.now() > entry.expires) {
this.store.delete(key);
return undefined;
}
return entry.value;
}
set(key: string, value: T, ttlMs: number): void {
this.store.set(key, { value, expires: Date.now() + ttlMs });
}
}
const cache = new Cache<ApiResponse>();
async function fetchWithCache(url: string): Promise<ApiResponse> {
const cached = cache.get(url);
if (cached) return cached;
const response = await fetch(url);
const data = await response.json();
cache.set(url, data, 300000); // 5 min TTL
return data;
}
アンチパターン
アンチパターン:入力を検証しない
例:ユーザー入力を API やデータベースに直接渡す 問題点:SQL インジェクション、コマンドインジェクション、データ破損 代わりに:Zod で検証し、入力をサニタイズし、パラメーター化クエリを使用します
アンチパターン:コード内のシークレット
例:API キーやトークンをソースコードにハードコードする 問題点:シークレットが git、ログ、エラーメッセージを通じて漏えいします 代わりに:環境変数、シークレットマネージャー、暗号化された設定を使用します
アンチパターン:レート制限がない
例:外部サービスへの API 呼び出しが無制限 問題点:コストの急増、API の利用停止、リソースの枯渇 代わりに:トークンバケット、スライディングウィンドウ、または適応型レート制限を使用します
アンチパターン:同期的なブロッキング
例:非同期ハンドラー内での sleep() やブロッキング I/O
問題点:すべてのリクエストをブロックし、タイムアウトを引き起こします
代わりに:適切な async/await とノンブロッキングパターンを使用します
アンチパターン:失敗を黙殺する
例:空の catch ブロック、エラーの握りつぶし 問題点:デバッグが不可能になり、データ破損を検知できません 代わりに:構造化されたエラー処理、ロギング、適切なエラー伝播を行います
アンチパターン:タイムアウトがない
例:外部サービスからの応答を無期限に待機する 問題点:接続がハングし、リソースがリークします 代わりに:すべての外部呼び出しに明示的なタイムアウトとサーキットブレーカーを設定します
MCP のテスト
MCP Inspector の使用
# Start inspector
npx @modelcontextprotocol/inspector
# In another terminal, start your server
node dist/index.js
# Connect inspector to your server
# Test tool invocations manually
単体テスト
import { describe, it, expect } from "vitest";
describe("my_tool", () => {
it("should validate input", async () => {
await expect(
handleTool({ userId: "invalid" })
).rejects.toThrow("Invalid userId format");
});
it("should return structured output", async () => {
const result = await handleTool({ userId: "507f1f77bcf86cd799439011" });
expect(result).toHaveProperty("success", true);
expect(result).toHaveProperty("data");
});
});
MCP に追加するタイミング:判断フロー
Does this tool need...
├── External API with auth? → Add to MCP
├── Persistent state/connection? → Add to MCP
├── Rate limiting for external service? → Add to MCP
├── Shared credentials with other tools? → Add to MCP
├── Security boundary from Claude? → Add to MCP
└── None of the above? → Consider Script instead
成功指標
| 指標 | 目標 |
|---|---|
| ツールのレイテンシー P95 | < 500ms |
| エラー率 | < 1% |
| 入力検証のカバレッジ | 100% |
| シークレットの露出 | 0 |
| レート制限違反 | 0 |
参考ファイル
| ファイル | 内容 |
|---|---|
references/architecture-patterns.md | トランスポート層、サーバーのライフサイクル、リソース管理 |
references/tool-design.md | スキーマのパターン、命名規則、出力形式 |
references/security-hardening.md | OWASP に準拠したセキュリティチェックリストの全容 |
references/error-handling.md | エラーの種類、復旧戦略、ロギング |
references/testing-debugging.md | Inspector の使用方法、単体テスト/統合テスト |
references/performance.md | キャッシュ、プーリング、非同期パターン |
templates/ | 本番環境に対応したサーバーテンプレート |
作成するもの:安全で高性能な MCP サーバー | 堅牢なツールインターフェース | セキュリティを強化した統合
併用するツール:security-auditor(セキュリティレビュー) | site-reliability-engineer(デプロイ) | agent-creator(MCP がエージェントをサポートする場合)