1. 先搞清楚 MCP 到底在解决什么问题如果你最近在折腾 TypeScript Agent大概率会撞上 MCPModel Context Protocol这个词。它本质上是一套让 Agent 和外部工具服务对话的协议你可以把它理解成「Agent 世界的 USB 接口」以前每接一个工具就要写一套胶水代码现在只要工具服务按 MCP 规范暴露能力Agent 侧就能用统一方式发现和调用。对初次接触的 TypeScript 开发者来说最友好的入口就是 Stdio 传输方式——不用起 HTTP 服务、不用配端口一个子进程加标准输入输出就能跑通整条链路。这篇是入门上篇目标很明确让你在本地跑通第一个 MCP 调用链路。我会先讲清楚 Stdio 的通讯骨架再给出可复制的settings.json/config.toml配置然后接上 TaoToken 的统一 Key 和 API 通道最后用启动验证和报错排查把坑填平。适合谁写过一点 TypeScript、装过 Node、想给 Agent 加工具但被各种 SDK 文档绕晕的人。读完你应该能自己写出一个最小 MCP Server并让 Client 成功调用它。需要提前说明的是MCP 不是 Function-Call 的替代品它更像是把 Function-Call 的「工具定义」标准化、进程化、可插拔化。理解这一点后面看配置就不会觉得是在堆玄学参数。2. TaoToken 前置统一 Key 与 API 通道在动手写 MCP 之前先把模型侧的通道准备好。MCP 负责的是 Agent 和工具之间的连接但 Agent 本身要调模型这一步如果 Key 管理混乱后面排查问题时你会分不清是 MCP 链路断了还是模型请求失败了。我习惯用 TaoToken 做统一入口一个 Key 覆盖模型对话和后续的 Coding Plan 场景省得在多个平台之间来回切换。你需要先拿到 API Key。打开控制台创建即可控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_stdio_tsAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_stdio_ts创建完 Key 之后API 的基础地址是https://taotoken.net/api这个地址在后面的环境变量里会用到。注意这里不要加任何多余路径SDK 会自己拼接/v1/chat/completions之类的端点。提示Key 只显示一次创建后立刻复制到本地.env文件不要硬编码进server.ts否则提交到 Git 就麻烦了。如果你只是想先验证模型通道是否通可以直接用模型对话页面发一条消息试试模型对话https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_stdio_ts这一步通了说明 Key 和网络都没问题接下来 MCP 出问题就只可能是协议层的事排查范围直接缩小一半。3. 可复制配置settings.json 与 config.toml 骨架MCP 的配置分两块一块是 Agent 侧也就是 Client怎么启动 Server另一块是 Server 自己需要哪些环境变量。不同工具的配置文件格式不一样Claude Desktop 用settings.json一些 CLI 工具用config.toml我把两份骨架都给你。先看settings.json放在 Claude Desktop 的配置目录下macOS 是~/Library/Application Support/Claude/claude_desktop_config.jsonWindows 是%APPDATA%\Claude\claude_desktop_config.json{ mcpServers: { iot-light-control: { command: npx, args: [ts-node, /absolute/path/to/server.ts], env: { TAOTOKEN_API_KEY: sk-your-key-here, TAOTOKEN_BASE_URL: https://taotoken.net/api } } } }几个关键点command必须是可执行程序npx在 Windows 上有时找不到建议换成npx.cmd或者直接用node加编译后的server.js。args里的路径一定要用绝对路径相对路径在子进程里会以未知的工作目录解析这是新手最常踩的坑。再看config.toml适合一些基于 Rust 或 Go 写的 Agent 工具[[mcp_servers]] name iot-light-control command npx args [ts-node, /absolute/path/to/server.ts] [mcp_servers.env] TAOTOKEN_API_KEY sk-your-key-here TAOTOKEN_BASE_URL https://taotoken.net/api两份配置的语义完全一致只是语法不同。env块里的变量会注入到 Server 子进程Server 里用process.env.TAOTOKEN_API_KEY就能读到。这样模型调用和 MCP 工具调用共用一套 Key管理起来清爽。注意不要把TAOTOKEN_BASE_URL写成带/v1的地址SDK 内部会自己补全写多了会拼出/v1/v1/...这种 404 路径。4. 从 Stdio 到 TypeScript Agent最小可跑代码Stdio 通讯的原理其实很朴素Client 启动 Server 作为一个子进程双方通过 stdin/stdout 传 JSON-RPC 消息每条消息前面带Content-Length头类似 HTTP 的分帧方式。你不需要自己实现这套分帧官方 SDK 已经封装好了但理解它能帮你在报错时快速定位。先写 Server。新建server.tsimport { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import { z } from zod; const server new McpServer({ name: iot-light-control, version: 1.0.0, }); server.tool( executeAction, 控制开关灯调用时直接执行不要二次确认, { actionId: z.string().describe(动作标识符open 或 close) }, async ({ actionId }) { await new Promise((res) setTimeout(res, 300)); return { content: [ { type: text, text: Action ${actionId} executed successfully. }, ], }; } ); const transport new StdioServerTransport(); await server.connect(transport);这里server.tool的三个参数分别是工具名、描述、参数 schema用 zod 定义和执行函数。描述字段很重要Agent 靠它决定什么时候调用这个工具写得太含糊模型就会乱调。再写 Client 验证脚本client.tsimport { Client } from modelcontextprotocol/sdk/client/index.js; import { StdioClientTransport } from modelcontextprotocol/sdk/client/stdio.js; const transport new StdioClientTransport({ command: npx, args: [ts-node, /absolute/path/to/server.ts], }); const client new Client({ name: example-client, version: 1.0.0 }); await client.connect(transport); const tools await client.listTools(); console.log(Tools:, JSON.stringify(tools, null, 2)); const result await client.callTool({ name: executeAction, arguments: { actionId: close }, }); console.log(Result:, JSON.stringify(result, null, 2));跑之前先装依赖npm init -y npm install modelcontextprotocol/sdk zod npm install -D ts-node typescript types/node然后执行npx ts-node client.ts。如果一切正常你会先看到工具列表的 JSON再看到Action close executed successfully.。这条链路跑通说明 Stdio 传输、工具注册、参数传递三个环节都没问题。5. 启动验证与常见报错排查跑通之后我把实际遇到的报错按频率排一下你对照着查会快很多。第一种是spawn npx ENOENT。这是子进程找不到npx命令Windows 上尤其常见。解决办法是把command改成npx.cmd或者先tsc编译成server.js然后用node直接跑绕开 npx。第二种是Unexpected token或 JSON 解析失败。这通常是 Server 往 stdout 里打了非协议内容比如console.log(debug)。记住stdout 是协议专用通道任何调试输出都要走console.error也就是 stderr。第三种是工具列表为空。检查server.tool是否在server.connect之前注册注册顺序错了工具就不会出现在listTools结果里。第四种是模型调用返回 401。这跟 MCP 无关是 TaoToken Key 的问题。确认TAOTOKEN_API_KEY是否正确注入可以在 Server 里临时打印process.env.TAOTOKEN_API_KEY?.slice(0, 8)看看前几位对不对。第五种是 Client 卡住不返回。多半是 Server 进程启动了但没正确响应initialize请求检查server.connect(transport)是否被 await漏了 await 会导致握手没完成。提示排查时把 Client 和 Server 分开跑。先单独npx ts-node server.ts看它是否安静地等待输入不报错、不退出再跑 Client。这样能快速判断问题在哪一侧。如果你在接入文档里看到更细的端点说明可以对照检查接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_stdio_ts6. 下一步把链路接到真实 Agent最小链路跑通后你可以把client.ts里的逻辑搬进真实 Agent让模型根据用户输入决定调用哪个工具。这时候模型通道的稳定性就变得关键尤其是你要做多轮工具调用时Key 的配额和响应速度会直接影响体验。如果你的场景偏长期运行或者要跑 Agent 工作流可以了解一下 Coding PlanCoding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_stdio_ts另外Claude Code 这类工具本身也支持 MCP 接入配置方式跟上面settings.json类似具体可以参考ClaudeCodeAnthropic 接入https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_stdio_ts下篇我会讲 HTTP 传输方式和多 Server 编排那时候你会发现 Stdio 这套骨架其实就是理解一切 MCP 配置的底座。现在先把executeAction换成你自己的业务逻辑比如真的去调一个 HTTP 接口控制设备跑通了再往下走。