-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Description
Initial Checks
- I confirm that I'm using the latest version of MCP Python SDK
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Description
Summary
The MCP Python SDK server violates the specification requirement that "Authorization servers MUST only accept tokens that are valid for use with their own resources." The server accepts any token without verifying that the token's resource field matches the server's own resource URL.
Issue Details
Rule Violation
MCP Specification: "Authorization servers MUST only accept tokens that are valid for use with their own resources."
Current Implementation Analysis
1. Server Token Validation Flow
File: src/mcp/server/auth/middleware/bearer_auth.py
# Lines 30-49: BearerAuthBackend.authenticate()
async def authenticate(self, conn: HTTPConnection):
# ... extract token ...
# Validate the token with the verifier
auth_info = await self.token_verifier.verify_token(token)
if not auth_info:
return None
if auth_info.expires_at and auth_info.expires_at < int(time.time()):
return None
return AuthCredentials(auth_info.scopes), AuthenticatedUser(auth_info)
# ❌ Missing: No validation of auth_info.resource against server URL
2. What's Currently Validated
The server only checks:
- ✅ Token exists and is loaded successfully
- ✅ Token is not expired
- ✅ Token has required scopes (in RequireAuthMiddleware)
Missing critical validation:
- ❌ Token resource field validation
- ❌ Verification that token is intended for this server
- ❌ Enforcement of "MUST only accept tokens valid for own resources"
3. Available Validation Tool
It's a little weird that I found the available validation function:
File: src/mcp/shared/auth_utils.py
# Lines 30-69: check_resource_allowed() function exists and is fully functional
def check_resource_allowed(requested_resource: str, configured_resource: str) -> bool:
""" Check if a requested resource URL matches a configured resource URL.
A requested resource matches if it has the same scheme, domain, port,
and its path starts with the configured resource's path. This allows
hierarchical matching where a token for a parent resource can be used
for child resources.
"""
4. Evidence of Non-Usage
Grep search results show:
- ✅ Function exists and is tested (36 test cases)
- ✅ Used in client-side resource selection
- ✅ Used in example server implementation
- ❌ NOT used in core server authentication flow
Impact
- Compliance Violation: Fails to meet MCP specification requirement
- Security Risk: Server may accept tokens intended for other resources
- Cross-Resource Token Leakage: Tokens for Server A could be used on Server B(maybe)
Root Cause
It appears that the server treats resource validation as not a mandatory rule, despite the specification's explicit "MUST" requirement. The validation tool exists but is not integrated into the core authentication flow.
Possible Solution
Add resource validation to BearerAuthBackend.authenticate()
:
async def authenticate(self, conn: HTTPConnection):
# ... existing code ...
auth_info = await self.token_verifier.verify_token(token)
if not auth_info:
return None
if auth_info.expires_at and auth_info.expires_at < int(time.time()):
return None
# NEW: Validate token resource matches server resource
if auth_info.resource:
from mcp.shared.auth_utils import check_resource_allowed, resource_url_from_server_url
server_resource = resource_url_from_server_url(conn.url)
if not check_resource_allowed(requested_resource=server_resource, configured_resource=auth_info.resource):
return None # Token not valid for this server
return AuthCredentials(auth_info.scopes), AuthenticatedUser(auth_info)
Files Affected
src/mcp/server/auth/middleware/bearer_auth.py
(lines 30-49)- May need to import
check_resource_allowed
andresource_url_from_server_url
Example Code
Python & MCP Python SDK
latest