news 2026/9/29 3:52:50

入门】用 Node.js 写一个 STDIO 版 MCP 服务器:TaoToken 配置与调试骨架

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
入门】用 Node.js 写一个 STDIO 版 MCP 服务器:TaoToken 配置与调试骨架

1. 为什么本地 MCP 服务器值得先跑一个 STDIO 版本

MCP(Model Context Protocol)说白了就是给 AI 工具定的一套「点菜规则」:AI 负责按标准格式说出要调什么工具、传什么参数,你的服务器负责真正执行并把结果按标准格式端回去。它解决的是「AI 想用你的能力,但每家接法都不一样」的问题。而 STDIO 方式是所有传输方式里门槛最低的一种——不用开端口、不用配网络、不用管鉴权网关,进程之间用标准输入输出对话就行,特别适合本地工具链、个人脚本、编辑器插件这类场景。

这篇面向的是想从零跑通本地 MCP 工具链的 Node.js 开发者。我会带你写一个最小可用的 STDIO 版 MCP 服务器,给出可直接复制的package.json、server启动骨架,再补上 TaoToken 统一 Key/API 通道的settings.json配置片段,最后用一次真实的 STDIO 握手和工具调用把整条链路验证一遍。全程不需要你懂协议细节,照着敲就能跑起来。

适合谁:写过一点 Node.js、想让自己的脚本被 AI 工具调用的人;或者已经在用支持 MCP 的编辑器、想搞清楚「服务器那头到底发生了什么」的人。跑完这一遍,你对 MCP 的握手、工具注册、参数校验、返回结构会有一个能上手改的实体认知,而不是停留在概念层。

2. TaoToken 前置:把 Key 和 API 通道先备好

在写代码之前,先把「AI 侧怎么连上模型」这件事解决掉。MCP 服务器本身只负责执行工具,真正发起对话、决定调用哪个工具的是模型客户端。如果你用的是支持自定义 API 通道的客户端,可以把它统一指向 TaoToken,这样 Key 管理、模型切换、用量查看都在一个地方,不用每个工具各配一套。

TaoToken 在这里扮演的是统一入口:你拿到一个 Key,客户端通过https://taotoken.net/api这个 API 地址访问模型,模型对话、编码计划、控制台、Key 管理都有对应页面。对本地 MCP 调试来说,好处是你不用在多个客户端之间来回换 Key,调试时切换模型也方便。

具体操作路径:

先去控制台创建 API Key,地址是https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite,在 Key 管理页生成一个,复制保存好,后面配置里要用。

如果你只是想先验证模型能不能通,可以直接用模型对话页试一句:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite,能正常返回就说明 Key 和通道没问题。

如果你打算长期做编码类、Agent 类的接入,建议看一下 Coding Plan:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite,它更适合高频调用场景。

Key 的详细管理入口在https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite,接入文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite,遇到字段含义不清楚的时候翻文档最快。

注意:Key 属于敏感凭据,别写进会提交到仓库的文件里。本地调试建议用环境变量或单独的本地配置文件,并在.gitignore里排除掉。

3. 可复制配置:package.json 与服务器启动骨架

先建目录、初始化项目。Node.js 建议用 18 以上版本,SDK 对 ESM 支持更稳。

mkdir mcp-stdio-demo && cd mcp-stdio-demo npm init -y

然后把package.json改成下面这样。关键是"type": "module",因为 SDK 用的是 ESM 导入语法;依赖只装两个:MCP 官方 SDK 和 zod(用来描述工具参数的类型和校验规则)。

{ "name": "mcp-stdio-demo", "version": "1.0.0", "description": "A minimal STDIO MCP server demo", "main": "server.js", "type": "module", "scripts": { "start": "node server.js", "inspect": "npx @modelcontextprotocol/inspector node server.js" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.20.2", "zod": "^3.23.8" } }

装依赖:

npm install

接着写server.js。这个骨架做了三件事:创建一个 MCP 服务器实例、注册一个带参数校验的工具、用 STDIO 传输层把服务器挂起来。注意日志一律走console.error,因为console.log在 STDIO 模式下会污染协议通道,这是新手最容易踩的坑。

#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; const server = new McpServer({ name: "demo_service", version: "1.0.0" }); // 注册一个工具:say_hello server.tool( "say_hello", { needShowMeText: z.string().describe("想要展示的话") }, async ({ needShowMeText }) => { try { return { content: [{ type: "text", text: "Hello => " + needShowMeText }] }; } catch (error) { return { content: [{ type: "text", text: `失败: ${error.message}` }], isError: true }; } } ); async function main() { try { const transport = new StdioServerTransport(); await server.connect(transport); console.error("MCP 服务器已启动,等待 STDIO 连接"); } catch (error) { console.error("启动服务器时出错:", error); process.exit(1); } } main();

这里server.tool的三个参数分别是:工具名、参数 schema(zod 对象,describe里的文字会作为参数说明暴露给模型)、执行函数。执行函数返回的content数组是 MCP 规定的标准返回结构,type: "text"表示文本结果;出错时把isError设为true,客户端就能识别为失败。

如果你想让这个服务器被编辑器里的 AI 工具接入,还需要在客户端的 MCP 配置里登记它。以常见的settings.json风格配置为例,片段长这样:

{ "mcpServers": { "mcp-stdio-demo": { "command": "node", "args": ["/absolute/path/to/mcp-stdio-demo/server.js"], "env": { "TAOTOKEN_API_KEY": "你的Key", "TAOTOKEN_BASE_URL": "https://taotoken.net/api" } } } }

command是启动命令,args是脚本路径,注意用绝对路径,相对路径在不同客户端的工作目录下容易找不到文件。env里放的是给服务器进程用的环境变量,如果你的工具需要调用模型,就可以在这里注入 TaoToken 的 Key 和 API 地址,服务器里用process.env.TAOTOKEN_API_KEY读取即可。

4. 验证请求:一次 STDIO 握手与工具调用

代码写完先确认进程能起来:

node server.js

正常的话终端不会有标准输出,只会在 stderr 打印「MCP 服务器已启动,等待 STDIO 连接」,然后进程挂起等待输入——这就是 STDIO 模式的正常状态,它在等客户端通过标准输入发消息。

最省事的验证方式是用官方调试工具 Inspector:

npx @modelcontextprotocol/inspector node server.js

它会起一个本地网页界面,自动连上你的服务器。在界面里你能看到服务器信息、已注册的工具列表,点进say_hello,在参数框里填一段文字,比如world,点执行。如果返回里出现Tool Result: Success,并且内容区显示Hello => world,说明握手、工具发现、参数传递、结果返回整条链路都通了。

想更硬核一点,也可以手动发一条 JSON-RPC 消息验证握手。MCP 基于 JSON-RPC 2.0,初始化请求大概长这样:

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"manual-test","version":"1.0.0"}}}

把它通过标准输入喂给进程,你会收到一条包含serverInfo和capabilities的响应,这就代表握手成功。日常调试用 Inspector 就够了,手动发消息主要是帮你理解协议层发生了什么。

5. 本篇常见错排查

启动就报Cannot use import statement outside a module:package.json里漏了"type": "module",或者你用了.cjs后缀。补上这一行即可。

客户端连不上、提示找不到命令:args里的脚本路径写成了相对路径。改成绝对路径,Windows 下注意反斜杠转义或直接用正斜杠。

工具调用返回乱码或客户端直接断开:检查代码里有没有用console.log输出调试信息。STDIO 模式下标准输出是协议通道,任何非协议内容都会破坏消息解析,调试信息一律用console.error。

Inspector 里看不到工具:确认server.tool(...)的注册代码在server.connect(transport)之前执行。如果注册写在main之后或者异步没等待,工具列表会是空的。

参数校验一直失败:zod schema 的字段名要和执行函数解构出来的名字完全一致,needShowMeText大小写错一个字母就会报参数缺失。

改了代码但行为没变:客户端可能缓存了旧的服务器进程。重启客户端,或者确认你改的是客户端实际加载的那个文件路径。

6. 把这条链路接到你的真实工具上

跑通这个骨架之后,真正有价值的是往里塞你自己的逻辑。say_hello换成查数据库、读本地文件、调内部接口都行,返回结构保持content数组的格式就不会出问题。参数 schema 用 zod 描述得越清楚,模型越知道该怎么传参,describe里的说明文字别偷懒。

如果你后面要接模型能力,Key 和通道统一走 TaoToken 会省很多事:模型对话验证在https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite,Key 管理在https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite,接入字段不清楚就查https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite。长期做编码和 Agent 接入的话,Coding Plan 那条线更合适:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite。

一个实用建议:把每个工具的执行函数都包一层 try/catch,出错时返回isError: true而不是让进程崩掉。STDIO 服务器一旦退出,客户端那边就是「连接断开」,排查起来比看一条错误返回麻烦得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 3:52:30

同城货运平台全链路测试实践:JMeter压测与性能优化复盘

“拾运”这个项目名,第一眼看像货运调度,实际测下来也确实是个同城货运撮合平台:货主发单、司机接单、平台调度、线上结算,典型的多端多角色业务系统。这轮测试我做了功能全量回归、接口级性能摸底和一部分弱网兼容性验证&#xf…

作者头像 李华
网站建设 2026/9/29 3:52:03

AI 应用系统设计:用 TaoToken 统一 Key 打通多工具配置链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 3:51:59

NewAPI+Sub2API 手把手部署搭建教程:TaoToken 统一 Key 接入配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华