SuperAPI AI Directory

mcp-builder

Agents & models

View repository

Updated 10-16 09:27

About this skill

MCP Server Construction

A methodology for systematically designing, implementing, testing, and deploying Model Context Protocol servers.

1. Protocol Core Concepts

MCP defines three primitives:

  • Tools: functions actively called by the AI assistant, with side effects. Such as search, create, and delete operations.
  • Resources: read-only data sources accessed by the AI assistant, identified by URI. Such as users://{id}/profile。
  • Prompts: predefined interaction templates that guide users to trigger workflows.

Selection principles: Perform operations → Tool | Read data → Resource | Guide interaction → Prompt

2. Project Structure Standards

TypeScript

my-mcp-server/
├── src/
│   ├── index.ts          # 入口,注册 tools/resources
│   ├── tools/             # 按功能拆分
│   ├── resources/
│   └── lib/               # 客户端封装、校验逻辑
├── tests/
├── package.json
└── tsconfig.json

Key dependencies:@modelcontextprotocol/sdk + zod

Python

my-mcp-server/
├── src/my_mcp_server/
│   ├── server.py
│   ├── tools/
│   └── lib/
├── tests/
└── pyproject.toml

Key dependencies:mcp + pydantic

3. Tool Design Principles

Naming

  • snake_case format, starting with a verb:search_users、create_issue、delete_file
  • Names should be self-explanatory; the AI assistant selects tools by name, and ambiguous naming leads to incorrect calls

Parameters

  • Each parameter has a type constraint and a .describe() description
  • Optional parameters should have default values to reduce the AI's decision-making burden
  • Use enums instead of boolean switches
server.tool("search_issues", {
  query: z.string().describe("搜索关键词"),
  status: z.enum(["open", "closed", "all"]).default("open").describe("状态筛选"),
  limit: z.number().min(1).max(100).default(20).describe("返回上限"),
}, async ({ query, status, limit }) => { /* ... */ });

Description

Explainpurpose + return content + limitations, this is the key basis for the AI to select tools:

server.tool("search_users",
  "根据姓名或邮箱搜索用户。返回 ID、姓名、邮箱列表。模糊匹配,最多 50 条。",
  schema, handler);

Output

  • Structured data → JSON, human-readable content → Markdown
  • Always use the content: [{ type: "text", text: "..." }] format to return

4. Input Validation and Error Handling

Use Zod/Pydantic for schema-level validation, and put business-level validation at the beginning of the handler:

server.tool("get_user", { id: z.string() }, async ({ id }) => {
  try {
    const user = await db.getUser(id);
    if (!user) {
      return {
        content: [{ type: "text", text: `用户 ${id} 不存在,请检查 ID。` }],
        isError: true,
      };
    }
    return { content: [{ type: "text", text: JSON.stringify(user, null, 2) }] };
  } catch (err) {
    return {
      content: [{ type: "text", text: `查询失败:${err.message}` }],
      isError: true,
    };
  }
});

Four principles of error handling:

  1. Never let the server crash — wrap all external calls in try/catch
  2. Return actionable error information — tell the AI what the problem is and what it can do
  3. Use isError: true — let the AI know the call failed
  4. Distinguish error types — parameter errors, insufficient permissions, resource not found, service unavailable

5. Resource Management and Lifecycle

// 资源注册
server.resource("user-profile", "users://{userId}/profile", async (uri) => {
  const profile = await db.getProfile(extractId(uri));
  return { contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(profile) }] };
});

// 生命周期:先初始化 → 再 connect → 监听关闭信号
const db = await Database.connect(config.dbUrl);
await server.connect(new StdioServerTransport());
process.on("SIGINT", async () => { await db.disconnect(); await server.close(); process.exit(0); });

Key points: use connection pooling, set timeouts for all external calls, and gracefully shut down to clean up resources.

6. Testing Strategy

Unit testing — separate business logic from MCP registration

// tools/search.ts 导出纯函数
export async function searchUsers(query: string, limit: number) { /* ... */ }

// search.test.ts 独立测试
test("返回匹配结果", async () => {
  const results = await searchUsers("alice", 10);
  expect(results[0].name).toContain("Alice");
});

Integration testing — use the SDK Client for end-to-end verification

const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await server.connect(serverTransport);
const client = new Client({ name: "test", version: "1.0.0" });
await client.connect(clientTransport);
const result = await client.callTool("search_users", { query: "test" });
expect(result.isError).toBeFalsy();

MCP Inspector — interactive debugging

npx @modelcontextprotocol/inspector node dist/index.js

View all tools/resources in the browser, call them manually, and view the results.

Testing key points: Each Tool covers normal + exception paths, boundary values, and external service failure simulation.

7. Security Considerations

Permission control:

  • Principle of least privilege, separate read and write Tools
  • Dangerous operations require confirmation parameters (such as confirm: true)

Input security:

  • SQL injection → parameterized queries, never concatenate
  • Path traversal → validate paths, prohibit ../
  • Command injection → use execFile instead of exec

Sensitive data:

  • Secrets are passed in through environment variables, not hardcoded
  • Logs do not print complete sensitive information
  • Returned data is desensitized

Sandbox: File operation restricted directories, network request whitelist, set resource quotas.

8. Deployment and Distribution

npm publishing

{ "bin": { "mcp-server-myservice": "dist/index.js" }, "files": ["dist"] }

User configuration:

{ "mcpServers": { "myservice": { "command": "npx", "args": ["@yourorg/mcp-server-myservice"], "env": { "API_KEY": "xxx" } } } }

pip publishing

[project.scripts]
mcp-server-myservice = "my_mcp_server.server:main"

Docker — suitable for complex dependencies or isolation scenarios

FROM node:20-slim
WORKDIR /app
COPY package*.json ./ && RUN npm ci --production
COPY dist ./dist
ENTRYPOINT ["node", "dist/index.js"]

9. Debugging Tips

Key: MCP uses stdio communication, cannot use console.log, it will break the protocol stream.

// 错误
console.log("debug");
// 正确
console.error("[DEBUG]", info);
// 更好
server.sendLoggingMessage({ level: "info", data: "处理中" });

Common issues:

Symptom Cause Solution
No response on startup transport not connected Check server.connect()
Tool does not appear Registered after connect Register first, then connect
AI does not call Tool Description unclear Improve name and description
Parameters always wrong Schema unclear Add .describe()
Call timeout External service slow Add timeout and caching

Debugging process: Inspector verifies basic functionality → manually call to confirm input and output → connect to a real AI client to observe call patterns → adjust the design based on actual behavior.

10. Build Checklist

Design

  • Clarify the division of labor between Tools vs Resources vs Prompts
  • Tool naming 动词_名词, description explains purpose and return content
  • Parameters concise, optional parameters have reasonable defaults

Implementation

  • Input validated with Zod/Pydantic
  • External calls have try/catch and timeout
  • Error returns isError: true with actionable information
  • Do not use console.log(use stderr or SDK logging)
  • Sensitive data goes through environment variables

Testing

  • Core logic has unit tests
  • Integration tests verify MCP protocol interaction
  • Manually verified with MCP Inspector
  • Tested with a real AI client

Deployment

  • README includes installation and configuration instructions
  • Provide client configuration JSON example
  • Follow semver, no hardcoded secrets