Skip to content

新版 MCP Server 开发指南 — 5 分钟从零接入 Claude Desktop

基于 2026-07-28 版 MCP 规范和官方 v2 TypeScript SDK,从零手写一个 stdio 传输的 MCP Server 并接入 Claude Desktop。覆盖新规范核心字段、ESM 环境配置、stdio 传输机制、日志污染避坑与 Claude Desktop 整合验证。适合想动手写第一个 MCP Server 的开发者。

目录


一、新版 MCP 规范的核心差异

核心概念

2026-07-28 版 MCP 规范(specification)是 MCP 协议的一次重大升级:去除了会话状态(stateless),引入了 _meta 元数据字段和 resultType 完成状态标记。

新旧规范对比

特性 旧版规范(2025-03-26 等) 新版规范(2026-07-28)
会话管理 有 stateful session(initialize 握手) Stateless,无握手,每请求独立
元数据 无强制要求 _meta 字段 MUST 包含在每请求中
结果状态 无显式完成标记 resultType: "complete" 或 "input_required"
工具列表 直接返回 tools 数组 resultType + tools + ttlMs + cacheScope
SDK 包名 @modelcontextprotocol/sdk(v1) @modelcontextprotocol/server + @modelcontextprotocol/client(v2)

_meta 字段结构

每个 MCP 请求 MUST 包含以下 _meta 字段:

{
  "_meta": {
    "io.modelcontextprotocol/protocolVersion": "2026-07-28",
    "io.modelcontextprotocol/clientInfo": {
      "name": "my-client",
      "version": "1.0.0"
    },
    "io.modelcontextprotocol/clientCapabilities": {}
  }
}

resultType 字段

响应中的 resultType 标记输出的完成状态:

值 含义 后续动作
"complete" 工具执行完成,结果已返回 直接处理结果
"input_required" 需要额外输入才能完成 客户端收集输入后重试(带 inputResponses)

兼容性注意

沿用旧版规范代码不会立即报错,但缺少 _meta 和 resultType 会导致: - 工具状态追踪失效 - 多轮交互(input_required)无法触发 - 高级客户端功能(缓存、认证)不兼容


二、环境与依赖初始化避坑

Node.js 版本要求

@modelcontextprotocol/server(v2.0.0)的 engines 声明为 {"node": ">=20"}。

# 检查 Node 版本
node --version   # 需要 v20+,推荐 v24(视频实测用 Node 24)

ESM 模块类型

package.json 必须声明 "type": "module":

{
  "name": "my-mcp-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

❌ 常见错误:不加 "type": "module" 直接用 import 语法 → Node 原生环境报 SyntaxError: Cannot use import statement outside a module

⚠️ 无效解法:改 Webpack/Babel 配置——MCP Server 是 Node 原生运行,不经过打包器

依赖安装

npm init -y
npm install @modelcontextprotocol/server

⚠️ 包名注意:

SDK 版本 包名 状态 周下载量
v1(legacy) @modelcontextprotocol/sdk 仍维护(1.30.0),6 个月后弃用 ~52M
v2(stable) @modelcontextprotocol/server + @modelcontextprotocol/client 当前 stable,对应 2026-07-28 spec ~4.9M

视频说"旧包即将淘汰"方向正确但时间线模糊——v1 当前仍在活跃维护,但 v2 是新的 stable release line。新项目建议直接用 v2。

TypeScript ≥6.0 的额外配置

npm 页面特别提示:TypeScript ≥6.0 不再自动包含 @types/*,需要在 tsconfig.json 中显式声明:

{
  "compilerOptions": {
    "types": ["node"]
  }
}

三、Server 实作与传输架构

传输机制:stdio vs HTTP

┌─────────────┐    stdin/stdout     ┌──────────────┐
│  Claude      │ ◄────────────────► │  MCP Server   │
│  Desktop     │    (JSON-RPC)      │  (Node.js)    │
└─────────────┘                     └──────────────┘

stdio 模式:
- 不开启网络端口
- 通过标准输入/输出双向通信
- 适合本地开发工具

HTTP 模式(Streamable HTTP):
- 开启网络端口
- 适合远程部署
- 需处理认证(OAuth)

选择决策树:

选 stdio 如果你:
  ✅ 本地开发工具
  ✅ 与桌面应用(Claude Desktop)集成
  ✅ 不需要网络暴露

选 HTTP 如果你:
  ✅ 远程部署
  ✅ 多客户端共享
  ✅ 需要认证/授权

Server 最小实现(v2 SDK)

// index.ts
import { McpServer } from "@modelcontextprotocol/server";
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";

const server = new McpServer({
  name: "my-tool-server",
  version: "1.0.0",
  capabilities: {
    tools: {},
  },
});

// 注册工具
server.registerTool("get_weather", {
  description: "获取指定城市的当前天气信息",
  inputSchema: {
    type: "object",
    properties: {
      location: {
        type: "string",
        description: "城市名称或邮编",
      },
    },
    required: ["location"],
  },
  handler: async ({ location }) => {
    // 实际业务逻辑
    return {
      content: [{ type: "text", text: `当前天气:${location} 晴,25°C` }],
    };
  },
});

// 启动 stdio 传输
const transport = new StdioServerTransport();
await server.connect(transport);

工具注册的三层结构

registerTool(工具名, {
  description:    ← 给 LLM 看的工具描述(决定模型是否调用)
  inputSchema:    ← JSON Schema 定义参数(LLM 生成参数值的依据)
  handler:        ← 实际执行逻辑(收到调用后运行)
})

description 的核心作用

工具的 description 不是开发者注释,而是 LLM 判断上下文的依据:

┌──────────────────────────────────────────────────┐
│  用户: "帮我查一下纽约的天气"                        │
│                                                   │
│  LLM 扫描所有已注册工具的 description:               │
│    "获取指定城市的当前天气信息"  ← 匹配!            │
│    "发送电子邮件"                         ← 不匹配  │
│    "查询数据库"                         ← 不匹配    │
│                                                   │
│  结论: 调用 get_weather(location="纽约")            │
└──────────────────────────────────────────────────┘

验证方法(视频实测):清空 description 后,相同用户输入 → Claude 只生成文本回复,完全不触发工具调用。


四、TS 编译配置与 stdio 协议除错

日志污染(Protocol Poisoning)

stdio 模式下,stdout 是 JSON-RPC 通信通道:

正常流程:
  Server → stdout → JSON-RPC 封包 → Client 解析 ✅

日志污染:
  Server → stdout → "DEBUG: 开始执行" + JSON-RPC 封包 → Client 解析 ❌ 崩溃

规则:

场景 正确做法 错误做法
调试日志 console.error(...) → stderr console.log(...) → stdout
错误信息 console.error(...) → stderr console.log(...) → stdout
协议消息 SDK 内部处理 → stdout 手动拼接 → stdout

✅ 正确:

console.error("DEBUG: 工具被调用", { location });  // 走 stderr,不影响协议

❌ 错误:

console.log("DEBUG: 工具被调用", { location });    // 走 stdout,污染 JSON-RPC

tsconfig 配置

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "types": ["node"]
  },
  "include": ["src"]
}

❌ 错误配置:module: "CommonJS" → 编译后执行报 exports is not defined(ESM 项目不能用 CommonJS 输出)

module 选择:

值 适用场景
Node16 Node.js 16+,ESM 项目(推荐)
NodeNext Node.js 16+,自动检测 ESM/CJS(推荐)
ES2020 仅配合 bundler(Webpack/Vite)
CommonJS 旧式 CJS 项目(MCP Server 不适用)

五、Claude Desktop 整合验证

配置文件

编辑 claude_desktop_config.json(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "my-tool-server": {
      "command": "node",
      "args": ["/绝对/路径/到/dist/index.js"]
    }
  }
}

⚠️ 绝对路径:相对路径会导致 Claude Desktop 找不到文件。

验证流程

1. 重启 Claude Desktop
       │
       ▼
2. 打开「Connectors」界面
       │
       ├── 看到 "my-tool-server"(type: desktop, local dev)✅
       │
       └── 没看到 → 检查配置路径 / Node 版本 / 编译产物
       │
       ▼
3. 在对话中提及工具功能
       │
       ▼
4. Claude 触发安全授权弹窗
       │
       ├── 用户核准 → 工具执行 → 返回结果 ✅
       │
       └── 用户拒绝 → Claude 文本回复(不调用工具)

反向验证:description 的影响

视频实测:清空 description 后,相同用户输入 → Claude 不触发工具调用,只生成文本回复。这证明 提示词语义是 Agent 工具调用的决定因素。


验证与勘误记录

视频声称 验证结果 来源
resultType 新字段 ✅ 真实存在 MCP 2026-07-28 spec - Tools
_meta 新字段 ✅ 真实存在 同上,规范要求每请求 MUST 包含
Node.js >= 20 ✅ 正确 npm registry: engines: {"node": ">=20"}
ESM "type": "module" ✅ 正确 npm 包声明 "type": "module"
@modelcontextprotocol/server 官方维护 ✅ 正确 Anthropic, PBC,v2.0.0 stable(2026-07-27 发布)
旧包 @modelcontextprotocol/sdk 即将淘汰 ⚠️ 部分正确 v1 仍维护(1.30.0,2026-07-27 更新),但 v2 是新 stable line;v1 周下载 52M vs v2 4.9M
stdio 传输机制 ✅ 正确 官方 SDK 支持 stdio,有 first-server tutorial
capabilities: { tools: {} } ✅ 正确 规范要求声明 tools capability
console.log 污染 stdio ✅ 正确 stdio 模式 stdout 用于 JSON-RPC,debug 须走 stderr
tsconfig Node16/NodeNext ✅ 正确 ESM 项目标准配置
claude_desktop_config.json 绝对路径 ✅ 正确 Claude Desktop 配置标准做法

勘误说明: 1. 视频说"旧包即将淘汰"表述过于绝对。v1 @modelcontextprotocol/sdk 当前仍在活跃维护(1.30.0),官方承诺 v1.x 至少 6 个月 bug fix + security update。但新项目建议直接用 v2。 2. 视频提到 registerTool 的方法名,v2 SDK 的实际 API 可能有差异(SDK 处于 v2 稳定期,API 可能调整),建议以 官方文档 为准。


参考资料

相关笔记

  • [[MCP 协议架构总览]]
  • [[Claude Desktop MCP 配置指南]]

文档生成时间:2026-09-16 基于 YAHA学堂 YouTube 视频 + MCP 2026-07-28 官方规范交叉验证