Bun MCP
此存储库的目标是原型化 MCP(模型上下文协议) 服务器使用 包子 运行时并通过VS使用其工具 代码复制聊天代理模式。
A screen recording showing the resulting MCP server in action
我首先阅读了模型上下文协议文档。 在MCP文档的命名中,我们将使用以下元素:
- 主机与客户端:VS Code与Copilot在代理模式下聊天
- 服务器:此存储库中实现的脚本
对于此设置,文档有一个特定的学习路径:
MCP服务器通过公开类似于REST端点和LLM的工具来工作 如果MCP客户端确定用户提示,则可以调用这些工具 可以从该工具能够提供的数据中受益。
文档页面提供了一个示例天气服务MCP服务器,这是一个 这是一个很好的例子,因为LLM不能提供天气信息 天气预报是实时数据,因此无法通过 LLM
我将构建一个能够管理MarkDown文件中待办事项列表的MCP服务器。 MCP服务器的目标是为用户提供创建和 通过允许他们添加、切换和删除待办事项来维护此文档。
值得一提的是,MCP服务器可以提供不同类型的数据 对于MCP客户端:
- 资源:文件和数据blob的内容
- 工具:LLM调用和使用以下结果的方法
- 提示:预定义的提示,帮助改进用户提示以获得最佳结果
与文档页面中一样,我的MCP服务器将只专注于提供工具。
与文档页面不同,我将使用Bun而不是Node。 尽管如此,我可能仍然能够从参考中受益 实施 这里.
教程页面包括一个基于SDK包的服务器实现。 我会先走这条路,但最后,我想建立一个服务器 从头开始,实现原始协议。
据我所知,这应该不是很难,因为服务器有能力 通过标准I/O和服务器发送的事件进行通信,这两者都是基本的 无需任何依赖即可实现。
- \[\]删除SDK包,使用直接MCP协议重建服务器
在他们之前,我将首先添加 @modelcontextprotocol/sdk 包裹 作为依赖使用 bun add @modelcontextprotocol/sdk.
Bun将创建 package.json 与我所有的个人项目一样,我 我正在将版本更改为 latest 这样项目就不会陷入困境 旧版本。
package.json:
{
"dependencies": {
"@modelcontextprotocol/sdk": "latest"
}
}我还添加了一个 .gitignore 文件并忽略 node_modules 和 bun.lock. 我不做依赖性销售,也不需要锁文件,因为所有 无论发生什么,依赖项都应该始终安装在最新版本。
服务器的肉和土豆将存储在一个名为的新文件中 index.ts. 我假设在客户端配置中,我将能够通过 命令和参数,如果是这样的话,将使它变得非常容易 只是指定 bun .作为命令和参数对。
我的脚本将是ESM,不会像往常一样有构建步骤。 它将通过Bun的原生TypeScript支持使用TypeScript,并且不会覆盖 Bun的默认TypeScript配置。
此基本MCP SDK import 服务器清单规范如下:
index.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({
name: "to-do",
version: "0.0.0",
capabilities: {
tools: {},
},
});下一步是注册MCP服务器要公开的工具。 我将从一个开始- list-todos 现在它将返回硬编码数据。
server.tool("list-todos", "Lists all to-do items in the TODO.md file", () => {
return {
content: [
{
type: "text",
text: "- [ ] Do the dishes\n- [ ] Go grocery shopping\n- [ ] Plan the weekend trip",
},
],
};
});定义了工具后,是时候配置服务器传输了,以便 客户端知道如何与服务器通信。 这需要一个新的 import 在文件顶部,我选择使用标准 I/O用于此。
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
// …
const transport = new StdioServerTransport();
await server.connect(transport);此时,是时候测试MCP服务器了。 文档页面演示了如何使用Claude完成此操作,因此我将推迟 在其他地方学习如何在VS Code中配置它。
MCP上的VS Code文档列出了几个选项: https://code.visualstudio.com/docs/copilot/chat/mcp-servers#\_add-mcp服务器
我更喜欢工作区配置选项,所以我创建了一个空的 .vscode/mcp.json 此存储库的工作区中的文件,并在 新的VS代码选项卡。
VS Code识别此特殊路径,并在以下位置显示一个名为“添加服务器”的按钮 文件编辑器区域的右下角。
我单击了按钮并选择了Command(stdio)选项。
在这一点上,必须进行一些摆弄和实验。 我首先尝试的命令只是 bun,但我没有意识到这种流动会 不要要求我为这个命令辩护。 它询问的另一件事是服务器名称,我把它放在哪里 to-do.
服务器启动失败,在MCP的输出窗格中:待办事项通道I 可以理解为什么-VS Code主机执行了命令并开始解释 其标准I/O流用于传输。
但由于命令只是 bun,当否时,它会打印默认输出 提供或发现脚本。 这些行未能解析为MCP消息,因此连接失败 成立。
这是不正确的配置:
{
"servers": {
"to-do": {
"type": "stdio",
"command": "bun",
"args": []
}
}
}此时,我开始调整JSON代码本身,而不是依赖于 VS代码UI流。
我想一个简单的修复方法是将命令更改为 bun . 因此,Bun 调用并尝试启动 index.ts.
我点击了VS code放在服务器条目的重启代码镜头。 这再次导致了一个错误。
似乎定义为命令的MCP服务器没有在 工作区目录。 为了验证这一点,我将命令更改为 pwd 并重新运行它。 此打印 /Users/tom 证实了我的怀疑。
从这里有多种选择。 我不想硬编码脚本的完整路径作为Bun的参数, 所以我想我可以依靠VS代码配置替换: https://code.visualstudio.com/docs/reference/variables-reference
我将命令更改为 echo '${workspaceFolder}' 看看它是否会打印出来 在“输出”窗口中输入变量的值,然后再次单击“重新启动”。
这打印出了预期的目录! 当然,服务器还没有启动,但此时我知道了最终的结果 命令必须是 bun ${workspaceFolder}. 我惊讶地发现这也不起作用,但我很快意识到我应该通过考试 这 workspaceFolder 变量作为参数 args 取而代之的是现场。
我将命令更改为 echo 再次确保一切正常 按预期工作:
{
"servers": {
"to-do": {
"type": "stdio",
"command": "echo",
"args": ["${workspaceFolder}"]
}
}
}此打印 [warning] Failed to parse message: "/Users/tom/Desktop/bun-mcp\n" 让我知道变量替换和命令传递有效。
我可以改变 command 向 bun 现在,让服务器启动。 服务器入口顶部的代码镜头变为“正在运行…”,我看到一阵骚动 输出选项卡中的活动:
[info] Connection state: Starting
[info] Starting server from LocalProcess extension host
[info] Connection state: Starting
[info] Connection state: Running
[info] Discovered 1 tools这意味着我的MCP服务器及其唯一工具被发现,我可以尝试提示 这应该会在代理模式下在VS Code GitHub Copilot聊天窗格中触发它。
我使用命令右侧的Copilot图标打开了GitHub Copilot聊天 VS Code窗口顶部中心的栏。
它以询问模式启动,所以我将该开关切换到代理。 这为聊天编辑器带来了一些新图标:开始语音聊天,选择工具 以及发现可用工具/新工具(如果不适用,则隐藏)。
我点击了“选择工具”按钮,并查看了打开的列表 to-do 服务器已列出并与其一起检查 list-todos 工具!
这意味着我的提示现在应该可以使用这个工具了。 我问Copilot:
我的清单上有什么待办事项?
它要么不够聪明,要么太聪明,因为它使用了复选框列表 在这个README文件中(该文件作为参考自动包含在聊天中 如提示输入区域顶部的项目所示),并通过列出 其中的待办事项复选框。
我点击了旁边的眼睛图标 readme.md 删除当前文件引用 从提示上下文中重新运行相同的提示。
这次,Copilot Chat问我是否要允许 to-do MCP服务器 运行 list-todos 该工具具有“继续”和“取消”按钮。 我选择了“继续”按钮旁边的V形图标,并选择了“始终允许进入” 此工作区允许我的MCP服务器在 从现在开始使用此存储库目录。
Copilot聊天更改为表示它运行了 list-todos 我的工具 to-do 服务器并返回:
您当前的待办事项列表包含以下项目: `洗碗去杂货店购物` 计划周末旅行 如果您想添加、删除或更新任何这些任务,请告诉我!
有趣的是,MarkDown复选框不会在Copilot聊天UI中呈现,所以我 我想我将不得不使用表情符号,当我改变工具不返回 硬编码数据。
此外,尽管我有MCP服务器,Copilot相信它可以帮助我编辑此列表 还没有公开这样做的工具。 我会把这归结为幻觉/不够聪明的提示 MCP服务器交互。
下一步,我将添加一个用于创建新待办事项和更改的工具 现有的列出待办事项的工具可以使用内存存储,这样我 可以添加并列出此新待办事项。
当涉及到使用参数注册工具时,MCP SDK似乎是绑定的 Zod用于MCP工具参数结构的模式验证。 我不喜欢这样,在我未来的实施中,我会实施MCP 通过手动协议,我将放弃对Zod的依赖,但现在我会遵守并 使用它:
bun add zod
package.json:
{
"dependencies": {
"@modelcontextprotocol/sdk": "latest",
"zod": "lates"
}
}我是这样改变的 index.ts 为了实现这一点:
import { z } from "zod";
// …
const todos: { name: string; isChecked: boolean }[] = [];
server.tool("list-todos", "Lists all to-do items in the TODO.md file", () => {
return {
content: [
{
type: "text",
text: todos
.map((todo) => `${todo.isChecked ? "✅" : "❎"} ${todo.name}`)
.join("\n"),
},
],
};
});
server.tool(
"add-todo",
"Adds a new to-do item to the TODO.md file",
{
name: z.string().describe("The name of the to-do item"),
},
({ name }) => {
const newTodo = { name, isChecked: false };
todos.push(newTodo);
return {
content: [
{
type: "text",
text: `Added new to-do item: ${newTodo.name}`,
},
],
};
}
);
// …做出这些更改后,我去了 mcp.json 再次单击选项卡并按下 重新启动代码镜头操作以使更改生效。
另一个代码镜头项目更改为“2个工具”,表示更改了 确实发生了,并得到了“输出”窗格日志的进一步证实 MCP:待办事项通道,现在添加了以下行:
[info] Stopping server to-do
[info] Connection state: Stopped
[info] Starting server to-do
[info] Connection state: Starting
[info] Starting server from LocalProcess extension host
[info] Connection state: Starting
[info] Connection state: Running
[info] Discovered 2 tools我将当前的文件引用保存在Copilot聊天上下文之外,并询问 它为我添加了一个新的待办事项:
添加待办事项以购买晚餐杂货
系统再次提示我继续或取消 to-do MCP服务器呼叫, 这一次为 add-todo 工具,我觉得很惊讶,我想这 检查是按每个工具而不是按服务器进行的 最初预计。
我再次在“继续”下拉菜单中选择了“始终在此工作区”选项。
副驾驶回答:
你的清单上增加了一个新的待办事项“购买晚餐杂货”。 如果你需要查看、更新或删除任何待办事项,请告诉我!
我扩展了“Ran” add-todo“Copilot响应顶部的框进行深入分析。 它根据提示打印了它制作的输入以及来自的输出 MCP服务器。
输入:
{
"name": "Buy groceries for dinner"
}输出:
新增待办事项:购买晚餐杂货
接下来,我问我的清单上有什么待办事项:
我的清单上有什么待办事项?
这一次,我没有被提示允许工具运行,它运行时没有中断, 所以提示似乎真的是针对每个工具的。
副驾驶回答:
您当前的待办事项列表包括: `` 买食品杂货当晚餐 如果你想添加、删除或更新任何待办事项,请告诉我!
检查工具箱以了解详细信息:
输入:
{}输出:
❎ 买食品杂货当晚餐
因此,Copilot LLM似乎将此工具响应重新格式化为 MarkDown清单本身就意味着我们与损坏的MarkDown发生了冲突 再次在VS Code Copilot聊天中渲染。
我不确定是否可以使用工具来防止这种情况,但MCP服务器 可能会暴露一个提示,该提示将改写简单的查询 将待办事项列表视图转换为更丰富的查询,指示Copilot将列表格式化为 特定方式,可能使用我在代码中使用的表情符号,而不是 MarkDown检查表。
- \[\]显示一个提示以丰富用户提示,从而避免MarkDown列表呈现
完成待办事项列表管理流程还剩下两件事:切换 以及删除待办事项。
我添加了一个基于关键字切换待办事项的工具,如下所示:
server.tool(
"toggle-todo",
"Toggles the completion status of a to-do item",
{
keyword: z
.string()
.describe("A keyword in the name of the to-do item to toggle"),
},
({ keyword }) => {
const todo = todos.find((todo) => todo.name.includes(keyword));
if (!todo) {
return {
content: [
{
type: "text",
text: `To-do item containing "${keyword}" not found.`,
},
],
};
}
todo.isChecked = !todo.isChecked;
return {
content: [
{
type: "text",
text: `Toggled to-do item "${todo.name}" to ${
todo.isChecked ? "completed" : "not completed"
}.`,
},
],
};
}
);我在VS Code中重启了MCP服务器,并询问Copilot:
把晚餐待办事项划掉
我确认始终在此工作区中 toggle-todo 工具调用并执行此操作 回复:
似乎找不到包含“晚餐”的待办事项。 你能确认一下待办事项的确切措辞吗,或者让我知道 最近是否被更改或删除?
我意识到问题是MCP服务器重新启动时丢失了内存存储 状态,所以实际上还有另一件事要做:坚持。
我计划更换 todos 常数,带I/O助手进行读写 将待办事项放入存储器。
为了实现这些助手,我使用了Bun的I/O方法,这要求我添加 Bun类型到依赖项,因此I/O方法可以在TypeScript中访问:
bun add -D @types/bun
package.json:
{
"dependencies": {
"@modelcontextprotocol/sdk": "latest",
"zod": "latest"
},
"devDependencies": {
"@types/bun": "latest"
}
}我使用导入Bun import Bun from "bun"; 并意识到,为了 能够为I/O编写助手,我需要确保脚本知道 要使用的目录路径。
我假设脚本的工作目录是 /Users/tom 因为我们 正在调用 bun VS Code工作区的完整路径正是因为 它从那个目录开始。
我决定仍然通过更改默认值来验证这一点 todos 列出完整 脚本运行所在目录的路径:
const todos: { name: string; isChecked: boolean }[] = [
{
name: `Know that the working directory is ${import.meta.dirname}`,
isChecked: true,
},
];我重启了服务器,问Copilot我的待办事项是什么,它说:
您当前的待办事项列表包括: `` 知道工作目录是/Users/tom/Destop/bun-mcp 如果你想添加、删除或更新任何待办事项,请告诉我!
因此,令人惊讶的是(对我来说),如果通过目录路径调用脚本,我想它 将工作目录设置为该路径。 这稍微简化了一些事情。
我换了 todos 此代码为常量:
const FILE_PATH = "TODO.md";
async function readTodos() {
const text = await Bun.file(FILE_PATH).text();
const lines = text.split("\n").filter((line) => line.trim() !== "");
return lines.map((line) => {
const isChecked = line.startsWith("- [x] ");
const name = line.slice("- [?] ".length).trim();
return { name, isChecked };
});
}
async function writeTodos(todos: Awaited>) {
const content = todos
.map((todo) => `- [${todo.isChecked ? "x" : " "}] ${todo.name}`)
.join("\n");
await Bun.write(FILE_PATH, content);
}我还更新了现有的三个工具,使它们的回调方法 async 并添加 const todos = await readTodos() 使用 todos 工作 再次并添加 await writeTodos(todos) 每当待办事项被修改为 将更改持久化到文件中。
我重新启动了MCP服务器,并以以下提示开始:
将取出垃圾箱添加到我的待办事项列表中
工具调用的输出如下:
ENOENT:没有这样的文件或目录,请打开“TODO.md”
我不记得了 Bun.file().text 会抛出一个不存在的文件 AFAIK没有提供回退内容的机制,因此我更改了I/O 辅助方法如下:
const FILE = Bun.file("TODO.md");
async function readTodos() {
const text = (await FILE.exists()) ? await FILE.text() : "";
const lines = text.split("\n").filter((line) => line.trim() !== "");
return lines.map((line) => {
const isChecked = line.startsWith("- [x] ");
const name = line.slice("- [?] ".length).trim();
return { name, isChecked };
});
}
async function writeTodos(todos: Awaited>) {
const content = todos
.map((todo) => `- [${todo.isChecked ? "x" : " "}] ${todo.name}`)
.join("\n");
await Bun.write(FILE, content);
}我重新启动了MCP服务器,并按了 聊天编辑器,用于回忆上次发送的消息并重新发送。
GitHub Copilot再次变得过于聪明,因为它创造了 TODO.md 单独和 在不调用我的MCP服务器的情况下向其添加了MarkDown复选框。
我重新编写了提示,希望能击中我的MCP服务器:
在我的待办事项列表中添加一个新的待办事项,用于倒垃圾
这导致了完全相同的事情发生,所以我转而问:
我的待办事项清单上有哪些项目?
MCP服务器正确调用了此功能。
您的待办事项列表当前为空。 如果你想添加一个新项目,请告诉我你想包括什么!
我接着说:
添加一个用于倒垃圾的项目
这也不起作用,所以我再次使用了“选择工具”按钮并取消选中 GitHub Copilot Chat下的Codebase选项希望它能阻止它 能够写入文件,但它不起作用,所以我重新打开了它。
我求助于这个提示:
使用我的待办事项列表MCP服务器添加待办事项以取出垃圾
这正确地调用了正确的工具,但我没有看到 TODO.md 如此创建 我问我的待办事项清单上有哪些文件,得知它是空的。
我还不知道如何调试MCP服务器脚本,所以我求助于更多的调试 通过工具结果走私信息,但这次我意识到我应该 使用过的 process.cwd() 而不是 import.meta.dir 整个时间!
- \[\]了解如何在VS Code调试器下运行MCP服务器脚本
我打消了在工具中添加更多信息的想法,转而去了 直接进入终端应用程序并运行 cd ~ 随后 ls.
这让我看到了 TODO.md 我的macOS用户目录中的文件。 我奔跑 cat TODO.md 并在那里看到了新的待办事项。
这意味着文件被正确写入(尽管缺少EOF换行符), 这就提出了一个问题,为什么我在回复中没有看到新的待办事项 向 list-todos.
但是,首先,我需要找到一种方法告诉MCP服务器 工作区目录是,我无法访问 import.meta.dir,因为这个案子 其中是我使用GitHub Copilot的工作区的工作区目录 与我将其开发为特殊工作区的工作区目录相同 这种情况不会适用于其他工作空间。
我换了 args 线路输入 mcp.json 对此:
"args": ["${workspaceFolder}", "${workspaceFolder}"]这样我就可以使用 process.argv 并获取脚本的唯一参数(暂且不谈) 脚本文件本身),并从中导出工作目录。
MCP服务器的安装方式不理想,因为 工作区目录是显式传递的,它应该能够请求此类型 信息本身,但目前我不知道如何做到这一点,或者如果 甚至在MCP协议中也支持。
从快速的网络搜索来看,答案可能不是。 我发现了一些提及 process.env.WORKSPACE_FOLDER_PATHS 它不在那里 在我的MCP服务器中 process.env 我还发现了一张纸条 . 扩展到 中的工作区根目录 mcp.json args 配置,我测试了 而且它似乎也不起作用。
目前,我将坚持使用双倍-workspaceFolder 在……里面 args.
- \[\]提交一个VS代码问题,要求将工作区根传递给MCP服务器脚本
我在MCP服务器脚本的顶部添加了一个检查,以指导用户和更改 工作目录(如果提供正确):
if (!process.argv[2]) {
throw new Error(
'Register the MCP server with `args` set to `["${workspaceFolder}", "${workspaceFolder}"]`.'
);
}
process.chdir(process.argv[2]);有了这些更改,我现在应该能够重新运行特定的提示,要求 创建一个新的todo并查看 TODO.md 文件似乎是由我的MCP服务器创建的,而不是 Copilot特工本身。
我重新启动了服务器并尝试了。
使用我的待办事项列表MCP服务器添加待办事项以取出垃圾
我看见 TODO.md 内容正确:
- [ ] Take out the trash此时,我意识到这个特定的存储库,因为 TODO.md 文件是测试数据的一部分,本质上,我应该忽略它。 它只应该在发生这种情况的工作区之外的工作区中不被忽视 使用MCP服务器。
.gitignore:
TODO.md
# NPM
node_modules
# Bun
bun.lock我再次尝试了“我的待办事项列表上有什么?”提示,它回答说: 没有待办事项。 我怀疑 const 随着 Bun.File 实例可能正在缓存 有些东西,我应该在每次通话中重新创建它 readTodos. 当我重新启动MCP服务器时,这种怀疑变得更加强烈 没有更改,待办事项现在已列出。
我更改了I/O助手,如下所示:
const FILE_NAME = "TODO.md";
async function readTodos() {
const text = (await Bun.file(FILE_NAME).exists())
? await Bun.file(FILE_NAME).text()
: "";
const lines = text.split("\n").filter((line) => line.trim() !== "");
return lines.map((line) => {
const isChecked = line.startsWith("- [x] ");
const name = line.slice("- [?] ".length).trim();
return { name, isChecked };
});
}
async function writeTodos(todos: Awaited>) {
const content = todos
.map((todo) => `- [${todo.isChecked ? "x" : " "}] ${todo.name}`)
.join("\n");
await Bun.write(FILE_NAME, content);
}这带来了正确的行为和东西现在工作! 我还可以让聊天记录将待办事项标记为已完成,这是正确的 呼叫 toggle-todo 工具。
- \[\]向添加选项参数
toggle-todo强制直接打开/关闭状态
我添加了另一个通过关键字删除待办事项的工具,类似于 切换它们:
server.tool(
"remove-todo",
"Removes a to-do item from the TODO.md file",
{
keyword: z
.string()
.describe("A keyword in the name of the to-do item to remove"),
},
async ({ keyword }) => {
const todos = await readTodos();
const index = todos.findIndex((todo) => todo.name.includes(keyword));
if (index === -1) {
return {
content: [
{
type: "text",
text: `To-do item containing "${keyword}" not found.`,
},
],
};
}
const removedTodo = todos.splice(index, 1)[0];
await writeTodos(todos);
return {
content: [
{
type: "text",
text: `Removed to-do item "${removedTodo.name}".`,
},
],
};
}
);这就完成了基本行为。 有很多方法可以改进这个玩具MCP服务器,我将 为未来储蓄。
______________________________________________________________________
再次回到这个演示后,我发现LLM可以很聪明 有时甚至足以将简短的提示与MCP服务器工具相关联。
我发现这些类型的提示可以很好地调用 to-do MCP与GitHub Copilot在代理模式下聊天,并使用OpenAI GPT-4.1模型。
这些工作没有 .github/copilot-instructions.md(详见下文)
- “创建新的待办事项…”
- “为…制定新的待办事项”
- “提醒我…”
- “注意…”
我对那些短的感到非常惊讶! 我无法重现绕过MCP服务器的问题 做一个 TODO.md 即使在重置聊天历史记录时,文件本身也是如此。
关于重置聊天历史记录,以了解提示将如何 在没有先前上下文的情况下处理:
使用Cmd+Shift+P命令调色板条目“聊天:清除所有工作区聊天” 重置GitHub Copilot对话,以确保不采用之前的上下文 在输入新的独立提示时,将其添加到帐户中。
我也发现了 .github/copilot-instructions.md 文件 它将额外的存储库级上下文嵌入到每个提示符/GitHub Copilot中 聊天,可用于引导代理走向所需的行为。
我用它来强迫代理人总是用句子大小写来命名项目 在每次突变后列出更新的列表。
更新到此文件后,将在下一个提示下发送到GitHub Copilot,它 只需保存,无需以其他方式刷新。
HTTP流传输
到目前为止,这个存储库已经实现了标准的I/O传输。 要将其转换为HTTP传输 StreamableHTTPServerTransport 可以使用传输实现。 还有 SSEServerTransport 计划使用服务器发送事件时。
我重新修改了代码,但缺少一部分。 需要运行一个单独的HTTP服务器 handleRequest 使用。 其签名仅与Node服务器兼容:
https://nodejs.org/api/http.html#class-http服务器
Bun.serve 不能用作其 request 和 response 类型不是 兼容的:
https://bun.sh/docs/api/http
我让Claude Code实现Node服务器,并以以下形式对其进行测试 这 test-server.sh Bash文件。
我还通过更新手动测试了它 .github/mcp.json 使用基于HTTP的 传输并使用VS Code GitHub Copilot代理询问与TODO相关的问题 不断使用正确的工具并更新内容和验证 TODO.md.
后来我发现 StreamableHTTPServerTransport 默认为SSE,但这 不同于 SSEServerTransport. 我希望JSON传输能够生成用于测试MCP交换的Bash脚本 更容易测试 jq 所以我打开了 enableJsonResponse 从哪个切换 SSE转换为JSON。
我请Claude Code研究SSE在流媒体方面的差异 HTTP传输和SSE传输,并得出结论 SSEServerTransport 是一个被取代的旧标准 StreamableHTTPServerTransport 哪个 仍然默认为SSE,但可以回退到JSON模式,这对 我的测试在这里。
