1. 从零跑通 MCP Client 到底卡在哪
MCP Client 是 MCP 协议里负责“牵线”的那一层:它把宿主应用(比如 IDE 插件、命令行工具)和 MCP Server 连起来,让工具调用、资源读取、提示词获取这些动作能真正发出去。适合谁?适合刚接触 MCP、已经照着教程写完一个 Hello world Server、但卡在“Client 怎么连上去、怎么把请求发出去”的开发者。我试过把官方 quickstart 直接抄下来跑,结果第一步就卡在传输层配置上——Server 路径写错、命令找不到、JSON-RPC 请求发出去没响应,全是坑。
这篇要解决的核心问题很具体:用最小的代码量,搭一个能跑通的 MCP Client,调用上一篇写好的 echo Server,把callTool这条链路走通。同时把模型调用的 Key 统一收口到 TaoToken,避免在 Client 里散落多家厂商的 Key 和 endpoint。整条链路是:Client 启动子进程 → 通过 stdio 发 JSON-RPC → Server 返回结果 → Client 打印。跑通之后你会看到Tool response里带着 echo 回来的内容,说明协议层、传输层、工具调用三层都通了。
下面按“环境准备 → TaoToken 前置 → 可复制配置 → 验证请求 → 排错 → 下一步”的顺序展开,每一步都给完整命令和文件内容,你可以直接复制改路径。
2. TaoToken 前置:统一 Key 与 endpoint 收口
在写 Client 代码之前,先把模型调用的出口定下来。MCP Client 本身只负责协议通信,但真实场景里 Client 往往还要调模型做推理或工具选择,如果每个 Client 都去配一套 OpenAI/Anthropic 的 Key,维护成本会很高。TaoToken 的做法是提供一个统一的 API 入口,把模型调用收敛到一个 Key 上。
你需要先拿到一个 API Key,入口在控制台的 API Keys 页面:
https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite拿到 Key 之后,模型调用的 base URL 统一用:
https://taotoken.net/api注意这个地址不带任何查询参数,直接作为 OpenAI 兼容客户端的base_url使用。Key 的传递方式就是标准的Authorization: Bearer <你的Key>,不需要额外签名或加密。
如果你后面要接 Claude Code 这类编码 Agent,Anthropic 兼容入口的文档在这里:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite这一步的意义在于:Client 代码里只出现一个TAOTOKEN_API_KEY环境变量和一个 base URL,换模型、换厂商都不用改 Client 逻辑。对于 Hello world 阶段,你甚至可以先不调模型,只验证 MCP 协议链路;等链路通了,再把模型调用接进来。
3. 可复制配置:项目骨架与 Client 代码
3.1 初始化项目与依赖
先确认 Node 环境,建议 18 以上:
node --version npm --version然后建目录、初始化、装依赖:
mkdir mcp-hello-client cd mcp-hello-client npm init -y npm install @modelcontextprotocol/sdk zod npm install -D @types/node typescript mkdir srcWindows 下把mkdir换成md,touch换成new-item即可,其余命令一致。
3.2 package.json 关键字段
打开package.json,确保有"type": "module"和构建脚本。下面是一份可直接用的骨架:
{ "name": "mcp-hello-client", "version": "1.0.0", "type": "module", "scripts": { "build": "tsc", "dev": "tsc --watch", "start": "node build/index.js" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.11.1", "zod": "^3.24.4" }, "devDependencies": { "@types/node": "^22.15.17", "typescript": "^5.8.3" } }"type": "module"必须加,否则 SDK 的 ESM 导入会报Cannot use import statement outside a module。
3.3 tsconfig.json
根目录建tsconfig.json,模块解析用 Node16,输出到build:
{ "compilerOptions": { "target": "ES2022", "module": "Node16", "moduleResolution": "Node16", "outDir": "./build", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }3.4 Client 主代码
在src/index.ts写入下面内容。核心是StdioClientTransport启动 Server 子进程,Client实例负责发 JSON-RPC:
import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; async function main() { // 传输层:启动 echo Server 子进程,路径改成你自己的 const transport = new StdioClientTransport({ command: "node", args: ["../mcp-hello-server/build/index.js"] }); const client = new Client({ name: "hello-client", version: "1.0.0" }); await client.connect(transport); try { const result = await client.callTool({ name: "echo", arguments: { message: "hello mcp" } }); console.log("Tool response:", JSON.stringify(result, null, 2)); } finally { await client.close(); } } main().catch((err) => { console.error("Client error:", err); process.exit(1); });几个关键点:command是node,args指向 Server 编译后的入口;callTool的name必须和 Server 注册的工具名完全一致;arguments的字段名也要和 Server 的 zod schema 对齐,否则会返回参数校验错误。
3.5 环境变量与 TaoToken 配置片段
如果你要在 Client 里顺带调模型,把 Key 放到环境变量,不要硬编码。Linux/macOS:
export TAOTOKEN_API_KEY="你的Key"Windows PowerShell:
$env:TAOTOKEN_API_KEY="你的Key"然后在代码里读取:
const apiKey = process.env.TAOTOKEN_API_KEY; const baseURL = "https://taotoken.net/api";这样 Client 里只有一处引用 Key,换环境只改环境变量。
4. 验证请求:构建、启动与预期输出
先构建:
npm run build看到build/index.js生成即成功。然后启动:
npm start预期输出类似:
Tool response: { "content": [ { "type": "text", "text": "hello mcp" } ] }只要content里出现你传进去的message,说明整条链路通了:Client 启动子进程 → stdio 传输 JSON-RPC → Server 收到tools/call→ 执行 echo → 返回结果 → Client 打印。
如果你想验证模型调用这一层,可以用模型对话入口快速测一下 Key 是否可用:
https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite在页面里发一条消息,能正常返回就说明 Key 和 endpoint 都没问题。这一步和 MCP 链路是独立的,先分开验证,出问题好定位。
5. 本篇常见错排查
5.1 报错Cannot find module '@modelcontextprotocol/sdk/client/index.js'
原因通常是"type": "module"没加,或者moduleResolution不是 Node16。检查package.json和tsconfig.json,改完重新npm run build。
5.2 启动后无输出,进程直接退出
大概率是 Server 路径写错,子进程启动失败但错误被吞了。把args里的路径改成绝对路径试一次,比如d:/projects/mcp-hello-server/build/index.js。另外确认 Server 已经npm run build过,build/index.js真实存在。
5.3Tool response里返回isError: true
说明请求发出去了,但 Server 侧执行失败。常见原因是工具名不对或参数不匹配。检查 Server 里server.tool("echo", ...)的第一个参数是不是echo,以及 zod schema 的字段名是不是message。两边必须逐字一致。
5.4 连接超时或connect卡住
stdio 传输依赖子进程的标准输入输出,如果 Server 启动时往 stdout 打了非 JSON-RPC 的日志,会污染协议流。检查 Server 代码里有没有console.log打在协议消息之外,有的话改成console.error。
5.5 环境变量读不到
process.env.TAOTOKEN_API_KEY返回undefined,先确认是在同一个终端会话里 export 的,或者用.env文件配合dotenv加载。Windows 下注意 PowerShell 和 CMD 的语法不同。
6. 下一步:从 Hello world 到长期编码 Agent
Hello world 跑通之后,下一步通常是把 MCP Client 接到真实的编码场景里,让 Agent 自动选择工具、连续调用。这时候单次callTool就不够了,需要处理多轮对话、工具结果回填、上下文管理。如果你打算长期跑编码类 Agent,可以看下 Coding Plan 的接入方式:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite接入文档里有完整的 endpoint 和参数说明:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite我的建议是先把这篇的 stdio 链路跑稳,再逐步加 resources 和 prompts 的调用,最后接模型。每一步都单独验证,出问题能快速定位到是协议层、传输层还是模型层。