mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 05:11:49 +01:00
fix(server): keep the connection health policy of master for stream failures
Master keeps a remote MCP connection healthy after a tool call timeout, and its tests check this. The event stream change marked the connection degraded after a timeout and unhealthy after a transport failure. This commit removes these two health writes, so a timeout or a peer reset fails only that call, as on master. Authorization failures still mark the connection unhealthy. The call evidence now records the response status, content type and request id before the body is read. A body that fails partway records the bytes received so far as its size. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6742569933
commit
717e6c77cd
2 files changed
+14
-16
No files matched your search
@@ -4629,7 +4629,7 @@ rl.on("line", (line) => {
|
||||
} else {
|
||||
const timeout = scenario === "default deadline" || scenario === "explicit deadline";
|
||||
expectGatewayError(result.error, timeout ? 504 : 502, timeout ? "tool_timeout" : "mcp_remote_fetch_failed");
|
||||
expect(stored.healthStatus).toBe(timeout ? "degraded" : "error");
|
||||
expect(stored.healthStatus).toBe("ok");
|
||||
expect(event.metadata).toMatchObject({ execution: {
|
||||
failureKind: timeout ? "invocation_timeout" : "transport_failure",
|
||||
deadline: { timeoutMs: scenario === "explicit deadline" ? 1500 : 30_000, aborted: timeout },
|
||||
|
||||
@@ -6521,6 +6521,17 @@ export function createToolGatewayService(
|
||||
// automatically: the failed call may have changed app data.
|
||||
if (mcpSession) forgetMcpHttpSession(mcpSession);
|
||||
}
|
||||
// Record the response headers before the body is read, so a body that
|
||||
// fails partway still has its status and content type in the evidence.
|
||||
execution.response = {
|
||||
httpStatus: response.status,
|
||||
contentType: response.headers.get("content-type"),
|
||||
bodySizeBytes: 0,
|
||||
upstreamRequestId:
|
||||
response.headers.get("x-request-id") ??
|
||||
response.headers.get("x-zapier-request-id") ??
|
||||
response.headers.get("traceparent"),
|
||||
};
|
||||
const body = response.ok
|
||||
? JSON.stringify(await readMcpHttpResponse(response, requestId, {
|
||||
maxBytes: MAX_REMOTE_MCP_RESPONSE_BYTES,
|
||||
@@ -6542,15 +6553,7 @@ export function createToolGatewayService(
|
||||
},
|
||||
}))
|
||||
: await readBoundedRemoteResponse(response);
|
||||
execution.response = {
|
||||
httpStatus: response.status,
|
||||
contentType: response.headers.get("content-type"),
|
||||
bodySizeBytes: Buffer.byteLength(body, "utf8"),
|
||||
upstreamRequestId:
|
||||
response.headers.get("x-request-id") ??
|
||||
response.headers.get("x-zapier-request-id") ??
|
||||
response.headers.get("traceparent"),
|
||||
};
|
||||
execution.response.bodySizeBytes = Buffer.byteLength(body, "utf8");
|
||||
if (isInsufficientConnectionScope(response, body)) {
|
||||
await markCallHealth("degraded", INSUFFICIENT_CONNECTION_SCOPE_MESSAGE);
|
||||
throw new ToolGatewayHttpError(403, INSUFFICIENT_CONNECTION_SCOPE_MESSAGE, "oauth_insufficient_scope", {
|
||||
@@ -6653,13 +6656,10 @@ export function createToolGatewayService(
|
||||
} catch (error) {
|
||||
execution.error = remoteHttpErrorEvidence(error);
|
||||
execution.deadline = { timeoutMs: ms, aborted: controller.signal.aborted };
|
||||
if (execution.response && execution.stream) execution.response.bodySizeBytes = execution.stream.bytesReceived;
|
||||
if (controller.signal.aborted || (error instanceof Error && error.name === "AbortError")) {
|
||||
if (mcpSession) forgetMcpHttpSession(mcpSession);
|
||||
execution.failureKind = "invocation_timeout";
|
||||
await markCallHealth(
|
||||
"degraded",
|
||||
"Remote MCP tool call timed out; transport remains viable.",
|
||||
);
|
||||
throw new ToolGatewayHttpError(504, "Remote MCP tool call timed out", "tool_timeout", {
|
||||
connectionId: connection.id, catalogEntryId: entry.id, execution, failureKind: "invocation_timeout",
|
||||
});
|
||||
@@ -6696,8 +6696,6 @@ export function createToolGatewayService(
|
||||
execution.failureKind = "transport_failure";
|
||||
if (error instanceof McpHttpInitializationError && (error.status === 401 || error.status === 403)) {
|
||||
await markCallHealth("error", "Remote MCP session authorization failed.");
|
||||
} else {
|
||||
await markCallHealth("error", "Remote MCP tool call failed.");
|
||||
}
|
||||
if (mcpSession) forgetMcpHttpSession(mcpSession);
|
||||
throw new ToolGatewayHttpError(
|
||||
|
||||
Reference in new issue
Block a user