Mindket

用官方 SDK 写一个 TypeScript MCP 服务器

黑色横幅,标题是“MCP 实战课”,下面一行写着“用 Python 或 TypeScript 写 MCP 服务器,测试并接入”。

要用 TypeScript 写 MCP 服务器,先安装 @modelcontextprotocol/server 和 zod,创建一个 McpServer,再用 registerTool 和 Zod 输入参数结构注册每个工具。用 serveStdio 提供服务,宿主就能把这个文件当作本地进程启动。运行 npx tsx src/index.ts 即可,不需要构建,然后用 MCP Inspector 调用工具。

本节内容

  • 你会在一个 TypeScript 文件里写出 stdio 服务器,带一个查询美国天气预警的工具 get-alerts。
  • Zod 结构是你唯一要写的参数结构。其余的都由 SDK 据此生成,包括在处理函数运行之前的参数校验。
  • 当前版本的 SDK 包叫 @modelcontextprotocol/server。旧教程装的 @modelcontextprotocol/sdk 是 1.x 系列。
  • stdio 服务器里只要有一个 console.log,协议就会被弄坏。日志请用 console.error。
全部课程
本页目录
  1. 开始之前
  2. 六步写出服务器
  3. 代码在做什么
  4. 模型调用工具时发生了什么
  5. David Soria Parra 谈无状态规范和 v2 SDK
  6. 常见错误
  7. 动手试试
  8. 下一课:用 MCP Inspector 好好测一遍
  9. 自测一下
  10. 常见问题
  11. 资料来源

开始之前

这一课照着 TypeScript SDK 自己仓库里的第一个服务器教程来做,它用 tsx 直接运行 TypeScript。MCP 构建指南写的是一个相似的天气服务器,多一个工具,并用 tsc 编译。想要有构建步骤的话,可以选那一份。

你需要 Node.js 20 或更高、npm,还要能上网,因为工具调用的是美国国家气象局的 API。最后一步的 Inspector 需要打过补丁的 Node:22.23.4、24.22.1 或 26.12.1,或者各自系列里更新的版本,第 3 课会解释。装任何东西之前先看清包名,因为 TypeScript 的 MCP 教程分成了两代。

TypeScript MCP 教程里会遇到的几个包
包SDK 系列在哪里会遇到
@modelcontextprotocol/serverv2,当前的稳定系列官方文档和这一课
@modelcontextprotocol/clientv2,用于连接服务器的代码客户端和测试脚本
@modelcontextprotocol/sdkv1.x,较早的系列,仍在维护旧教程和已有代码

六步写出服务器

代码分两段:工具和启动调用。两段都放进同一个文件 src/index.ts。

import { McpServer } from '@modelcontextprotocol/server';
import { serveStdio } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';

const NWS_API = 'https://api.weather.gov';

interface AlertsResponse {
    features: { properties: { event?: string; headline?: string } }[];
}

function createServer(): McpServer {
    const server = new McpServer({ name: 'weather', version: '1.0.0' });

    server.registerTool(
        'get-alerts',
        {
            description: 'Get the active weather alerts for a US state',
            inputSchema: z.object({
                state: z.string().length(2).describe('Two-letter US state code, e.g. CA')
            })
        },
        async ({ state }) => {
            const code = state.toUpperCase();
            const url = `${NWS_API}/alerts/active?area=${code}`;
            const res = await fetch(url, { headers: { 'User-Agent': 'mcp-weather-tutorial/1.0' } });
            if (!res.ok) {
                return { content: [{ type: 'text', text: `NWS API error: HTTP ${res.status}` }], isError: true };
            }
            const { features } = (await res.json()) as AlertsResponse;
            if (features.length === 0) {
                return { content: [{ type: 'text', text: `No active alerts for ${code}.` }] };
            }
            const lines = features.map(f => f.properties.headline ?? f.properties.event ?? 'Unnamed alert');
            return { content: [{ type: 'text', text: lines.join('\n') }] };
        }
    );

    return server;
}

void serveStdio(createServer);
console.error('weather MCP server running on stdio');
  1. 用 node --version 检查 Node,版本必须是 20 或更高。
  2. 用 mkdir weather && cd weather 创建项目目录,再运行 npm init -y,然后运行 npm pkg set type=module。type=module 这个设置不能省,因为 SDK 只提供 ES 模块。
  3. 用 npm install @modelcontextprotocol/server zod tsx 安装 SDK、Zod 和 tsx,再用 mkdir src 建源码目录。
  4. 新建 src/index.ts,把上面的代码粘进去。
  5. 在项目根目录用 npx tsx src/index.ts 启动服务器。它会往 stderr 打印 weather MCP server running on stdio,然后停在那里等待。按 Ctrl+C 停止。
  6. 运行 npx @modelcontextprotocol/inspector npx tsx src/index.ts 调用工具。在它打开的浏览器标签页里点 Connect,打开 Tools 标签页,选中 get-alerts,输入像 TX 这样的州代码,然后运行。

代码在做什么

createServer 是一个工厂函数,每次调用都新建一个 McpServer 并在上面注册一个工具。registerTool 接收名称、配置和一个异步处理函数。inputSchema 是一个 Zod 结构,SDK 就靠这一份结构给模型生成 JSON Schema,在处理函数运行之前校验参数,并推断出处理函数的参数类型。

处理函数返回 content,也就是一组带类型的内容块,这里只有一个 text 块。设置 isError: true 表示这次结果是失败,模型能读到并作出反应。用 { "state": "California" } 调用 get-alerts,SDK 会在处理函数运行之前就拒绝,模型看到的是这条消息:

Input validation error: Invalid arguments for tool get-alerts: state: Too big: expected string to have <=2 characters

工厂写法是有意为之的。MCP 构建指南说,serveStdio 每次需要实例时都会调用它,所以每次调用都必须返回新的 McpServer。SDK README 里更短的示例是用 server.connect(new StdioServerTransport()) 手动接线的。构建指南说,这样启动的服务器只能服务用 2025 年版旧握手开头的客户端,所以 serveStdio 更稳妥。

模型调用工具时发生了什么

模型看不到你的代码。它看到的是工具的名称、说明,以及由 inputSchema 生成的 JSON Schema,所以工具会不会被调用,全看这三样。把服务器接到宿主上之后,一次回答要经过六步。

一次工具调用,从提问到回答
  1. 宿主发送问题

    SDK 示例里的宿主是 VS Code。它把问题连同每个可用工具的名称、说明和输入参数结构一起发给模型。

  2. 模型挑选工具

    它判断 get-alerts 能回答这个问题,就发出一次调用,参数由它自己决定。

  3. 客户端调用你的服务器

    宿主内部的 MCP 客户端通过 stdio 发出一个 tools/call 请求。

  4. SDK 运行你的处理函数

    它先按 inputSchema 校验参数,再运行处理函数。

  5. 你的内容被送回去

    处理函数的 content 通过 stdout 作为 tools/call 的结果返回。

  6. 模型写出回答

    它读取文本块,写出你在聊天里看到的回复。

David Soria Parra 谈无状态规范和 v2 SDK

David Soria Parra 是 Anthropic 的技术人员,也是 MCP 的联合创建者。2026-07-28 版规范发布当天,他在 X 上宣布:MCP 变成了无状态协议,Python 和 TypeScript SDK 也为它发布了 v2.0.0。

这和本课的工厂函数对得上:没有会话把客户端绑在某个对象上,serveStdio 需要时就能新建一个 McpServer。

同一条帖子还把扩展列为另一项重点:MCP Apps、Tasks、Enterprise Managed Auth 等等,都是在特定领域使用 MCP 的方式。TypeScript SDK 在 10 月 23 日的 2.4.0 版又加了 Skills over MCP。自己动手写这类功能之前,先翻翻 SDK 的发布记录。

当天晚些时候,他又在 X 上感谢各 SDK 的维护者,并列出支持新规范的版本:TypeScript、Python 和 C# SDK 的 v2.0.0,以及 Go SDK 的 v1.7.0。协议都是同一套,按团队写的语言挑 SDK 就行。

部署 MCP 服务一下子简单多了,也更容易扩展。

David Soria Parra, Anthropic 技术人员,MCP 联合创建者,引文为译文 · X (2026年11月5日 查阅)
David Soria Parra(@dsp_)2026 年 7 月 28 日在 X 上发帖:很高兴宣布 MCP 2026-07-28 版发布。MCP 现在是无状态的,并为多轮往返的请求定义了语义,部署 MCP 服务一下子简单多了,也更容易扩展。MCP 现在有了扩展。Python、Typescript 和 C#(即将推出)SDK 都为新规范发布了 v2.0.0,用起来更顺手
David Soria Parra 在 X 上,2026 年 7 月 28 日
David Soria Parra(@dsp_)2026 年 7 月 28 日晚些时候在 X 上发帖:特别感谢各 SDK 的维护者,赶在发布时备好了带根本性升级的 v2.0.0。去拿 Typescript、Python 和 C# SDK 的 v2.0.0,以及支持新规范的 Go SDK v1.7.0
David Soria Parra 在 X 上,2026 年 7 月 28 日

X 官方嵌入卡片的截图,拍摄于 2026 年 11 月 5 日,时间为 UTC。两条帖子都被 X 用“Show more”截断了。点击截图可到 X 上打开原帖。

常见错误

  • 使用 console.log。在 stdio 上,stdout 就是协议通道,宿主会报 SyntaxError: Unexpected token ... is not valid JSON,引号里的那个字符是多出来那一行的第一个字符。改用 console.error。
  • 漏掉第 2 步里 package.json 的 type=module 那一行。
  • 依赖树里有两份 zod。TypeScript 可能报 TS2589: Type instantiation is excessively deep。运行 npm ls zod,让它只列出一个版本,某个依赖固定了别的版本时,在 package.json 里加一条 overrides。
  • 用 Node 18 或更旧的版本。SDK 的每个包都要求更新的运行时,故障排查页说 ReferenceError: crypto is not defined 就表示运行时太旧。
  • 照搬 1.x 的教程。如果它安装的是 @modelcontextprotocol/sdk,它的导入写法和这一课对不上。

动手试试

  • 在 Inspector 里用 { "state": "California" } 调用 get-alerts,把得到的消息和上面那条对比一下。
  • 在文件开头加一行 console.log("hello"),再运行一次 Inspector 命令,看看什么坏了,然后把它改成 console.error。
  • 在 createServer 里紧挨着第一个工具再加一个工具,确认 Tools 标签页里列出了两个。MCP 构建指南里的 get_forecast 就是现成的例子。

下一课:用 MCP Inspector 好好测一遍

你在 Inspector 里调用过一次工具了。第 3 课会把每个标签页、命令行模式,以及服务器出问题时该查什么都过一遍。想要这个服务器的 Python 版本,第 1 课就是。

想了解全貌,可以看什么是 MCP,里面讲了宿主、客户端和服务器是怎样配合的。

自测一下

  1. 当前版本的 TypeScript SDK 用哪个包来构建服务器?

    查看答案

    C. @modelcontextprotocol/server 当前的 SDK 是 @modelcontextprotocol/server,而 @modelcontextprotocol/sdk 是老教程里装的 1.x 版本。

  2. stdio 服务器的宿主报出 SyntaxError: Unexpected token ... is not valid JSON,最可能的原因是什么?

    查看答案

    A. 有一处 console.log 往 stdout 写了内容,而 stdout 是协议通道 在 stdio 上,stdout 传的是协议数据,多出来的一行会把它破坏掉,所以日志要用 console.error。

  3. 模型用 { "state": "California" } 调用 get-alerts,会发生什么?

    查看答案

    D. SDK 在你的处理函数运行之前就拒绝了它 SDK 会先按 inputSchema 检查参数,模型会读到校验失败的消息。

  4. 是什么决定了模型会不会调用你的工具?

    查看答案

    B. 工具的名称、描述和输入 schema 模型从来看不到你的代码,只能看到名称、描述,以及由 inputSchema 生成的 JSON Schema。

常见问题

还能用旧的 @modelcontextprotocol/sdk 包吗?

暂时可以。它是 1.x 系列,README 说在 2026 年 7 月 27 日 v2 发布后,它至少六个月内仍会收到缺陷修复和安全更新。新代码应该从 @modelcontextprotocol/server 开始。

构建指南里的 tsc 方案多了什么?

它把 src 编译到 build 文件夹,package.json 里多出一个 bin 条目、一个 files 列表和一个运行 tsc 的 build 脚本。之后宿主对 build/index.js 运行 node,就像指南里的 Claude Desktop 配置那样。

输入参数结构一定要用 Zod 吗?

不一定。README 说工具和提示词的结构使用 Standard Schema,所以 Zod v4、Valibot、ArkType 或任何兼容的库都可以。教程用的是 Zod,而且同一棵依赖树里有两份 Zod 会引起类型错误。

SDK 能在 Bun 或 Deno 上运行吗?

可以。README 说 SDK 能在 Node.js、Bun 和 Deno 上运行。用 bun add @modelcontextprotocol/server 或 deno add npm:@modelcontextprotocol/server 安装。

怎样让同一个服务器走 HTTP?

把同一个 createServer 工厂交给 SDK 的 HTTP 服务,而不是 serveStdio。教程说,要让一个端点服务很多客户端时就这样做。SDK 还发布了适配 Express、Fastify、Hono 和 Node 自带 HTTP 服务器的小型适配包。

stdio 服务器怎样打日志?

用写到 stderr 的 console.error,或者写到 stderr 或文件的日志库。宿主会自动捕获 stdio 服务器的 stderr,不需要额外接线。

资料来源

  1. MCP TypeScript SDK: README (2026年11月4日 查阅)https://github.com/modelcontextprotocol/typescript-sdk
  2. MCP TypeScript SDK docs: Build your first server (2026年11月4日 查阅)https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/get-started/first-server.md
  3. MCP TypeScript SDK docs: Plug into a real host (2026年11月4日 查阅)https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/get-started/real-host.md
  4. MCP TypeScript SDK docs: Troubleshooting (2026年11月4日 查阅)https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/troubleshooting.md
  5. MCP docs: Build an MCP server (2026年11月4日 查阅)https://modelcontextprotocol.io/docs/develop/build-server
  6. MCP docs: MCP Inspector (2026年11月4日 查阅)https://modelcontextprotocol.io/docs/tools/inspector
  7. MCP docs: Debugging (2026年11月4日 查阅)https://modelcontextprotocol.io/docs/2026-07-28/tools/debugging
  8. MCP Inspector: README (2026年11月5日 查阅)https://github.com/modelcontextprotocol/inspector
  9. MCP TypeScript SDK release v2.4.0 (2026年11月5日 查阅)https://github.com/modelcontextprotocol/typescript-sdk/releases/tag/v2.4.0
  10. David Soria Parra on X: the MCP 2026-07-28 release (2026年11月5日 查阅)https://x.com/dsp_/status/2082173429399142616
  11. David Soria Parra on X: the SDK releases that support the spec (2026年11月5日 查阅)https://x.com/dsp_/status/2082225962402402384

分享本节课

看看别的 MCP 服务器能做什么

到 Mindket 上浏览 MCP 服务器,和你刚写的这个比一比。

浏览 MCP 服务器

本节课的 Markdown 版本 · MCP 实战课:写、测试并接入 MCP 服务器 · 全部课程