Skip to content

Fix MCP approval resuming#50

Merged
ScriptSmith merged 1 commit into
mainfrom
fix-mcp-approval
Jun 7, 2026
Merged

Fix MCP approval resuming#50
ScriptSmith merged 1 commit into
mainfrom
fix-mcp-approval

Conversation

@ScriptSmith

Copy link
Copy Markdown
Member

No description provided.

@greptile-apps

greptile-apps Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes three interrelated bugs in the MCP approval-resuming flow: org ID partition mismatches caused resume to look in the wrong database partition; the tool loop continued after parking (sending a continuation to the model), producing a stray trailing assistant message that poisoned the resume transcript; and replayed mcp_approval_request history items were being forwarded to the upstream model, which couldn't consume them.

  • Org resolution: Extracts resolve_request_org() as a shared helper and calls it on both the park path (PipelinePrincipal::from_auth) and the resume route, ensuring anonymous/no-auth requests resolve identically in both directions and land in the same DB partition.
  • Loop stop signal: Adds stop_loop: bool to ToolCallResult; the MCP approval gate sets it true when parking, and the runner breaks before issuing a continuation request. All other tools explicitly set stop_loop: false.
  • History cleanup: rewrite_mcp_history now filters out mcp_approval_request items before reconstructing history for the upstream provider, since resume has already folded the approved call into a function_call/function_call_output pair.

Confidence Score: 4/5

The changes are targeted correctness fixes for the MCP approval flow with comprehensive test coverage; no regressions expected in unrelated paths.

All three bugs are fixed at their root: the org-partition mismatch is resolved by sharing a single resolver; the trailing assistant-message problem is fixed by the stop_loop signal; and stale mcp_approval_request history items are now dropped before upstream forwarding. Each fix is covered by a dedicated unit or integration test.

No files require special attention; the core logic changes are in responses_pipeline.rs, chat.rs, runner.rs, and executor.rs, all of which read clearly and are well-tested.

Important Files Changed

Filename Overview
src/services/responses_pipeline.rs Extracts resolve_request_org() as a public helper and refactors PipelinePrincipal::from_auth to call it; adds two unit tests covering the anonymous-fallback and no-default cases.
src/routes/api/chat.rs Resume path now calls resolve_request_org (with default_org_id fallback) instead of principal().org_id() alone, fixing the partition mismatch that caused anonymous approvals to never resolve.
src/services/server_tools/mod.rs Adds stop_loop: bool field to ToolCallResult and derives Default; the field documentation clearly explains its purpose and usage contract.
src/services/server_tools/runner.rs Adds stop_requested check after the failure check; renames emit_failure_terminal to emit_final_terminal; adds comprehensive end-to-end stop-loop tests.
src/services/mcp/executor.rs Sets stop_loop: true on the park result, stop_loop: false on failure-closed and real-call results; adds a focused test verifying the parked result signals stop.
src/services/mcp/preprocess.rs Drops mcp_approval_request items from history in rewrite_mcp_history before forwarding to the upstream provider; includes a test verifying the item is filtered while the user message and function pair survive.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Route as chat.rs
    participant Runner as ToolLoopRunner
    participant Executor as McpExecutor
    participant DB as mcp_pending_approvals

    Note over Client,DB: Park turn
    Client->>Route: POST /v1/responses
    Route->>Runner: wrap_streaming
    Runner->>Executor: execute(mcp_call)
    Executor->>DB: "insert(org_id=resolve_request_org())"
    Executor-->>Runner: "ToolCallResult stop_loop=true"
    Runner-->>Client: mcp_approval_request + response.completed

    Note over Client,DB: Resume turn
    Client->>Route: POST /v1/responses + mcp_approval_response
    Route->>Route: resolve_request_org() same helper
    Route->>DB: take_by_id_and_org(approval_id, org_id)
    DB-->>Route: parked call row
    Route->>Route: resume_mcp_approvals rewrites input
    Route->>Runner: wrap_streaming rewritten input
    Runner-->>Client: real tool result
Loading

Reviews (1): Last reviewed commit: "Fix MCP approval resuming" | Re-trigger Greptile

@ScriptSmith ScriptSmith merged commit c98fab0 into main Jun 7, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant