diff --git a/src/lib/agent-interface.spec.ts b/src/lib/agent-interface.spec.ts index 0c39f813..478517bd 100644 --- a/src/lib/agent-interface.spec.ts +++ b/src/lib/agent-interface.spec.ts @@ -169,6 +169,18 @@ describe('runAgent retry loop', () => { }) as typeof emitter.emit; }); + it('isolates the agent from user Claude Code settings and MCP servers', async () => { + mockQuery.mockImplementation(createMockSDKResponse([{ text: 'Done!' }])); + + await runAgent(makeAgentConfig(), 'Test prompt', makeOptions(), undefined, emitter); + + const { options } = mockQuery.mock.calls[0][0] as { options: Record }; + // Omitted, the SDK loads ~/.claude settings: user plugins, MCP servers, hooks, and + // permission rules that would apply before installerCanUseTool. + expect(options.settingSources).toEqual([]); + expect(options.strictMcpConfig).toBe(true); + }); + it('returns retryCount=0 when no retryConfig provided', async () => { mockQuery.mockImplementation(createMockSDKResponse([{ text: 'Done!' }])); diff --git a/src/lib/agent-interface.ts b/src/lib/agent-interface.ts index 22efda04..c61e6eeb 100644 --- a/src/lib/agent-interface.ts +++ b/src/lib/agent-interface.ts @@ -677,6 +677,12 @@ export async function runAgent( return Promise.resolve(result); }, tools: { type: 'preset', preset: 'claude_code' }, + // Load no ~/.claude or project settings. Omitted, the SDK (since 0.2.89) loads them + // all: the user's plugins, MCP servers, hooks, CLAUDE.md, and permission rules, + // which apply before installerCanUseTool and would bypass the Bash gate. + settingSources: [], + // Only MCP servers we pass explicitly (none), even if the SDK's defaults change again. + strictMcpConfig: true, allowedTools: agentConfig.allowedTools, plugins: [{ type: 'local', path: pluginPath }], pathToClaudeCodeExecutable: agentConfig.claudeExecutablePath,