ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

MCP 入门(二):从握手到执行,一文拆解架构设计——用 TaoToken 统一 Key 跑通 JSON-RPC 全链路

MCP 入门(二):从握手到执行,一文拆解架构设计——用 TaoToken 统一 Key 跑通 JSON-RPC 全链路 1. 为什么你配好了 MCP 服务器AI 还是调不动工具很多人第一次接触 MCPModel Context Protocol时卡点不在装没装服务器而在握手之后到底发生了什么。你照着文档把服务器进程拉起来了配置文件也写了结果 AI 应用里工具列表是空的或者调用时报Method not found甚至连接直接断掉。这类问题九成出在对 MCP 客户端-服务器架构和 JSON-RPC 全链路的理解断层上。MCP 是什么一句话它是一套让 AI 应用Host通过标准化协议去发现和调用外部能力的规范。能做什么把文件读写、数据库查询、API 调用这些操作包装成 AI 可以动态发现的工具资源提示词。适合谁正在给 AI 工具接入本地或远程能力、又不想为每个模型单独写适配层的开发者。这一篇聚焦从握手到执行的完整链路Host 怎么创建 Client、Client 怎么和 Server 完成initialize能力协商、tools/list怎么发现原语、tools/call怎么执行并回传结果。同时我会用 TaoToken 统一 Key 和 API 通道把模型侧和 MCP 侧串起来交付可复制的config.toml与settings.json骨架并给出一次真实握手请求与执行响应的验证动作。读完你应该能自己判断问题出在传输层、数据层还是能力协商阶段。2. 先把 TaoToken 的 Key 和通道准备好MCP 本身不负责模型推理它只管上下文和工具怎么传。但你在本地跑通全链路时总得有个 LLM 来触发工具调用否则tools/call永远不会被发起。所以第一步是把模型通道统一掉避免一会儿换一个 Key、一会儿改一个 base_url。TaoToken 在这里的角色是统一入口一个 Key 覆盖多家模型API 地址固定省得你在多个配置文件里来回粘贴不同的凭证。注册和拿 Key 的入口在官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 登录后进控制台创建 API Key地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。API 基址统一用 https://taotoken.net/api 注意这个地址不带任何查询参数。拿到 Key 之后先别急着写 MCP 配置。用一条最朴素的请求确认通道是通的这一步能帮你排除掉后面 80% 的到底是 MCP 问题还是模型问题的扯皮。curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: reply with ok}] }返回里能看到choices[0].message.content就说明模型通道没问题。把TAOTOKEN_API_KEY写进环境变量别硬编码进配置文件后面 MCP 服务器和客户端都会读它。注意MCP 的传输层和模型 API 是两条独立的通道。模型通道断了表现是 AI 不回复MCP 通道断了表现是工具列表为空或调用超时。排障时先分清是哪条。3. 拆开架构Host、Client、Server 与两层协议在写配置之前得先把角色理清楚否则你会在我到底该配哪个文件上浪费半小时。MCP 采用客户端-服务器架构三个角色分工明确Host 是 AI 应用本体管全局负责协调一个或多个 ClientClient 是 Host 为每个 Server 创建的专属连接对象一条连接对应一个 Server互不干扰Server 提供能力暴露工具、资源、提示词。一句话概括就是Host 管全局Client 管连接Server 管能力。按运行位置Server 分两种。本地服务器走 STDIO 传输通过标准输入输出流通信零网络开销服务单个 Client远程服务器走 Streamable HTTP 传输可同时服务多个 Client兼容 bearer 令牌、API Key、自定义请求头等认证方式。协议本身分两层。数据层定义基于 JSON-RPC 2.0 的通信协议管说什么包含生命周期管理、工具/资源/提示词等核心元素、以及通知机制传输层定义通信机制和通道管怎么送达包含连接建立、消息帧和授权。这个分层最妙的地方在于不管底层是 STDIO 还是 HTTP上层 JSON-RPC 消息格式完全一致。所以你调试时抓到的报文换传输方式后结构不变。数据层里最核心的概念是原语Primitives。服务器可以暴露三个核心原语工具Tools是可执行函数资源Resources是上下文数据源提示词Prompts是可复用模板。每个原语都关联发现*/list、检索*/get以及执行tools/call方法。工作流是先*/list发现再按需调用。这个设计让工具列表可以动态更新而不是写死的。4. 可复制的 config.toml 与 settings.json 骨架现在进入实操。下面这份config.toml是 MCP 服务器侧的配置骨架我把它放在项目根目录用 STDIO 传输启动一个本地 Server。# config.toml - MCP Server 侧配置骨架 [server] name local-tools version 1.0.0 protocol_version 2025-06-18 [transport] type stdio # 本地用 stdio远程改 streamable-http command python args [-m, my_mcp_server] [capabilities] tools { listChanged true } # 声明支持工具原语且列表可变 resources {} # 声明支持资源原语 prompts {} # 声明支持提示词原语 [model] # 模型侧统一走 TaoToken一个 Key 覆盖多模型 base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY default_model gpt-4o-mini对应的settings.json是 Host 侧的客户端配置告诉 AI 应用去哪里找 Server、怎么连。{ mcpServers: { local-tools: { command: python, args: [-m, my_mcp_server], env: { TAOTOKEN_API_KEY: ${TAOTOKEN_API_KEY} }, transport: stdio }, remote-tools: { url: https://taotoken.net/api/mcp, transport: streamable-http, headers: { Authorization: Bearer ${TAOTOKEN_API_KEY} } } }, model: { base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY } }几个关键点值得单独说。capabilities里的listChanged true决定了服务器后续能不能主动推送notifications/tools/list_changed如果你没声明却指望收到通知那是收不到的。transport字段决定走 STDIO 还是 HTTP本地调试优先 STDIO因为不涉及网络和认证出问题好定位。env里用${TAOTOKEN_API_KEY}引用环境变量避免把 Key 写进版本库。提示远程 Server 的url和模型 API 的base_url是两个不同的端点别混用。模型走/api/v1/chat/completionsMCP 走它自己的路径。5. 一次握手请求与执行响应的完整验证配置写完了怎么确认链路真的通了别只看 AI 有没有回复要抓 JSON-RPC 报文。下面按顺序走一遍。第一步握手。Client 向 Server 发initialize协商协议版本和能力。{ jsonrpc: 2.0, id: 1, method: initialize, params: { protocolVersion: 2025-06-18, capabilities: { elicitation: {} }, clientInfo: { name: example-client, version: 1.0.0 } } }Server 的响应会亮出它的底牌{ jsonrpc: 2.0, id: 1, result: { protocolVersion: 2025-06-18, capabilities: { tools: { listChanged: true }, resources: {} }, serverInfo: { name: example-server, version: 1.0.0 } } }看到capabilities.tools存在说明服务器支持工具原语。握手成功后Client 必须补发一个通知否则 Server 不会进入就绪状态{ jsonrpc: 2.0, method: notifications/initialized }第二步发现工具。发tools/list不需要参数。{ jsonrpc: 2.0, id: 2, method: tools/list }响应里的tools数组就是可用工具清单每个工具带name、description、inputSchema。inputSchema是 JSON Schema 格式标注了哪些参数必填、哪些可选。这一步拿到的name是后面调用的主键必须精确匹配。第三步执行工具。用发现阶段拿到的完整名称发起tools/call。{ jsonrpc: 2.0, id: 3, method: tools/call, params: { name: weather_current, arguments: { location: San Francisco, units: imperial } } }响应是内容对象数组type字段标识内容类型{ jsonrpc: 2.0, id: 3, result: { content: [ { type: text, text: Current weather in San Francisco: 68F, partly cloudy. } ] } }到这里从握手到执行的链路就闭环了。如果你在 AI 应用里操作Host 会自动完成这些步骤初始化时逐一连接 Server 并缓存能力把各 Server 的工具汇总成统一注册表交给 LLMLLM 决定调用后 Host 拦截请求、路由到对应 Server、把结果追加回对话流。第四步验证通知。如果你的 Server 声明了listChanged true当工具列表变动时它会主动推送{ jsonrpc: 2.0, method: notifications/tools/list_changed }注意这条消息没有id字段遵循 JSON-RPC 2.0 的通知语义——发了就完事不等回复。Client 收到后应该立即重新发一次tools/list刷新本地注册表形成通知到刷新的闭环。6. 本篇常见错排查报错一Method not found。最常见的原因是握手没完成就发tools/list。MCP 是有状态协议必须先initialize再发notifications/initialized之后才能调其他方法。顺序错了Server 会直接拒绝。报错二工具列表为空。先确认initialize响应里有没有capabilities.tools。如果服务器压根没声明工具能力tools/list返回空数组是正常的。再检查settings.json里的command和args能不能手动跑起来进程起不来自然没工具。报错三tools/call报参数校验失败。对照tools/list返回的inputSchema检查参数名和类型。required数组里的字段一个都不能少enum字段的值必须在允许范围内。工具名也要精确匹配weather_current不能写成weather。报错四连接建立后立刻断开。多半是协议版本不匹配。protocolVersion字段如果双方不一致MCP 会直接终止连接绝不含糊。把 Client 和 Server 的版本对齐到同一个日期版本。报错五收不到list_changed通知。检查初始化时服务器有没有声明listChanged: true。没声明就不会发这是能力协商决定的不是 bug。报错六模型不触发工具调用。这通常是模型侧问题不是 MCP 问题。确认 TaoToken 通道正常、模型支持 function calling、工具描述写得够清楚。工具描述太模糊LLM 不知道该在什么时候调用。排障时建议按传输层到数据层的顺序查先确认进程/网络通不通再确认 JSON-RPC 报文格式对不对最后确认能力协商和原语调用。抓包看报文是最快的定位方式因为不管 STDIO 还是 HTTP上层消息格式完全一致。7. 把链路跑通之后下一步做什么链路跑通只是起点。真正让 MCP 好用的是理解原语的动态性工具列表可以随服务状态、外部依赖、用户权限变化而增减通知机制让 Client 无需轮询就能保持同步。你可以试着给 Server 加一个工具观察list_changed通知怎么触发 Client 刷新注册表这个体感比读十遍文档都强。如果你要长期跑编码类或 Agent 类任务建议把模型通道固定下来用 TaoToken 的 Coding Plan 统一管理额度入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。想先在网页里验证模型对工具调用的理解可以直接用模型对话 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。接入细节和字段说明看文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite Key 管理在控制台 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。Claude Code 相关的接入配置参考 https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 。最后留一个我踩过的坑STDIO 传输下Server 往标准输出里打任何非 JSON-RPC 的日志都会污染消息流导致解析失败。调试信息一律走标准错误别走标准输出。这个细节不写进文档但能让你少熬一个晚上。
返回列表