Skip to content

Commit a64da04

Browse files
Dumbrisclaude
andcommitted
fix(server): close the tool_call record on a direct-mode sanitisation block
Direct routing (#1685) returned applyOutputSanitisation's block result before emitting the call's completion. It now emits the same error tool_call (error_class proxy_policy, block message only) as the call_tool_* paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 4b9d601 commit a64da04

2 files changed

Lines changed: 14 additions & 0 deletions

File tree

‎internal/server/mcp_routing.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,11 @@ func (p *MCPProxyServer) makeDirectModeHandler(entry *directCatalogEntry) mcpser
745745
// applied to /mcp/all. Applied to the RAW result before the activity
746746
// classification and truncation below; a non-nil result means blocked.
747747
if blockResult := p.applyOutputSanitisation(ctx, serverName, toolName, requestID, directContentTrust, result); blockResult != nil {
748+
// The upstream ran, so the started record is closed with the block
749+
// message, never the response (direct mode keeps no history).
750+
blockMsg := firstTextOf(blockResult)
751+
callerr.NoteOutcome(ctx, callerr.Outcome{Class: callerr.ClassProxyPolicy, Domain: callerr.DomainProxy})
752+
p.emitActivityToolCallCompleted(ctx, serverName, toolName, sessionID, requestID, "mcp", "error", blockMsg, durationMs, enrichedArgs, "", false, contracts.DeriveCallWith(annotations), nil, directContentTrust, "", 0, 0, "", nil, "")
748753
return blockResult, nil
749754
}
750755

‎internal/server/sanitisation_block_completion_test.go‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ func TestLegacyCallTool_SanitisationBlockRecordsToolCallCompletion(t *testing.T)
108108
assertBlockedCallRecorded(t, f)
109109
}
110110

111+
func TestDirectMode_SanitisationBlockRecordsToolCallCompletion(t *testing.T) {
112+
f := blockedSecretFixture(t)
113+
res := f.call(t, fullTierAgentOn("github"), "github", "get_secret")
114+
require.True(t, res.IsError)
115+
require.Equal(t, int64(1), f.ups["github"].count.Load(), "the upstream ran")
116+
117+
assertBlockedCallRecorded(t, f)
118+
}
119+
111120
// The tool-call history entry of a blocked call keeps the attempt but never
112121
// the response: the block message takes its place. (The direct-routing
113122
// fixture's incarnation guard drops every history write, so this is checked

0 commit comments

Comments
 (0)