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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user