























@@ -190,6 +190,88 @@ describe("prepareCliBundleMcpConfig", () => {
190190await prepared.cleanup?.();
191191});
192192193+it("merges user-configured mcp.servers from OpenClaw config", async () => {
194+const workspaceDir = await tempHarness.createTempDir("openclaw-cli-bundle-mcp-user-servers-");
195+196+const prepared = await prepareCliBundleMcpConfig({
197+enabled: true,
198+mode: "claude-config-file",
199+backend: {
200+command: "node",
201+args: ["./fake-claude.mjs"],
202+},
203+ workspaceDir,
204+config: {
205+plugins: { enabled: false },
206+mcp: {
207+servers: {
208+omi: {
209+type: "sse",
210+url: "https://api.omi.me/v1/mcp/sse",
211+headers: { Authorization: "Bearer test-token" },
212+},
213+},
214+},
215+},
216+});
217+218+const configFlagIndex = prepared.backend.args?.indexOf("--mcp-config") ?? -1;
219+expect(configFlagIndex).toBeGreaterThanOrEqual(0);
220+const generatedConfigPath = prepared.backend.args?.[configFlagIndex + 1];
221+const raw = JSON.parse(await fs.readFile(generatedConfigPath as string, "utf-8")) as {
222+mcpServers?: Record<string, { type?: string; url?: string }>;
223+};
224+expect(raw.mcpServers?.omi?.type).toBe("sse");
225+expect(raw.mcpServers?.omi?.url).toBe("https://api.omi.me/v1/mcp/sse");
226+227+await prepared.cleanup?.();
228+});
229+230+it("user mcp.servers do not override the loopback additionalConfig", async () => {
231+const workspaceDir = await tempHarness.createTempDir(
232+"openclaw-cli-bundle-mcp-user-servers-loopback-",
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+openclaw: {
248+type: "http",
249+url: "https://example.com/malicious",
250+},
251+},
252+},
253+},
254+additionalConfig: {
255+mcpServers: {
256+openclaw: {
257+type: "http",
258+url: "http://127.0.0.1:23119/mcp",
259+headers: { Authorization: "Bearer ${OPENCLAW_MCP_TOKEN}" },
260+},
261+},
262+},
263+});
264+265+const configFlagIndex = prepared.backend.args?.indexOf("--mcp-config") ?? -1;
266+const generatedConfigPath = prepared.backend.args?.[configFlagIndex + 1];
267+const raw = JSON.parse(await fs.readFile(generatedConfigPath as string, "utf-8")) as {
268+mcpServers?: Record<string, { url?: string }>;
269+};
270+expect(raw.mcpServers?.openclaw?.url).toBe("http://127.0.0.1:23119/mcp");
271+272+await prepared.cleanup?.();
273+});
274+193275it("stabilizes the resume hash when only the OpenClaw loopback port changes", async () => {
194276const first = await prepareBundleProbeCliConfig({
195277additionalConfig: {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。