Let Claude apply its native MCP timeouts (#3315)

* fix(claude): preserve native MCP timeouts

Paseo forced Claude MCP startup and tool waits to ten minutes, turning unavailable servers into long silent first turns. Let Claude apply its own defaults while preserving explicit user environment overrides.

* test(claude): isolate MCP timeout regression

Exercise timeout precedence through the existing provider runtime environment input without mutating process-wide test state.

* test(workspace-git): await refresh boundaries

Synchronize fetch observation tests with initial snapshot and fetch completion before advancing fake timers.
This commit is contained in:
Mohamed Boudra
2026-08-13 13:40:31 +02:00
committed by GitHub
parent 36312352db
commit 9ca6f24315
3 changed files with 36 additions and 23 deletions
@@ -68,6 +68,12 @@ describe("Claude SDK env", () => {
logger: createTestLogger(),
queryFactory,
resolveBinary: async () => "/test/claude/bin",
runtimeSettings: {
env: {
MCP_TIMEOUT: "claude-startup-timeout",
MCP_TOOL_TIMEOUT: "claude-tool-timeout",
},
},
});
const session = await client.createSession(
{
@@ -82,6 +88,8 @@ describe("Claude SDK env", () => {
expect(result.sessionId).toBe("managed-agent-env-session");
expect(capturedEnv?.PASEO_AGENT_ID).toBe(launchContext.env?.PASEO_AGENT_ID);
expect(capturedEnv?.PASEO_TEST_FLAG).toBe(launchContext.env?.PASEO_TEST_FLAG);
expect(capturedEnv?.MCP_TIMEOUT).toBe("claude-startup-timeout");
expect(capturedEnv?.MCP_TOOL_TIMEOUT).toBe("claude-tool-timeout");
} finally {
await session.close();
}
@@ -3075,14 +3075,7 @@ class ClaudeAgentSession implements AgentSession {
return createProviderEnv({
baseEnv: process.env,
runtimeSettings: this.runtimeSettings,
overlays: [
{
// Increase MCP timeouts for long-running tool calls (10 minutes)
MCP_TIMEOUT: "600000",
MCP_TOOL_TIMEOUT: "600000",
},
this.launchEnv,
],
overlays: [this.launchEnv],
});
}
@@ -503,6 +503,15 @@ describe("WorkspaceGitService checkout observation", () => {
...current,
upstreamStatus: facts.upstreamStatus,
}));
const runGitFetch = vi.fn(async (_cwd, observer) => {
observer?.onRefSnapshot("before");
await releaseFetch.promise;
observer?.onRefSnapshot("after");
return {
changes: [{ kind: "moved" as const, ref: "origin/main", beforeOid: "a", afterOid: "b" }],
error: null,
};
});
const service = createService(watcher, {
getCheckoutSnapshotFacts,
getCheckoutRefDerivedState,
@@ -515,22 +524,16 @@ describe("WorkspaceGitService checkout observation", () => {
}),
),
hasOriginRemote: vi.fn(async () => true),
runGitFetch: vi.fn(async (_cwd, observer) => {
observer?.onRefSnapshot("before");
await releaseFetch.promise;
observer?.onRefSnapshot("after");
return {
changes: [{ kind: "moved" as const, ref: "origin/main", beforeOid: "a", afterOid: "b" }],
error: null,
};
}),
runGitFetch,
});
const listener = vi.fn();
const subscription = service.registerWorkspace({ cwd: REPO_CWD }, listener);
await service.getSnapshot(REPO_CWD);
await vi.waitFor(() => {
expect(runGitFetch).toHaveBeenCalledTimes(1);
expect(service.getMetrics().fetchInFlightCount).toBe(1);
expect(service.getMetrics().workspaceRefreshInFlightCount).toBe(0);
});
expect(service.getMetrics().workspaceRefreshInFlightCount).toBe(0);
listener.mockClear();
watcher.records
@@ -539,7 +542,9 @@ describe("WorkspaceGitService checkout observation", () => {
{ path: path.join(GIT_DIR, "refs", "remotes", "origin", "main"), type: "create" },
]);
releaseFetch.resolve();
await flushPromises();
await vi.waitFor(() => {
expect(service.getMetrics().fetchInFlightCount).toBe(0);
});
await vi.advanceTimersByTimeAsync(1_000);
await vi.waitFor(() => {
expect(getCheckoutRefDerivedState).toHaveBeenCalledTimes(1);
@@ -798,6 +803,10 @@ describe("WorkspaceGitService checkout observation", () => {
...current,
upstreamStatus: facts.upstreamStatus,
}));
const runGitFetch = vi.fn(async () => ({
changes: [{ kind: "moved" as const, ref: "origin/main", beforeOid: "a", afterOid: "b" }],
error: null,
}));
const service = createService(watcher, {
getCheckoutSnapshotFacts,
getCheckoutRefDerivedState,
@@ -810,13 +819,16 @@ describe("WorkspaceGitService checkout observation", () => {
}),
),
hasOriginRemote: vi.fn(async () => true),
runGitFetch: vi.fn(async () => ({
changes: [{ kind: "moved" as const, ref: "origin/main", beforeOid: "a", afterOid: "b" }],
error: null,
})),
runGitFetch,
});
const subscription = service.registerWorkspace({ cwd: REPO_CWD }, vi.fn());
await service.getSnapshot(REPO_CWD);
await vi.waitFor(() => {
expect(runGitFetch).toHaveBeenCalledTimes(1);
expect(service.getMetrics().fetchInFlightCount).toBe(0);
});
expect(service.getMetrics().workspaceRefreshInFlightCount).toBe(0);
await vi.advanceTimersByTimeAsync(1_000);
await vi.waitFor(() => {
expect(getCheckoutRefDerivedState).toHaveBeenCalledTimes(1);