1. 什么是 MCP

MCP 全称 Model Context Protocol(模型上下文协议)。

它是一套标准化的 JSON-RPC 协议,定义了 AI 模型与外部工具之间的通信方式。核心概念:

概念 说明
MCP Client AI 客户端(Claude Desktop、Claude Code、Cline、Cursor 等)
MCP Server 提供工具能力的外部程序(本项目的 mcp-proxy.js
Tool 一个可被 AI 调用的功能单元,有名称、描述和参数 schema
Resource 可被 AI 读取的数据源(如场景层级快照)

MCP 协议基于 JSON-RPC 2.0,核心消息类型:

1
2
3
4
5
6
7
8
9
10
11
// 1. 初始化握手
{"jsonrpc":"2.0", "id":1, "method":"initialize", "params":{}}

// 2. 获取工具列表
{"jsonrpc":"2.0", "id":2, "method":"tools/list", "params":{}}

// 3. 调用工具
{"jsonrpc":"2.0", "id":3, "method":"tools/call", "params":{
"name": "get_scene_hierarchy",
"arguments": {"depth": 2}
}}

2. 什么是 MCP stdio transport

MCP 支持多种传输方式,本项目使用的是 stdio(标准输入/输出)

原理:

  • MCP Client(如 Claude)启动一个子进程(node mcp-proxy.js
  • Claude 通过子进程的 stdin 发送 JSON-RPC 请求
  • 子进程通过 stdout 返回 JSON-RPC 响应
  • 子进程的 stderr 用于打印调试日志(不会被 Claude 读取)
1
2
3
4
5
6
7
8
┌─────────────────┐          stdin           ┌─────────────────┐
│ │ ───── JSON-RPC 请求 ────▶ │ │
│ Claude Client │ │ mcp-proxy.js │
│ │ ◀──── JSON-RPC 响应 ───── │ │
└─────────────────┘ stdout └─────────────────┘
│ stderr

调试日志输出

为什么用 stdio 而不是 HTTP/WebSocket?

  • 不需要额外的端口占用
  • 进程生命周期由 Claude 客户端管理,启动即连接、退出即断开
  • 安全性好,只有本机的父子进程通信,不对外暴露接口

3. mcpServers 配置在哪里

mcpServers 是告诉 AI 客户端”有哪些 MCP Server 可以用”的配置项。

不同客户端的配置文件位置:

macOS

客户端 配置文件路径
Claude Code ~/.claude.json
Cursor ~/.cursor/mcp.json
Trae ~/.trae/mcp.json
Trae CN ~/.trae-cn/mcp.json
Windsurf ~/.codeium/windsurf/mcp_config.json
Gemini CLI ~/.gemini/mcp.json
OpenCode ~/.opencode/mcp.json
Codex ~/.codex/mcp.json
Qwen Code ~/.qwen/mcp.json
Kilo Code ~/.kilo/mcp.json

Windows

客户端 配置文件路径
Claude Code %USERPROFILE%\.claude.json
Claude Desktop %APPDATA%\Claude\claude_desktop_config.json
Cursor %USERPROFILE%\.cursor\mcp.json
Cline (VSCode) %APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json
Trae %USERPROFILE%\.trae\mcp.json

配置内容格式

所有客户端的配置格式统一如下:

1
2
3
4
5
6
7
8
9
10
{
"mcpServers": { // ← 固定的顶层键名,所有 MCP Server 都写在这里
"mcp-bridge": { // ← Server 标识名(自定义,用于显示和管理)
"command": "node", // ← 启动命令(可执行程序的名称或路径)
"args": [ // ← 命令参数数组
"/absolute/path/to/dist/mcp-proxy.js" // ← mcp-proxy.js 的绝对路径
]
}
}
}

各字段含义:

字段 说明
mcpServers MCP Server 集合,可配置多个
mcp-bridge Server 名称(自定义标识)
command 启动命令,这里是 node
args 命令参数,指向编译后的 mcp-proxy.js 绝对路径

4. 总览:从配置到可用的完整时间线

1
2
3
4
5
6
7
8
时间线 ──────────────────────────────────────────────────────────────────────▶

┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 读取 │ │ 拉起 │ │ MCP │ │ 工具 │ │ 等待 │ │ 调用 │
│ mcpServers│→│ 子进程 │→ │ 握手 │→ │ 注入 │→ │ 用户 │→ │ 工具 │
│ 配置 │ │ │ │ │ │ 模型 │ │ 提问 │ │ │
└─────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
阶段一 阶段二 阶段三 阶段四 阶段五 阶段五

每个阶段的核心问题:

阶段 核心问题 答案
从哪里读配置? 各客户端有固定的配置文件路径
怎么拉起 MCP Server? 执行配置中的 command + args
怎么知道 Server 可用? 通过 initialize + tools/list 握手
模型怎么知道有工具? 客户端把工具列表注入模型上下文
模型怎么决定调不调用? 根据用户意图 + 工具描述匹配
会话结束后呢? 客户端杀死子进程

杂记

  • mcp启动:
    1.AI 客户端(比如 Claude Code)启动时读取配置文件,看到”mcpServers”: {}配置后会立即执行 node /path/to/dist/mcp-proxy.js,把这个进程拉起来并保持不退
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {
    "mcpServers": {
    "mcp-bridge": {
    "command": "node",
    "args": ["/path/to/dist/mcp-proxy.js"]
    }
    }
    }


    2.进程拉起后,AI 客户端通过 stdin 依次发两条消息:
     1. initialize    → 问:"你是 MCP Server 吗?支持什么能力?"
    2. tools/list    → 问:"你有哪些工具可以用?"
    
    如果 mcp-proxy.js 正常回复了,这个 MCP Server 就标记为可用,如果进程启动失败、崩溃、或者没有按 MCP 协议回复,就标记为不可用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Claude Code 启动

├─ 读取 ~/.claude.json 里的 mcpServers

├─ 对每个 Server 执行 command + args 拉起子进程

├─ 发 initialize → 收到回复 → 握手成功

├─ 发 tools/list → 收到工具列表 → 注入模型上下文

├─ 标记为"可用" ✅

│ (如果上面任何一步失败 → 标记为"不可用" ❌)

└─ 等待用户提问...

└─ 模型判断需要工具 → 发 tools/call → 执行 → 返回结果