stacklok / stacklok/mecatl

New message during a still-pending MCP authorization hits opaque 'has a live external authorization' error

Open
#1,307 0 comments 0 reactions 1 assignee View on GitHub

@jhrozek is already working on this.

Since Sep 10, 2026.

Dominant language
Go
Stars
152
Forks
16
Avg merge
14h 48m
Merged PRs (30d)
536

Description

Summary

A user sends a message that triggers a protected MCP tool call (broker/DCR mode). The tool call parks the session for authorization (StateAuthorizing), the user is shown the consent flow. If the user sends a new message before that authorization finishes resolving, the request fails with an opaque error instead of a clear "authorization still pending" response:

stream error: rpc error: code = FailedPrecondition desc = server: failed precondition: session "0aa385b9d1606022f4a60c29eb6ebc41" has a live external authorization

Reproduction (observed live)

Session 0aa385b9d1606022f4a60c29eb6ebc41, against a live mecak8s deployment with connector_gateway configured (client.mode: dcr):

  1. User: "list my meeting notes in read.ai"
  2. Model calls connector_gateway's Read_ai_f1bde01f_list_meetings tool - this is the FIRST use of the Read.ai backend for this user, so it parks the session for authorization (expected, matches ADR 0310/0311's lazy-authorization design).
  3. User sends a follow-up message ("can you share") before completing/confirming the authorization has resolved.
  4. Server returns FailedPrecondition: session ... has a live external authorization - a hard, opaque error with no guidance.

Root cause

Traced end to end:

  • Every run-entry (new message) passes through reopenLoadedSession (internal/adapter/server/service.go:4042) -> interruptRestoredAuthorizationLocked (internal/adapter/server/mcp_authorization.go:937) whenever the session's persisted state is StateAuthorizing.
  • interruptRestoredAuthorizationLocked's own doc comment says it "repairs authorizing state whose exact process-local transaction is unavailable" - i.e. it is meant for the case where the process that originally parked the session is gone (crash, restart, redeploy).
  • Its ONLY signal for reaching that conclusion is sess.State == StateAuthorizing, loaded fresh from the durable store. It cannot distinguish "orphaned by a dead process" from "still legitimately in-flight, same live process, user just sent a message before the authorization resolved" - both look identical from this check alone.
  • When it finds the authorization still live via attachment.AuthorizationStatus, it correctly refuses to silently clear it (a good safety property for the orphan case) but returns this hard FailedPrecondition for BOTH cases, with no differentiation and no actionable message for the still-in-flight case.

There does not appear to be any earlier check in the run-entry funnel that recognizes "this session has a pending, still-resolving authorization, please wait or cancel" and short-circuits to a friendly response before falling into the orphan-recovery path.

Suggested fix direction

Distinguish the two cases before returning this error - for example, check whether the parking transaction is still genuinely being tracked by the SAME process/owner (not just whether the external authorization is still live) before concluding the session needs "restoring" at all. If it's still owned by this same live process, return a clear, distinct "authorization pending, please complete or cancel it" response instead of routing into the dead-process repair path and its opaque error. CancelMCPAuthorization already exists as a working escape hatch and does not hit this guard - the gap is that a user has no way to know from this error message that cancelling (or just waiting) is the way forward.

Impact

Any user of an oauth-mode MCP broker backend (GitHub, connector-gateway, etc.) who sends a follow-up message while their first authorization is still resolving hits this same confusing dead end. Likely also explains an earlier, separately-reported symptom from the same day ("took very long to confirm the connection, had to press Enter repeatedly, then a confusing error about state") on the same deployment/feature.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.