
TypeScript SDK 的 JSON 响应模式用responseMode: json在 serverless/edge 运行时提供单次 JSON 响应【免费下载链接】typescript-sdkThe official TypeScript SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/GitHub_Trending/ty/typescript-sdk在 Model Context ProtocolMCP的现代 HTTP 服务路径中服务器默认以 SSE 流应答请求但这在无法长期保持流打开的 serverless / edge 运行时如按请求计费的函数平台中并不适用。本指南基于官方 TypeScript SDK 中的json-response示例examples/json-response/README.md完整讲解createMcpHandler({ responseMode: json })这一单次application/json响应模式它的语义、适用场景、完整可运行的服务端与客户端代码以及它在 SDK 源码中的底层实现原理。读完你将能自主决定何时用 JSON 模式替代 SSE 流式应答并能在自己的 Hono / Workers 等 HTTP 入口中落地同一配置。一、为什么需要「单次 JSON 响应」模式MCP 的现代2026-07-28 协议修订版per-request HTTP 服务路径中一次请求-响应交换的默认行为是如果 handler 在产生结果之前发出了任何 related 消息如 progress、logging 通知响应会升级为 SSE 流把中间消息和最终结果一起推送给客户端。这个「按需升级为流」的行为对常规部署非常友好但存在一类部署无法接受Serverless / edge 运行时函数平台的请求生命周期通常很短且很多平台无法保持一个流长期打开超时、网关缓冲、计费模型均不友好这类环境更希望每个请求对应一个完整的、可以立即返回的 JSON 响应体。responseMode: json正是为这类场景设计的开关createMcpHandler收到该选项后每个请求只返回一个application/json响应体而不是 SSE 流。代价是调用过程中途发出的通知会被丢弃——这一点在示例文档中明确说明handler 在构造时也会打印警告。需要强调的是该选项本质上是 HTTP-only 的它塑造的是 HTTP 响应体形态stdio 路径没有对应物stdio 传输也不会触及该选项见 server.ts 头部注释。二、三种响应模式一网打尽responseMode是createMcpHandler的选项之一其类型定义与完整语义位于 createMcpHandler.ts 的CreateMcpHandlerOptions中底层类型PerRequestResponseMode定义在 perRequestTransport.ts。三种取值如下取值行为典型适用场景auto默认单个 JSON body除非handler 在结果前发出 related 消息此时响应升级为 SSE 流常规部署兼顾简单与流式能力sse总是以 SSE 流应答需要确定性流式行为、且 handler 结果前可能不发出任何消息的场景json永不流式结果之前发出的 related 消息progress、logging 等一律丢弃只投递终态结果serverless / edge 等无法保持流打开的运行时两个重要的通用边界对三种模式均成立见选项文档subscriptions/listen订阅流总是通过 SSE 提供与responseMode无关——它本质是一条持续的变更事件流无法压缩成单次 JSON预分发的校验拒绝ladder 拒绝始终带着映射后的 HTTP 状态码直接以 JSON 应答不会被强制sse模式框进 200 流见 perRequestTransport.ts 中「ladder 拒绝在 dispatch window 内以映射状态码结算」的实现说明。仅作用于现代2026-07-28路径responseMode只塑造现代 per-request HTTP 路径的响应体。从 package.json 的注释可以确认responseModeshapes the modern (2026-07-28) per-request path only; 2025-era traffic goes through the stateless legacy fallback unaffected, so a legacy leg would not exercise the option.也就是说未携带 per-request_metaenvelope 的 2025 时代流量仍然走无状态 legacy 回退路径legacy: stateless默认完全不受该选项影响。三、服务端实战createMcpHandlerresponseMode: json完整的服务端示例代码在 server.ts核心只有几行import { serve } from hono/node-server; import { parseExampleArgs } from mcp-examples/shared; import { createMcpHonoApp } from modelcontextprotocol/hono; import { createMcpHandler, McpServer } from modelcontextprotocol/server; import * as z from zod/v4; function buildServer(): McpServer { const server new McpServer({ name: json-response-example, version: 1.0.0 }); server.registerTool( greet, { description: A simple greeting tool, inputSchema: z.object({ name: z.string() }) }, async ({ name }) ({ content: [{ type: text, text: Hello, ${name}! }] }) ); return server; } const { port } parseExampleArgs(); // responseMode: json is the point of this story — applies to the modern // (2026-07-28) per-request HTTP path. const handler createMcpHandler(buildServer, { responseMode: json }); // createMcpHonoApp() binds the endpoint behind localhost host/origin // validation by default, matching the framework factories defaults. const app createMcpHonoApp(); app.all(/mcp, c handler.fetch(c.req.raw)); serve({ fetch: app.fetch, port, hostname: 127.0.0.1 }, () { console.error([server] listening on http://127.0.0.1:${port}/mcp); });逐点拆解buildServer工厂createMcpHandler接受一个McpServerFactorycreateMcpHandler.ts每个 HTTP 请求都会调用工厂生成一个全新的 server 实例per-request serving 模型。工厂是跨时代共用的同一个工具定义既服务现代路径也服务无状态 legacy 回退。responseMode: json正是本文的主题配置。它被传入createMcpHandler后最终经由invokeseaminvoke.ts交给PerRequestHTTPServerTransport由其决定响应体形态。构造期警告当选项为json时createMcpHandler会在构造时打印一条console.warncreateMcpHandler.tsresponseMode: json drops mid-call notifications. subscriptions/listen streams are always served over SSE regardless; other notifications emitted before a result are dropped.挂载方式示例使用modelcontextprotocol/hono的createMcpHonoApp()创建 Hono 应用再app.all(/mcp, c handler.fetch(c.req.raw))把 fetch 形状的 handler 绑定到/mcp路由。createMcpHonoApp默认带 localhost host/origin 校验与框架工厂默认行为一致。handler.fetch是 web-standard 面Workers/Bun/Deno 均可直接export defaultExpress/Fastify/原生node:http则用toNodeHandler(handler)来自modelcontextprotocol/node包装一次见 createMcpHandler.ts 的注释说明。四、客户端实战断言 JSON 响应 标准 Client 无缝兼容示例的客户端client.ts做了两件事先用低层 HTTP 探测断言响应确实是application/json而非text/event-stream再用未做任何修改的标准Client验证高层兼容性import { check, parseExampleArgs } from mcp-examples/shared; import { Client, isJsonContentType, StreamableHTTPClientTransport } from modelcontextprotocol/client; const { url } parseExampleArgs(); const client new Client({ name: json-response-example-client, version: 1.0.0 }, { versionNegotiation: { mode: auto } }); await client.connect(new StreamableHTTPClientTransport(new URL(url))); // Low-level: a 2026-07-28 (envelope) request should come back as plain JSON — // the JSON content-type assertion is the point of the story. const probe await fetch(url, { method: POST, headers: { content-type: application/json, accept: application/json, text/event-stream, mcp-protocol-version: 2026-07-28, mcp-method: tools/list }, body: JSON.stringify({ jsonrpc: 2.0, id: 1, method: tools/list, params: { _meta: { io.modelcontextprotocol/protocolVersion: 2026-07-28, io.modelcontextprotocol/clientInfo: { name: probe, version: 1.0.0 }, io.modelcontextprotocol/clientCapabilities: {} } } }) }); check.equal(isJsonContentType(probe.headers.get(content-type)), true); check.equal(probe.status, 200); // High-level: the regular Client works unchanged. const result await client.callTool({ name: greet, arguments: { name: json } }); check.equal(result.content?.[0]?.type text ? result.content[0].text : , Hello, json!); await client.close();要点低层探测请求携带现代2026-07-28信封的_meta、mcp-protocol-version与mcp-method头这是现代 per-request 路径的入口形态响应断言Content-Type为 JSON用isJsonContentType做媒体类型判定而非简单字符串比较、状态码 200——这正是「JSON 模式」的验证核心高层Client完全无感知ClientStreamableHTTPClientTransport照常工作client.callTool能拿到Hello, json!。也就是说JSON 响应模式对标准 SDK 客户端是透明的服务端切换响应形态不需要客户端配合。五、运行示例示例位于 pnpm workspace 内package.jsonexamples/json-response/package.json提供了两个脚本scripts: { server: tsx server.ts, client: tsx client.ts }典型运行流程在仓库根目录安装依赖后启动服务端pnpm --filter mcp-examples/json-response server或进入 examples/json-response 目录后pnpm server监听http://127.0.0.1:port/mcp另开终端运行客户端pnpm --filter mcp-examples/json-response client客户端会用上文的低层探测与高层调用双重验证 JSON 响应行为。parseExampleArgs()来自 workspace 内的 mcp-examples/shared负责统一解析端口/URL 参数。六、底层原理JSON 模式在 per-request transport 中如何实现responseMode从选项到行为的完整链路为createMcpHandler (选项解析) → serveModern → invoke (invoke.ts) → PerRequestHTTPServerTransport (perRequestTransport.ts) → send() 路径决定响应形态关键实现在 perRequestTransport.ts 的send()方法第 241-327 行。发送方dispatch 层/协议层发来的每条消息会先经过分类终态响应result 或 error若当前没有打开 SSE 流、且模式不是sse则以Response.json(message, { status: 200, headers: { Content-Type: application/json } })结算整个交换第 310-313 行与在途请求相关的非终态消息mid-call notification 或 server-to-client request这里就是json模式的分水岭——// A message related to the in-flight request that is not its terminal // response: a mid-call notification or a server-to-client request // emitted by the handler. if (this._responseMode json) { // JSON responses cannot carry mid-call messages; they are dropped. return; }JSON 响应体没有承载中间消息的通道因此相关消息被直接丢弃第 319-322 行而在auto模式下同一位置会触发upgradeToSse()第 323-325 行——这正是「自动模式按需升级为 SSE、JSON 模式永不流式」的底层分叉点。此外交换的 HTTP 状态码映射也有讲究只有 dispatch window 内产生的错误校验 ladder、era 注册表 gate 等才按 ladder 表映射 HTTP 状态handler 产出的错误在 JSON 模式下保持在 HTTP 200 的 JSON-RPC error 体内第 260-313 行的注释详尽说明了该规则。七、测试验证三种模式行为被单元测试钉死SDK 在 createMcpHandler.test.ts 中用三个用例钉死了responseMode的行为默认惰性升级handler 在结果前发出 related 通知时响应升级为 SSE 流Content-Type含text/event-streambody 含notifications/progressjson永不流式且丢弃 mid-call 通知对同一个「先发 progress 再返回结果」的工具调用responseMode: json下响应Content-Type为application/json、状态 200、body不含notifications/progress但包含最终结果文本——这正是 client.ts 断言逻辑的测试侧印证sse即使 handler 结果前不发任何消息也强制流式Content-Type为text/event-stream。如果你的 handler 会在结果前发送 progress/logging 等通知且这些通知对调用方有业务价值请避免使用json模式或选择auto/sse反之若你的工具是「单次入参、单次出参、无需中间反馈」的形态且部署在无法保持流的 serverless/edge 运行时responseMode: json就是官方 SDK 提供的标准解法。八、总结responseMode: json让现代2026-07-28per-request HTTP 路径每个请求只返回一个application/json响应体是 serverless / edge 运行时无法保持 SSE 流打开时的官方应对方案代价明确结果之前发出的相关消息progress、logging 等被丢弃仅投递终态结果subscriptions/listen订阅流不受影响、始终走 SSEHTTP-only无 stdio 等价物且只影响现代路径2025 时代流量走无状态 legacy 回退不受影响配置极简createMcpHandler(buildServer, { responseMode: json })标准 SDKClient无需任何改动即可兼容三种模式auto/sse/json的取舍、底层send()分叉实现与单元测试均已在上文给出仓库内源码位置可自行深入研读。【免费下载链接】typescript-sdkThe official TypeScript SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/GitHub_Trending/ty/typescript-sdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考