开始之前
这一课照着 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 教程分成了两代。
| 包 | SDK 系列 | 在哪里会遇到 |
|---|---|---|
@modelcontextprotocol/server | v2,当前的稳定系列 | 官方文档和这一课 |
@modelcontextprotocol/client | v2,用于连接服务器的代码 | 客户端和测试脚本 |
@modelcontextprotocol/sdk | v1.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');
- 用
node --version检查 Node,版本必须是 20 或更高。 - 用
mkdir weather && cd weather创建项目目录,再运行npm init -y,然后运行npm pkg set type=module。type=module这个设置不能省,因为 SDK 只提供 ES 模块。 - 用
npm install @modelcontextprotocol/server zod tsx安装 SDK、Zod 和 tsx,再用mkdir src建源码目录。 - 新建
src/index.ts,把上面的代码粘进去。 - 在项目根目录用
npx tsx src/index.ts启动服务器。它会往 stderr 打印weather MCP server running on stdio,然后停在那里等待。按 Ctrl+C 停止。 - 运行
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,所以工具会不会被调用,全看这三样。把服务器接到宿主上之后,一次回答要经过六步。
宿主发送问题
SDK 示例里的宿主是 VS Code。它把问题连同每个可用工具的名称、说明和输入参数结构一起发给模型。
模型挑选工具
它判断
get-alerts能回答这个问题,就发出一次调用,参数由它自己决定。客户端调用你的服务器
宿主内部的 MCP 客户端通过 stdio 发出一个
tools/call请求。SDK 运行你的处理函数
它先按
inputSchema校验参数,再运行处理函数。你的内容被送回去
处理函数的
content通过 stdout 作为tools/call的结果返回。模型写出回答
它读取文本块,写出你在聊天里看到的回复。
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 服务一下子简单多了,也更容易扩展。
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,里面讲了宿主、客户端和服务器是怎样配合的。
自测一下
当前版本的 TypeScript SDK 用哪个包来构建服务器?
查看答案
C.
@modelcontextprotocol/server当前的 SDK 是@modelcontextprotocol/server,而@modelcontextprotocol/sdk是老教程里装的 1.x 版本。stdio 服务器的宿主报出
SyntaxError: Unexpected token ... is not valid JSON,最可能的原因是什么?查看答案
A. 有一处
console.log往 stdout 写了内容,而 stdout 是协议通道 在 stdio 上,stdout 传的是协议数据,多出来的一行会把它破坏掉,所以日志要用console.error。模型用
{ "state": "California" }调用get-alerts,会发生什么?查看答案
D. SDK 在你的处理函数运行之前就拒绝了它 SDK 会先按
inputSchema检查参数,模型会读到校验失败的消息。是什么决定了模型会不会调用你的工具?
查看答案
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,不需要额外接线。
资料来源
- MCP TypeScript SDK: README https://github.com/modelcontextprotocol/typescript-sdk
- MCP TypeScript SDK docs: Build your first server https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/get-started/first-server.md
- MCP TypeScript SDK docs: Plug into a real host https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/get-started/real-host.md
- MCP TypeScript SDK docs: Troubleshooting https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/troubleshooting.md
- MCP docs: Build an MCP server https://modelcontextprotocol.io/docs/develop/build-server
- MCP docs: MCP Inspector https://modelcontextprotocol.io/docs/tools/inspector
- MCP docs: Debugging https://modelcontextprotocol.io/docs/2026-07-28/tools/debugging
- MCP Inspector: README https://github.com/modelcontextprotocol/inspector
- MCP TypeScript SDK release v2.4.0 https://github.com/modelcontextprotocol/typescript-sdk/releases/tag/v2.4.0
- David Soria Parra on X: the MCP 2026-07-28 release https://x.com/dsp_/status/2082173429399142616
- David Soria Parra on X: the SDK releases that support the spec https://x.com/dsp_/status/2082225962402402384


