入门篇讲了 MCP 是什么。这篇拆协议本身——适合要 写 MCP Server评估 MCP 是否适合你的架构 的工程师。

协议栈

应用层    Tools / Resources / Prompts(MCP 语义)
          ─────────────────────────────
传输层    stdio(本地) | SSE(远程 HTTP)
          ─────────────────────────────
消息层    JSON-RPC 2.0

MCP 基于 JSON-RPC 2.0。Host 和 Server 之间通过请求/响应消息通信,没有 RESTful URL 的概念。

生命周期

Host                          Server
  │── initialize ──────────────→│
  │←─ capabilities ────────────│  (Server 声明支持 Tools/Resources/Prompts)
  │── initialized ─────────────→│
  │                              │
  │── tools/list ───────────────→│  (Host 发现可用工具)
  │←─ [tool definitions] ──────│
  │                              │
  │── tools/call ──────────────→│  (Host 让 Server 执行工具)
  │←─ result / error ──────────│

关键点:Server 是被动的——它不主动推消息,只响应 Host 的请求。Host(Cursor、Claude Desktop)控制整个交互节奏。

Tools 定义规范

Server 通过 tools/list 返回工具清单,每个工具包含:

{
  "name": "query_database",
  "description": "Execute a read-only SQL query against the production database",
  "inputSchema": {
    "type": "object",
    "properties": {
      "sql": { "type": "string", "description": "SQL query to execute" }
    },
    "required": ["sql"]
  }
}

description 字段至关重要——LLM 靠它决定什么时候调用、传什么参数。写 MCP Server 时,description 的质量直接决定 Agent 的调用准确率。

传输层选择

传输场景特点
stdio本地 Server,Claude Desktop / CursorServer 作为子进程启动,stdin/stdout 通信
SSE远程 Server,Web 部署HTTP Server-Sent Events,支持多客户端

本地开发几乎都用 stdio。生产环境如果多个 Host 共享一个 Server,用 SSE + 鉴权。

最小 MCP Server(TypeScript)

使用官方 SDK @modelcontextprotocol/sdk

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: "my-server", version: "1.0.0" });

server.tool(
  "get_weather",
  "Get current weather for a city",
  { city: z.string().describe("City name, e.g. Beijing") },
  async ({ city }) => {
    // 实际项目中调天气 API
    const data = { city, temp: "25°C", condition: "晴" };
    return { content: [{ type: "text", text: JSON.stringify(data) }] };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);

Host 配置:

{
  "mcpServers": {
    "weather": {
      "command": "node",
      "args": ["./dist/server.js"]
    }
  }
}

Resources vs Tools:什么时候用哪个

ToolsResources
语义「帮我做一件事」「给我一些数据」
副作用可以有(写文件、发消息)应该只读
LLM 怎么用Function calling 主动调用按需读取,类似 RAG
例子创建 PR、执行 SQL读取文件、获取 schema

工程经验:读操作用 Resources,写操作用 Tools。混在一起会导致 Agent 误调用。

生产部署注意事项

  1. 权限最小化:MCP Server 只暴露必要的 Tools,database server 用 read-only 连接
  2. 输入校验inputSchema 只是给 LLM 看的,Server 内部必须再校验
  3. 超时和重试:Tool 调用可能很慢,Host 侧要有 timeout
  4. 日志和审计:谁通过 MCP 做了什么操作,生产环境必须可追溯
  5. 版本管理:Tool schema 变更时要考虑向后兼容

生态现状(2026)

  • 官方维护的 Server 仓库:modelcontextprotocol/servers(GitHub、Postgres、Filesystem 等)
  • 社区 Server 数量快速增长,质量参差不齐
  • Cursor、Claude Desktop、Windsurf、Zed 均已支持
  • OpenAI 尚未原生支持 MCP,但通过第三方桥接可用

小结

MCP 的 engineering 核心:JSON-RPC 消息 + 清晰的 Tool/Resource 定义 + 合适的传输层。写 Server 时把 description 写好、权限控好,比追求功能数量重要得多。