mirror of https://github.com/openclaw/openclaw.git
fix(cli): isolate claude MCP config
This commit is contained in:
parent
85b169c453
commit
b8ff152a98
|
|
@ -40,6 +40,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Agents/status: use provider-aware context window lookup for fresh Anthropic 4.6 model overrides so `/status` shows the correct 1.0m window instead of an underreported shared-cache minimum. (#54796) Thanks @neeravmakwana.
|
||||
- Agents/errors: surface provider quota/reset details when available, but keep HTML/Cloudflare rate-limit pages on the generic fallback so raw error pages are not shown to users. (#54512) Thanks @bugkill3r.
|
||||
- Claude CLI: switch the bundled Claude CLI backend to `stream-json` output so watchdogs see progress on long runs, and keep session/usage metadata even when Claude finishes with an empty result line. (#49698) Thanks @felear2022.
|
||||
- Claude CLI/MCP: always pass a strict generated `--mcp-config` overlay for background Claude CLI runs, including the empty-server case, so Claude does not inherit ambient user/global MCP servers. (#54961) Thanks @markojak.
|
||||
- Agents/embedded replies: surface mid-turn 429 and overload failures when embedded runs end without a user-visible reply, while preserving successful media-only replies that still use legacy `mediaUrl`. (#50930) Thanks @infichen.
|
||||
- WhatsApp/allowFrom: show a specific allowFrom policy error for valid blocked targets instead of the misleading `<E.164|group JID>` format hint. Thanks @mcaxtr.
|
||||
- Agents/cooldowns: scope rate-limit cooldowns per model so one 429 no longer blocks every model on the same auth profile, replace the exponential 1 min -> 1 h escalation with a stepped 30 s / 1 min / 5 min ladder, and surface a user-facing countdown message when all models are rate-limited. (#49834) Thanks @kiranvk-2011.
|
||||
|
|
|
|||
|
|
@ -272,6 +272,56 @@ describe("runCliAgent with process supervisor", () => {
|
|||
expect(allArgs).toContain("You are a helpful assistant.");
|
||||
});
|
||||
|
||||
it("injects a strict empty MCP config for bundle-MCP-enabled Claude CLI runs", async () => {
|
||||
supervisorSpawnMock.mockResolvedValueOnce(
|
||||
createManagedRun({
|
||||
reason: "exit",
|
||||
exitCode: 0,
|
||||
exitSignal: null,
|
||||
durationMs: 50,
|
||||
stdout: JSON.stringify({
|
||||
session_id: "session-123",
|
||||
message: "ok",
|
||||
}),
|
||||
stderr: "",
|
||||
timedOut: false,
|
||||
noOutputTimedOut: false,
|
||||
}),
|
||||
);
|
||||
|
||||
await runCliAgent({
|
||||
sessionId: "s1",
|
||||
sessionFile: "/tmp/session.jsonl",
|
||||
workspaceDir: "/tmp",
|
||||
config: {
|
||||
agents: {
|
||||
defaults: {
|
||||
cliBackends: {
|
||||
"claude-cli": {
|
||||
command: "node",
|
||||
args: ["/tmp/fake-claude.mjs"],
|
||||
clearEnv: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies OpenClawConfig,
|
||||
prompt: "hi",
|
||||
provider: "claude-cli",
|
||||
model: "claude-sonnet-4-6",
|
||||
timeoutMs: 1_000,
|
||||
runId: "run-bundle-mcp-empty",
|
||||
});
|
||||
|
||||
const input = supervisorSpawnMock.mock.calls[0]?.[0] as { argv?: string[] };
|
||||
expect(input.argv?.[0]).toBe("node");
|
||||
expect(input.argv).toContain("/tmp/fake-claude.mjs");
|
||||
expect(input.argv).toContain("--strict-mcp-config");
|
||||
const configFlagIndex = input.argv?.indexOf("--mcp-config") ?? -1;
|
||||
expect(configFlagIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(input.argv?.[configFlagIndex + 1]).toMatch(/^\/.+\/mcp\.json$/);
|
||||
});
|
||||
|
||||
it("runs CLI through supervisor and returns payload", async () => {
|
||||
supervisorSpawnMock.mockResolvedValueOnce(
|
||||
createManagedRun({
|
||||
|
|
|
|||
|
|
@ -15,6 +15,32 @@ afterEach(async () => {
|
|||
});
|
||||
|
||||
describe("prepareCliBundleMcpConfig", () => {
|
||||
it("injects a strict empty --mcp-config overlay for bundle-MCP-enabled backends without servers", async () => {
|
||||
const workspaceDir = await tempHarness.createTempDir("openclaw-cli-bundle-mcp-empty-");
|
||||
|
||||
const prepared = await prepareCliBundleMcpConfig({
|
||||
enabled: true,
|
||||
backend: {
|
||||
command: "node",
|
||||
args: ["./fake-claude.mjs"],
|
||||
},
|
||||
workspaceDir,
|
||||
config: {},
|
||||
});
|
||||
|
||||
const configFlagIndex = prepared.backend.args?.indexOf("--mcp-config") ?? -1;
|
||||
expect(configFlagIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(prepared.backend.args).toContain("--strict-mcp-config");
|
||||
const generatedConfigPath = prepared.backend.args?.[configFlagIndex + 1];
|
||||
expect(typeof generatedConfigPath).toBe("string");
|
||||
const raw = JSON.parse(await fs.readFile(generatedConfigPath as string, "utf-8")) as {
|
||||
mcpServers?: Record<string, unknown>;
|
||||
};
|
||||
expect(raw.mcpServers).toEqual({});
|
||||
|
||||
await prepared.cleanup?.();
|
||||
});
|
||||
|
||||
it("injects a merged --mcp-config overlay for bundle-MCP-enabled backends", async () => {
|
||||
const env = captureEnv(["HOME"]);
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -98,10 +98,9 @@ export async function prepareCliBundleMcpConfig(params: {
|
|||
}
|
||||
mergedConfig = applyMergePatch(mergedConfig, bundleConfig.config) as BundleMcpConfig;
|
||||
|
||||
if (Object.keys(mergedConfig.mcpServers).length === 0) {
|
||||
return { backend: params.backend };
|
||||
}
|
||||
|
||||
// Always pass an explicit strict MCP config for background claude-cli runs.
|
||||
// Otherwise Claude may inherit ambient user/global MCP servers (for example
|
||||
// Playwright) and spawn unexpected background processes.
|
||||
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-cli-mcp-"));
|
||||
const mcpConfigPath = path.join(tempDir, "mcp.json");
|
||||
const serializedConfig = `${JSON.stringify(mergedConfig, null, 2)}\n`;
|
||||
|
|
|
|||
Loading…
Reference in New Issue