{
  "lead": "MCP（Model Context Protocol）是让 AI 应用调用外部工具、读取数据的开放协议：一个 MCP 服务端通过 JSON-RPC 声明自己有哪些「工具」「资源」和「提示词」，客户端（比如 AI 助手）按需调用。这个调试台是一个运行在浏览器里的 MCP 客户端，协议逻辑用 Rust 编写并编译成 WebAssembly；它通过本机的桥接服务连接你用 Go、Rust、Zig 或任何语言写的 MCP 服务端，也能把普通命令行工具当成 MCP 工具来调用。",
  "formulas": [
    [
      "页面（WASM 客户端）→ 桥接服务（本机）→ MCP 服务端 / 命令行工具",
      "浏览器不能启动进程，桥接服务只负责搬运消息和执行登记过的程序"
    ]
  ],
  "terms": [
    [
      "WASM 里的 MCP 客户端",
      "JSON-RPC 消息的组装与解析、initialize 握手与协议版本协商、分页列表、把工具的 JSON Schema 变成表单、把表单填写的值转换成正确类型的参数并校验，全部在 Rust 里完成（连 JSON 解析器也是手写的）。请求由 WASM 通过浏览器的 fetch 发出，服务端的推送通过 EventSource 接收。网络请求最终都经过浏览器，所以同源、跨域规则照常生效；WASM 能改进的是协议代码的可靠和复用，而不是权限。"
    ],
    [
      "桥接服务",
      "由 <code>scripts/serve.py --mcp 配置文件</code> 启用，只做搬运：stdio 型服务端作为子进程启动，每行一条 JSON-RPC 消息；Streamable HTTP 型服务端直接转发，并处理会话编号和 SSE 格式的响应；子进程的 stderr、服务端主动发来的通知和请求通过事件流推给页面。"
    ],
    [
      "命令行工具变成 MCP 工具",
      "配置文件里登记的每个命令行工具，会被包装成一个「虚拟 MCP 服务端」上的工具：参数表单来自配置里的 input_schema，调用时把参数值填进命令模板的 {占位符}，stdout、stderr 和退出码作为结果返回，退出码非 0 就标记为出错。程序直接启动，不经过 shell，所以参数里的 ; | $() 之类的字符只会原样传给程序。参数值单独占一个位置、又以「-」开头时默认拒绝，以免被程序当成选项（比如 --output=…）；程序本身也不能由参数决定。"
    ],
    [
      "服务端反过来请求客户端",
      "MCP 服务端可以向客户端请求采样、目录或用户输入。调试台不提供这些能力：收到 ping 就回复空结果，其他请求回复「不支持的方法」，并把整个过程记录在「原始报文」里。示例服务端的「反向请求」工具可以演示这一来一回。"
    ],
    [
      "安全",
      "能调用这个接口，就等于能在本机运行配置里的程序，所以桥接服务只接受同时满足以下条件的请求：来自本机回环地址、Host 头是 localhost、没有来自其他网站的 Origin，并带有令牌。令牌只在本机打开本页时通过 HttpOnly、SameSite=Strict 的 Cookie 下发，其他网站既读不到也带不上。浏览器只能按编号使用配置文件里登记的服务端和工具，不能指定程序或参数模板。服务端返回的内容一律当作纯文本显示。服务端的输出按行读取且有长度上限，命令行工具的输出最多保留 1 MB，多出来的读走丢弃；同一时间多个标签页各自的请求编号可能重复，桥接服务会换成自己分配的唯一编号，再把响应换回原编号。"
    ]
  ],
  "flow": [
    [
      "js",
      "页面加载后调用 <code>mcp_servers()</code> 取得配置里的服务端；点选一个后 <code>mcp_listen</code> 开始接收推送，<code>mcp_connect</code> 完成握手，再用 <code>mcp_list</code> 取回工具、资源和提示词。"
    ],
    [
      "rust",
      "WASM 为每个服务端维护一个会话：分配请求编号、组装 JSON-RPC、经 <code>/api/mcp/&lt;id&gt;/rpc</code> 发出并匹配响应；<code>mcp_form</code> 把工具的 inputSchema 转成表单描述，<code>mcp_call</code> 校验并转换参数后发出 tools/call。"
    ],
    [
      "js",
      "JS 按表单描述生成输入控件，展示结果里的文字、图片和资源；「原始报文」按时间列出所有发出、收到和推送的消息，也可以手写一条 JSON-RPC 直接发送。"
    ]
  ],
  "perf": [
    "这个页面需要本地服务：部署到静态托管时桥接服务不存在，页面会显示启动方法。只有它不是纯浏览器端的示例。",
    "消息往返的开销主要在进程间通信和 HTTP，本机上握手和一次工具调用通常只需几毫秒；超时（默认 30 秒，可在配置里调整）后桥接服务返回 504，子进程退出后下一次请求会自动重启它。",
    "这个 .wasm 约 120 KB，比其他示例大：主要是异步请求的状态机、浏览器接口绑定和字符串处理，因此用了体积优先的优化级别。"
  ],
  "src": [
    [
      "crates/tools/mcp/src/mcp.rs",
      ""
    ],
    [
      "crates/tools/mcp/src/web.rs",
      ""
    ],
    [
      "scripts/mcp_bridge.py",
      ""
    ],
    [
      "scripts/mcp_shell.py",
      ""
    ],
    [
      "scripts/mcp_demo_server.py",
      ""
    ],
    [
      "crates/tools/mcp/examples/demo_server.rs",
      ""
    ],
    [
      "examples/mcp-servers/go/main.go",
      ""
    ],
    [
      "examples/mcp-servers/zig/demo_server.zig",
      ""
    ],
    [
      "www/mcp/index.js",
      ""
    ]
  ]
}
