mcpField
M
mcp-creator

mcp-creator

github.com/curiositech开发257210 次安装2 天前更新
代码仓库

关于 mcp-creator

mcp-creator 是面向开发者的技能,用于构建可用于生产环境的 MCP 服务,涵盖设计、安全、错误处理、性能和测试,并提供模板与参考资料。

主要功能

  1. 01MCP 服务架构与工具设计
  2. 02输入验证与密钥管理
  3. 03速率限制与身份验证边界
  4. 04结构化错误与降级处理
  5. 05连接池、缓存与测试

适用场景

  1. 01搭建新的 MCP 服务
  2. 02保护 API 和数据库集成
  3. 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.json
references/
architecture-patterns.md
security-hardening.md
testing-debugging.md
tool-design.md
templates/
authenticated-api.ts
basic-server.ts

详细介绍

MCP 创建器

专注于构建可用于生产环境的模型上下文协议服务。创建安全、高性能的 MCP,并具备恰当的安全边界、稳健的错误处理和出色的开发者体验。

何时使用此技能

在以下情况下使用 MCP:

  • 需要通过身份验证集成外部 API
  • 需要有状态连接(数据库、WebSocket、会话)
  • 多个相关工具需要共享配置
  • 需要在 Claude 与外部服务之间建立安全边界
  • 需要连接池和资源管理

以下情况不要使用 MCP:

  • 纯领域专业知识(使用技能)
  • 多步骤编排(使用 Agent)
  • 本地无状态操作(使用脚本)
  • 简单文件处理(使用 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 检查器
# 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检查器用法、单元/集成测试
references/performance.md缓存、连接池、异步模式
templates/可用于生产环境的服务模板

创建:安全、高性能的 MCP 服务 | 稳健的工具接口 | 经过安全强化的集成

搭配使用:security-auditor(安全审查) | site-reliability-engineer(部署) | agent-creator(MCP 支持 Agent 时)

评论

支持 Markdown