SuperAPI AI Directory

mcp-builder

Coding & development

View repository

Updated 10-15 08:55

About this skill

MCP Server Construction

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

1. Core Protocol Concepts

MCP defines three primitives:

  • Tools: functions actively invoked by AI assistants, with side effects. Such as search, create, and delete operations.
  • Resources: read-only data sources for AI assistants, 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; AI assistants select tools by name, and vague naming leads to incorrect invocation

Parameters

  • Each parameter has a type constraint and .describe() description
  • Optional parameters should have default values to reduce the AI's decision 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, which 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 content: [{ type: "text", text: "..." }] format for returns

4. Input Validation and Error Handling

Use Zod/Pydantic for schema-level validation, and place 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 can be done
  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 pools, 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 inspect the results.

Testing key points: Each Tool should cover 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 masked

Sandbox: Restrict file operation directories, whitelist network requests, and 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 Techniques

Key: MCP uses stdio for communication and cannot use console.log, as 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 the Tool unclear description improve the name and description
parameters always wrong Schema unclear Add .describe()
call timeout external service slow add timeout and caching

Debugging workflow: 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 among Tools vs Resources vs Prompts
  • Tool naming 动词_名词, with descriptions explaining purpose and return content
  • Concise parameters, with reasonable default values for optional parameters

Implementation

  • Validate input with Zod/Pydantic
  • External calls have try/catch and timeouts
  • 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 a client configuration JSON example
  • Follow semver, no hard-coded secrets