深入解析 @modelcontextprotocol/fastify:用 Fastify 承载 MCP 服务器的官方适配器
【免费下载链接】typescript-sdkThe official TypeScript SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/GitHub_Trending/ty/typescript-sdk
导读
@modelcontextprotocol/fastify是官方 TypeScript SDK(typescript-sdk)中面向 Fastify 框架的 MCP 服务器适配层,用于将 @modelcontextprotocol/server 的能力以 Fastify 应用的形式对外提供。阅读本文后,你将掌握:如何用createMcpFastifyApp()一键创建带安全默认值的 MCP Fastify 应用、如何挂载 Streamable HTTP 端点、如何通过 Host 与 Origin 头部校验防御 DNS rebinding 攻击,以及该包在 SDK v2 演进中引入的 ESM/CJS 双构建与 2026-07-28 规范支持等关键变更。
包定位:薄集成层而非 MCP 实现
从 README.md 的定位描述与 package.json 的依赖声明可以看出,该包自身不实现任何 MCP 协议逻辑:
dependencies为空,核心能力来自两个peerDependencies:@modelcontextprotocol/server与fastify;- 它只做两件事:创建带 MCP 合理默认值的 Fastify 应用、为 localhost 服务器提供 DNS rebinding 防护;
- 与 Express 适配器、Hono 适配器 遵循完全相同的适配模式,按变更记录(
2.0.0-alpha.1)所述,该包即是在参考二者后新增的 Fastify 版本。
包的公开导出非常精简,全部来自 src/index.ts:
export * from './fastify'; export * from './middleware/hostHeaderValidation'; export * from './middleware/originValidation';实际对外 API 共 6 个:createMcpFastifyApp、hostHeaderValidation、localhostHostValidation、originValidation、localhostOriginValidation。
安装与前置条件
npm install @modelcontextprotocol/server @modelcontextprotocol/fastify fastify # 若需要基于 Node.js (IncomingMessage/ServerResponse) 的 MCP Streamable HTTP: npm install @modelcontextprotocol/node安装前提(以当前仓库为准):包要求 Node.js>=20(见 package.json 的engines字段),模块系统为"type": "module",同时通过exports的import/require双条件支持 ESM 与 CommonJS 两种消费方式(详见下文“构建与发布”)。
createMcpFastifyApp:带安全默认值的应用工厂
核心入口是 src/fastify.ts 中的createMcpFastifyApp(options?)。它的设计哲学是“默认安全”:只要绑定在 localhost 类地址上,就自动挂载 DNS rebinding 防护钩子。
选项参数说明
| 选项 | 类型 | 默认值 | 行为 |
|---|---|---|---|
host | string | '127.0.0.1' | 绑定主机名。为'127.0.0.1'、'localhost'或'::1'时自动启用 DNS rebinding 保护 |
allowedHosts | string[] | 无 | 显式提供 Host 校验白名单(端口无关,仅主机名)。IPv6 需带方括号(如'[::1]')。常用于绑定'0.0.0.0'/'::'但仍想限制合法主机名时 |
allowedOrigins | string[] | 无 | 显式提供 Origin 校验白名单(端口无关,仅主机名,约定与allowedHosts一致)。省略时对 localhost 类绑定自动启用 Origin 校验 |
安全默认值的武装逻辑
从 src/fastify.ts 的实现可以归纳出以下决策阶梯:
- Host 校验:
- 若显式传入
allowedHosts,则用hostHeaderValidation(allowedHosts)挂载onRequest钩子; - 否则若
host属于['127.0.0.1', 'localhost', '::1'],自动挂载localhostHostValidation(); - 否则若
host为'0.0.0.0'或'::'(绑定所有网卡),打印一条警告日志,提示应使用allowedHosts限制主机或改用认证保护服务器。
- 若显式传入
- Origin 校验(
2.0.0-alpha.4起):- 若显式传入
allowedOrigins,挂载originValidation(allowedOrigins); - 否则对 localhost 类绑定自动挂载
localhostOriginValidation()——没有Origin头的请求放行(非浏览器 MCP 客户端不受影响),带Origin但主机名不在白名单或无法解析(包括不透明的nullorigin)的请求以403拒绝。
- 若显式传入
典型用法示例
import { createMcpFastifyApp } from '@modelcontextprotocol/fastify'; // 默认:绑定 127.0.0.1,自动启用 Host + Origin 校验 const app = createMcpFastifyApp(); // 自定义 host:绑定 0.0.0.0 时不自动启用 DNS rebinding 保护 const appOpen = createMcpFastifyApp({ host: '0.0.0.0' }); // 绑定 localhost 时保护仍然生效 const appLocal = createMcpFastifyApp({ host: 'localhost' }); // 非 localhost 绑定 + 显式白名单 const app = createMcpFastifyApp({ host: '0.0.0.0', allowedHosts: ['myapp.local', 'localhost'], });注意:createMcpFastifyApp内部直接调用Fastify()创建实例,Fastify 默认就会解析 JSON 请求体,因此 MCP Streamable HTTP 端点无需额外 body 解析中间件(见 src/fastify.ts 的注释)。
Streamable HTTP 端点挂载
将 MCP 服务器挂到 Fastify 路由上的完整示例(来自 README.md):
import { createMcpFastifyApp } from '@modelcontextprotocol/fastify'; import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node'; import { McpServer } from '@modelcontextprotocol/server'; const app = createMcpFastifyApp(); const mcpServer = new McpServer({ name: 'my-server', version: '1.0.0' }); app.post('/mcp', async (request, reply) => { // 无状态示例:每个请求新建 transport。 // 有状态模式(sessions)下应保留并复用 transport 实例。 const transport = new NodeStreamableHTTPServerTransport({ sessionIdGenerator: undefined }); await mcpServer.connect(transport); // 客户端关闭连接(如 SSE 流式传输期间)时清理 transport reply.raw.on('close', () => { transport.close(); }); await transport.handleRequest(request.raw, reply.raw, request.body); });实战注意事项(README 明确给出):
- 无状态模式下若每个请求都新建
McpServer,也应在close处理器中调用mcpServer.close(); - 若希望以
405 Method Not Allowed拒绝非 POST 请求,可为 GET/DELETE 添加返回 JSON-RPC 错误响应的路由; - 更完整的 Fastify 托管方案可参考 serving/fastify.md 与可运行的 examples/fastify 示例。
Host 头部校验:DNS rebinding 防护
原理与动机
DNS rebinding 攻击通过操控 DNS 让一个域名解析到127.0.0.1,使恶意网页能够绕过同源策略访问本机服务。对没有认证、没有 HTTPS 的 localhost/开发服务器而言,这是需要重点防御的攻击面——这正是 src/middleware/hostHeaderValidation.ts 中注释强调的适用场景。
两个 Hook
import { hostHeaderValidation, localhostHostValidation } from '@modelcontextprotocol/fastify'; // 自定义白名单(端口无关;IPv6 带方括号) app.addHook('onRequest', hostHeaderValidation(['localhost', '127.0.0.1', '[::1]'])); // 便捷钩子:只允许 localhost / 127.0.0.1 / [::1] app.addHook('onRequest', localhostHostValidation());实现上(见 src/middleware/hostHeaderValidation.ts),钩子将request.headers.host交给服务器包导出的validateHostHeader(来自@modelcontextprotocol/server,导出见 packages/server/src/index.ts),校验失败时以403返回 JSON-RPC 格式错误:
{ "jsonrpc": "2.0", "error": { "code": -32000, "message": "<校验失败原因>" }, "id": null }localhostHostValidation()则直接复用服务器包提供的localhostAllowedHostnames()作为白名单。
测试用例印证
test/fastify.test.ts 覆盖了完整行为矩阵:
- 仅允许
localhost时,host: 'evil.com:3000'的请求返回403,响应体为 JSON-RPC 错误且code === -32_000; host: 'localhost:3000'正常放行(200);- 多白名单场景下
127.0.0.1:8080与myapp.local均放行; localhostHostValidation()分别允许localhost:3000、127.0.0.1、[::1]:3000,拒绝evil.com:3000。
Origin 头部校验:面向浏览器的跨站防护
2.0.0-alpha.4引入的 Origin 校验(PR #2286)是 Host 校验的补充:浏览器在跨域请求中会携带Origin头,校验它可以进一步防御 DNS rebinding 与跨站请求伪造(CSRF)。
核心实现位于 src/middleware/originValidation.ts,同样提供两个钩子:
import { originValidation, localhostOriginValidation } from '@modelcontextprotocol/fastify'; // 自定义 origin 白名单(无 scheme、无端口;IPv6 带方括号) app.addHook('onRequest', originValidation(['localhost', '127.0.0.1', '[::1]'])); // 便捷钩子:仅允许 localhost / 127.0.0.1 / [::1] 的 origin app.addHook('onRequest', localhostOriginValidation());行为约定(与 src/fastify.ts 注释及 CHANGELOG 一致):
- 无
Origin头 → 放行:非浏览器的 MCP 客户端(如 CLI、SDK 直连)通常不发送该头,不受影响; Origin存在但主机名不在白名单、或无法解析(含不透明的nullorigin)→ 403 拒绝;- 校验同样委托给服务器包提供的
validateOriginHeader与localhostAllowedOrigins(导出见 packages/server/src/index.ts),底层是框架无关的辅助函数validateOriginHeader/originValidationResponse。
这套 Origin 校验并非 Fastify 独有——同一 PR 同时为 Express、Hono 适配器增加了对应中间件与allowedOrigins选项,并为node:http裸服务器适配器(@modelcontextprotocol/node)补齐了hostHeaderValidation/originValidation请求守卫。
构建与发布:ESM 与 CommonJS 双构建
2.0.0-beta.2起(PR #2405),所有包改为同时发布 ESM 与 CommonJS 两种产物:
- 通过 tsdown 的
format: ['esm', 'cjs']同时产出.mjs/.d.mts与.cjs/.d.cts(见 tsdown.config.ts); exportsmap 增加require条件,使require('@modelcontextprotocol/fastify')在 CommonJS 消费方也能正常工作;- 输出扩展名在各包间统一规范化,公开导入路径不变。
从 package.json 可以看到完整的条件导出结构:
"exports": { ".": { "import": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }, "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" } } }, "main": "./dist/index.cjs", "types": "./dist/index.d.mts"此外2.0.0-alpha.3(PR #1898)为包增加了顶层types字段(client/server 上另有typesVersions),使采用旧式moduleResolution: "node"的消费方也能解析类型声明;exportsmap 对nodenext/bundler解析仍是权威来源。2.0.0-alpha.2则修复了 tsdown 的 exports 解析问题。
版本演进时间线:从 alpha 到 2.0.0
结合 CHANGELOG.md,该包的演进脉络如下:
| 版本 | 关键变更 |
|---|---|
2.0.0-alpha.1 | 首次引入 Fastify 中间件适配器(PR #1536),遵循 Express/Hono 适配器模式 |
2.0.0-alpha.2 | 修复 tsdown exports 解析(PR #1840) |
2.0.0-alpha.3 | 增加顶层types字段与typesVersions,兼容旧式moduleResolution: "node"(PR #1898) |
2.0.0-alpha.4 | 新增 Origin 头部校验:originValidation/localhostOriginValidation中间件与allowedOrigins选项(PR #2286) |
2.0.0-beta.2 | ESM 与 CommonJS 双构建(PR #2405) |
2.0.0-beta.1/2.0.0 | 首个支持MCP 2026-07-28 规范修订的 SDK v2 正式版(PR #2402) |
各版本均与@modelcontextprotocol/server对应版本同步发布(CHANGELOG 中每个版本都带有对该依赖的Updated dependencies条目)。
向 v2 与 2026-07-28 规范迁移
2.0.0是 SDK v2 的首个正式版本,核心是支持 MCP 2026-07-28 规范修订。CHANGELOG 明确指引读者参考两份迁移文档:
- docs/migration/upgrade-to-v2.md:从 v1 升级到 v2 的完整指南;
- docs/migration/support-2026-07-28.md:采用 2026-07-28 规范修订的指南。
对于使用本适配器的开发者,升级到 v2 后 API 表面保持稳定(createMcpFastifyApp与各校验钩子签名不变),新增的allowedOrigins选项与默认启用的 Origin 校验属于行为层面的增强:只要绑定在 localhost 类地址,应用就会自动获得 Host + Origin 双重防护,而对非浏览器客户端(不发送Origin头)透明无感。
小结
@modelcontextprotocol/fastify用极薄的 API 表面(一个工厂函数加四个校验钩子)为 Fastify 用户补齐了 MCP 服务器托管的三件关键能力:合理的默认绑定与防护、Streamable HTTP 端点挂载、以及面向 localhost/开发场景的 Host + Origin 双重校验。其实现完全依赖@modelcontextprotocol/server的框架无关校验辅助函数,保持了一致的适配模式与安全语义;配合 v2 的 ESM/CJS 双构建,可以无缝接入 ESM 或 CommonJS 的 Fastify 项目。
【免费下载链接】typescript-sdkThe official TypeScript SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/GitHub_Trending/ty/typescript-sdk
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考