feat(mcp): associate OAuth tokens with requesting user and surface consent in chat - #79449
Open
astraltrekkin wants to merge 5 commits into
Open
astraltrekkin wants to merge 5 commits into
astraltrekkin wants to merge 5 commits into
Conversation
…78174) Add mcp.oauth.identity_mode=per_user so gateway callers use isolated token storage and MCP connections instead of silently sharing the profile-scoped OAuth bearer. Shared mode remains the default. Co-authored-by: Cursor <cursoragent@cursor.com>
Bare-name _servers lookups missed server@@user_key entries after identity_mode=per_user, breaking OAuth recovery and availability checks. Co-authored-by: Cursor <cursoragent@cursor.com>
Deliver authorize URLs via the session notify path when a messaging user hits an OAuth MCP without tokens, and accept pasted redirect callbacks so headless consent no longer depends on the Hermes host terminal (NousResearch#78169). Co-authored-by: Cursor <cursoragent@cursor.com>
Add wipe-all/logout revocation, gateway reauth with authorization_url on needs_reauth, actionable consent failure chat replies, and harden tool args so models cannot select another user's credentials. Keep dashboard and login re-auth from clearing every by-user token tree. Co-authored-by: Cursor <cursoragent@cursor.com>
Mocks for handle_401 / invalidate_if_disk_changed must accept the per-user kwarg so recovery paths still run under identity_mode wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
5 of 7 tasks
10 tasks done
This branch has not been deployed
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.
What does this PR do?
Hermes historically stored one MCP OAuth token set per profile/server, so on a shared gateway User B could silently reuse User A's authorization. This PR adds an opt-in
mcp.oauth.identity_mode: per_userboundary that scopes tokens and connections to the authenticated session user, fails closed when identity is missing, and surfaces headless OAuth consent URLs in the originating chat (with paste-back) instead of only the host terminal.Default remains
sharedfor single-operator CLI/profile compatibility.Related Issue
Fixes #78174
Fixes #78169
Type of Change
Changes Made
tools/mcp_oauth_identity.py—shared/per_usermode, session-derived user key, fail-closed missing identity, credential-selector arg strippingtools/mcp_oauth.py/tools/mcp_oauth_manager.py— per-user token paths (mcp-tokens/by-user/<sanitized-key>/), provider cache keyed by user, wipe-all vs single-identity removetools/mcp_gateway_oauth.py— gateway consent flow, chat URL delivery, paste correlation, consent failure notify (mcp_oauth_consent_result)tools/mcp_tool.py— per-user registry keys, lazy connect + gateway reauth,needs_reauthincludesauthorization_urlwhen publishedgateway/run.py/gateway/platforms/base.py— deliver consent / consent-result messages; OAuth paste bypass of active-session queuehermes_cli/mcp_config.py/subcommands/mcp.py—hermes mcp login --user,hermes mcp logout [--user]hermes_cli/web_server.py/ login path — dashboard/CLI re-auth usesall_identities=Falseso by-user trees are not wipedhermes_cli/config_defaults.py—mcp.oauth.identity_mode: sharedwebsite/docs/user-guide/features/mcp.md— per-user mode, redirect_uri recommendation, logout/remove, notify-path desktop notetests/tools/test_mcp_oauth_per_user_identity.py,test_mcp_gateway_oauth.py,test_mcp_tool_401_handling.py,tests/hermes_cli/test_mcp_config.pyHow to Test
config.yaml:mcp-tokens/by-user/files, consent URL lands in the originating chat, and pasting User A's redirect on User B's session is rejected.hermes mcp logout <server>clears shared + all by-user tokens;--user <key>clears one identity. Dashboard/hermes mcp loginmust not wipe other users' tokens.Checklist
Code
fix(scope):,feat(scope):, etc.)scripts/run_tests.shon the MCP OAuth-focused files above and they pass (full suite not re-run in this session)Documentation & Housekeeping
website/docs/user-guide/features/mcp.md)cli-config.yaml.exampleif I added/changed config keys — or N/A (key lives inconfig.yaml/config_defaults.py)CONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/Apathlib/ Hermes home)Screenshots / Logs
N/A — hermetic unit/integration coverage; no live Telegram/Discord E2E in CI for this PR.