
























@@ -227,6 +227,93 @@ describe("prepareCliBundleMcpConfig", () => {
227227await prepared.cleanup?.();
228228});
229229230+it("translates OpenClaw transport field on user mcp.servers into Claude type", async () => {
231+const workspaceDir = await tempHarness.createTempDir(
232+"openclaw-cli-bundle-mcp-user-servers-transport-",
233+);
234+235+const prepared = await prepareCliBundleMcpConfig({
236+enabled: true,
237+mode: "claude-config-file",
238+backend: {
239+command: "node",
240+args: ["./fake-claude.mjs"],
241+},
242+ workspaceDir,
243+config: {
244+plugins: { enabled: false },
245+mcp: {
246+servers: {
247+context7: {
248+transport: "streamable-http",
249+url: "https://mcp.context7.com/mcp",
250+headers: { CONTEXT7_API_KEY: "ctx7sk-test" },
251+},
252+"omi-sse": {
253+transport: "sse",
254+url: "https://api.omi.me/v1/mcp/sse",
255+},
256+},
257+},
258+},
259+});
260+261+const configFlagIndex = prepared.backend.args?.indexOf("--mcp-config") ?? -1;
262+expect(configFlagIndex).toBeGreaterThanOrEqual(0);
263+const generatedConfigPath = prepared.backend.args?.[configFlagIndex + 1];
264+const raw = JSON.parse(await fs.readFile(generatedConfigPath as string, "utf-8")) as {
265+mcpServers?: Record<string, { type?: string; transport?: string; url?: string }>;
266+};
267+268+expect(raw.mcpServers?.context7?.type).toBe("http");
269+expect(raw.mcpServers?.context7?.url).toBe("https://mcp.context7.com/mcp");
270+expect(raw.mcpServers?.context7?.transport).toBeUndefined();
271+272+expect(raw.mcpServers?.["omi-sse"]?.type).toBe("sse");
273+expect(raw.mcpServers?.["omi-sse"]?.transport).toBeUndefined();
274+275+await prepared.cleanup?.();
276+});
277+278+it("preserves explicit type and still strips transport on user mcp.servers", async () => {
279+const workspaceDir = await tempHarness.createTempDir(
280+"openclaw-cli-bundle-mcp-user-servers-transport-explicit-",
281+);
282+283+const prepared = await prepareCliBundleMcpConfig({
284+enabled: true,
285+mode: "claude-config-file",
286+backend: {
287+command: "node",
288+args: ["./fake-claude.mjs"],
289+},
290+ workspaceDir,
291+config: {
292+plugins: { enabled: false },
293+mcp: {
294+servers: {
295+mixed: {
296+type: "http",
297+transport: "sse",
298+url: "https://mcp.example.com/mcp",
299+},
300+},
301+},
302+},
303+});
304+305+const configFlagIndex = prepared.backend.args?.indexOf("--mcp-config") ?? -1;
306+const generatedConfigPath = prepared.backend.args?.[configFlagIndex + 1];
307+const raw = JSON.parse(await fs.readFile(generatedConfigPath as string, "utf-8")) as {
308+mcpServers?: Record<string, { type?: string; transport?: string }>;
309+};
310+311+expect(raw.mcpServers?.mixed?.type).toBe("http");
312+expect(raw.mcpServers?.mixed?.transport).toBeUndefined();
313+314+await prepared.cleanup?.();
315+});
316+230317it("user mcp.servers do not override the loopback additionalConfig", async () => {
231318const workspaceDir = await tempHarness.createTempDir(
232319"openclaw-cli-bundle-mcp-user-servers-loopback-",
@@ -548,4 +635,52 @@ describe("prepareCliBundleMcpConfig", () => {
548635549636await prepared.cleanup?.();
550637});
638+639+it("translates user mcp.servers transport fields in Gemini system settings", async () => {
640+const prepared = await prepareCliBundleMcpConfig({
641+enabled: true,
642+mode: "gemini-system-settings",
643+backend: {
644+command: "gemini",
645+args: ["--prompt", "{prompt}"],
646+},
647+workspaceDir: "/tmp/openclaw-bundle-mcp-gemini",
648+config: {
649+plugins: { enabled: false },
650+mcp: {
651+servers: {
652+context7: {
653+transport: "streamable-http",
654+url: "https://mcp.context7.com/mcp",
655+headers: {
656+Authorization: "Bearer ${CONTEXT7_API_KEY}",
657+},
658+},
659+},
660+},
661+},
662+env: {
663+CONTEXT7_API_KEY: "ctx7-test",
664+},
665+});
666+667+expect(prepared.env?.CONTEXT7_API_KEY).toBe("ctx7-test");
668+expect(typeof prepared.env?.GEMINI_CLI_SYSTEM_SETTINGS_PATH).toBe("string");
669+const raw = JSON.parse(
670+await fs.readFile(prepared.env?.GEMINI_CLI_SYSTEM_SETTINGS_PATH as string, "utf-8"),
671+) as {
672+mcp?: { allowed?: string[] };
673+mcpServers?: Record<
674+string,
675+{ type?: string; transport?: string; url?: string; headers?: Record<string, string> }
676+>;
677+};
678+expect(raw.mcp?.allowed).toEqual(["context7"]);
679+expect(raw.mcpServers?.context7?.type).toBe("http");
680+expect(raw.mcpServers?.context7?.transport).toBeUndefined();
681+expect(raw.mcpServers?.context7?.url).toBe("https://mcp.context7.com/mcp");
682+expect(raw.mcpServers?.context7?.headers?.Authorization).toBe("Bearer ctx7-test");
683+684+await prepared.cleanup?.();
685+});
551686});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。