Draft
Conversation
Recovery messages (a previously-failed toolset is now available again)
were going through the same warning queue as real failures. After lazy-
init OAuth completed and the toolset reconnected, the user saw
Some toolsets failed to initialize for agent 'root'.
Details:
- mcp(remote host=mcp.slack.com transport=streamable) is now available
The body says 'is now available' (success) but the framing says 'failed'
(failure), which reads like 'is NOT available'.
This change splits the agent's queue in two:
- AddToolWarning / DrainWarnings: real failures (start failed,
list failed, ...). Exported because the runtime emits these from
the startup tool-loading path (added in a follow-up commit).
- AddToolNotice / DrainNotices: positive, informational status
updates. The 'now available' recovery path now uses this queue.
emitAgentWarnings drains both, formatting failures with the existing
'Some toolsets failed to initialize' banner and notices with a neutral
'Toolset status update' header so each reads correctly on its own.
Assisted-By: docker-agent
Running 'docker agent run ./examples/slack.yaml' could hang during
startup before the TUI was even ready: the runtime was eagerly starting
toolsets to populate sidebar tool counts, the remote MCP client got back
401 + WWW-Authenticate, and the OAuth flow tried to surface an
elicitation dialog. The TUI hadn't rendered yet, the elicitation
goroutine was blocked on a synchronous channel send, and Ctrl-C
couldn't reach it.
This change introduces a per-context flag that lets callers opt out of
interactive flows:
- WithoutInteractivePrompts(ctx) marks a context as non-interactive.
- The oauthTransport checks the flag before triggering the OAuth
elicitation on a 401 and short-circuits with a recognisable
AuthorizationRequiredError instead of blocking.
- IsAuthorizationRequired(err) lets callers distinguish 'OAuth was
deferred' from a real failure. Because the MCP SDK wraps transport
errors with %v (not %w), enrichConnectError reads the deferred-auth
flag back off the transport in remote.go and re-emits a clean
AuthorizationRequiredError.
The runtime wraps the startup tool-loading context with this helper, so
toolsets that need OAuth are detected immediately and silently deferred
to the first RunStream where the user is interacting and a dialog can
be rendered. Real start failures still surface as warnings via the
agent's warning channel (a.AddToolWarning), and freshFailure is
preserved for the deferred-OAuth case so the *real* failure on the
eventual interactive retry isn't suppressed by the once-per-streak
guard.
Assisted-By: docker-agent
… re-auth on scope changes Three related fixes to the remote MCP OAuth flow, motivated by the Slack MCP server (https://mcp.slack.com/mcp). - Accept Slack's oauth.v2.user.access response shape in addition to the standard RFC 6749 §5.1 flat shape. Slack nests the user token inside an authed_user object and signals application-level failures via HTTP 200 + {"ok":false}. Previously the flat decoder silently produced an empty bearer, and every subsequent MCP request was rejected with 401. Decoding is factored out into parseTokenResponse, used by both ExchangeCodeForToken and RefreshAccessToken, and we now error out explicitly when no access_token can be located. - Track the configured scope list on each stored token as a new RequestedScopes field. In getValidToken, if the configured scopes are no longer covered by the stored token, purge it from the store and return nil so the next request triggers a fresh OAuth flow. The scope list is preserved across silent refreshes, and legacy tokens without RequestedScopes are left untouched to avoid forcing re-auth on upgrade. - Log the response body (capped at 2 KiB) when an authenticated retry after a successful OAuth flow is still rejected with a non-2xx. The MCP SDK only surfaces http.StatusText, which hides provider-specific error detail such as insufficient_scope. The body remains readable by downstream consumers, and enrichConnectError attaches the extracted message to the Connect error so callers see the real server-side cause (e.g. 'App is not enabled for Slack MCP server access'). Covered by new unit tests for Slack's nested and ok:false payloads, post-OAuth retry body preservation, and the scope-invalidation path. Assisted-By: docker-agent
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.