fix(mcp): fail closed when the tool scope gate cannot reach its auth config - #716
Draft
vishal-bala wants to merge 1 commit into
Draft
fix(mcp): fail closed when the tool scope gate cannot reach its auth config#716vishal-bala wants to merge 1 commit into
vishal-bala wants to merge 1 commit into
Conversation
…config Four tool wrappers carried an identical three-line prologue that read auth_config off the server, pulled a scope name from it, and passed that to ensure_tool_scope. Every step tolerated a miss, so renaming the server's auth_config attribute resolved a None scope and made the gate return early on every tool at once, silently. Replace the prologue with ensure_read_scope/ensure_write_scope, which resolve the scope field inside auth.py via an undefaulted getattr, and make ensure_tool_scope raise when auth is enabled but its config is unreachable. The tokenless-request exit is unchanged: an authenticated HTTP transport rejects those before a tool body runs.
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.
Motivation
The MCP scope gate can be disabled by a rename, silently. Four tool wrappers each carry an identical three-line prologue that reads
auth_configoff the server, pulls a scope name from it, and hands that toensure_tool_scope. Every step of that chain tolerates a miss:getattr(server, "auth_config", None)yieldsNone, the conditional expression then yields aNonescope, andensure_tool_scopereturns early on aNonescope. So renaming the server'sauth_configattribute stops read and write scopes being enforced on every tool at once, with no error, no warning and no failing test.The prologue is also redundant.
ensure_tool_scopeperforms the samegetattrlookup itself, so the caller's copy exists only to name which scope field applies.Changes
The scope name is resolved inside
auth.pyensure_read_scope(server)andensure_write_scope(server)replace the prologue at all four call sites. Each resolves its own scope field from the server and delegates toensure_tool_scope, so a wrapper no longer needs to know that a read tool readsread_scope.becomes
The field lookup is a bare
getattr(auth_config, attribute)with no default, so renaming a field onMCPAuthConfigraisesAttributeErrorrather than resolving toNoneand turning the gate into a no-op.An unreachable auth config now fails closed
ensure_tool_scopechecks_auth_enabledfirst and, when auth is wired, treats a missingauth_configas an internal inconsistency rather than a reason to skip the check:The tokenless-request exit is unchanged and still returns early. That one is correct: an authenticated HTTP transport rejects tokenless requests before a tool body runs, so a missing token means stdio, where there is no scope to check.
Secondary changes
tools/search.py,tools/upsert.py,tools/list_indexes.py,tools/profiles.py. No wrapper reads anauth_configattribute any more.tests/unit/test_mcp/test_auth_scope.pycovering scope resolution, the auth-disabled no-op, the unreachable-config failure and the renamed-field failure.Notes
Both new guards were mutation-checked: reverting the fail-closed raise alone fails exactly one test, and weakening the bare
getattrto a defaulted one fails exactly one other. Neither guard is decorative.ensure_tool_scopekeeps its signature and stays public, because it is the right entry point for a caller that has a scope name in hand rather than a server to resolve one from. The new helpers are the preferred call-site form and its docstring says so.Next Steps