-
Notifications
You must be signed in to change notification settings - Fork 461
fix: MCP list operations respect token team scope (#1915) #2016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
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
Previously, tools/list, resources/list, and prompts/list operations
returned unfiltered results regardless of the authenticated token's
team scope. This allowed public access tokens to see private resources
they shouldn't have access to.
Changes:
- Add token_teams parameter to service list functions (tool_service,
resource_service, prompt_service) to filter by token scope instead
of DB team membership lookup
- Add helper functions in main.py to extract and normalize token teams
from JWT payloads (_normalize_token_teams, _get_token_teams_from_request,
_get_rpc_filter_context)
- Wire /rpc and /servers/{id}/tools|resources|prompts endpoints to use
token-based filtering
- Fix SSE token forwarding to read auth from cookies (for admin UI) and
preserve is_admin status in fallback tokens
- Update streamable HTTP auth to check both top-level and nested is_admin
in JWT payloads
- Update token_scoping middleware to allow empty-team tokens access to
owned resources (own + public policy)
- Update admin UI message from "public-only access" to "your own resources
and public resources only"
The empty-team token policy is now "own + public" - users with tokens
that have no teams can see their own resources plus public resources,
not just public resources.
Closes #1915
Signed-off-by: Mihai Criveti <[email protected]>
7 tasks
Member
Author
Test plan1. Reproduce Original Issue (Before Fix)
2. Token Team Scope Filtering2.1 Tools List (
|
Signed-off-by: Mihai Criveti <[email protected]>
Signed-off-by: Mihai Criveti <[email protected]>
Security improvements to token team scoping: - Unify teams claim semantics: missing key or null = unrestricted for admin, public-only for non-admin (secure default) - Admin bypass now requires token_teams is None (not just is_admin flag) - Admin with teams: [] explicitly scoped to public-only resources - Fix inconsistency where /rpc treated missing teams differently than REST - Update session token generation to omit teams for admin users (unrestricted) - Fix all enforcement points: middleware, main.py, services, transports Token scoping rules: - Admin, no teams key: unrestricted (sees all) - Admin, teams: null: unrestricted (same as missing) - Admin, teams: []: public-only (scoped automation token) - Non-admin, no teams: public-only (secure default) - Non-admin, teams: []: public-only Also: - Update UI text to reflect public-only policy for unscoped tokens - Add tests for teams: null handling - Fix docstrings to document correct semantics Signed-off-by: Mihai Criveti <[email protected]>
Add comprehensive documentation for token-based access control: - Token teams claim semantics (missing key, null, empty, explicit teams) - Different behavior for admin vs non-admin users - ASCII flow diagrams for token scoping decision tree - Visibility levels (public, team, private) explanation - Enforcement points across all access layers - Token types and use cases (session, API, automation) - CLI examples for generating scoped tokens - Best practices for token lifecycle and team organization - Troubleshooting guide for common access issues Also add summary table and cross-reference in securing.md. Signed-off-by: Mihai Criveti <[email protected]>
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.
Previously, tools/list, resources/list, and prompts/list operations returned unfiltered results regardless of the authenticated token's team scope. This allowed public access tokens to see private resources they shouldn't have access to.
Token Scoping Security Model
Unified Token Teams Semantics
All enforcement layers (middleware, REST endpoints, RPC, /mcp transport) now follow consistent rules:
Security Design Principles
teams: []are intentionally restricted to public resources (for CI/CD, monitoring)Token Scoping Flow
Enforcement Points Updated
token_scoping.py): Request-level access controlmain.py):/tools,/resources,/prompts,/servers/{id}/*main.py):tools/list,resources/list,prompts/list, legacylist_toolsstreamablehttp_transport.py): MCP protocol filteringtool_service.py,resource_service.py,prompt_service.py): Query filteringMCP List Visibility Fix
Changes:
_normalize_token_teams,_get_token_teams_from_request,_get_rpc_filter_context)Token Details Modal & Scope Display
Added enhanced token visibility in the Admin UI at
/admin/#tokens:Token List Enhancements:
Token Details Modal:
Input Validation
Added comprehensive validation for token scope fields:
Frontend Validation (admin.js):
isValidIpOrCidr()- Validates IPv4/IPv6 addresses and CIDR notation using regexisValidPermission()- Validatesresource.actionformat or wildcard*Backend Validation (schemas.py):
TokenScopeRequest.validate_ip_restrictions()- Uses Python'sipaddressmodule for robust validationTokenScopeRequest.validate_permissions()- Regex pattern matching forresource.actionformatValidation Examples:
192.168.1.1,10.0.0.0/8,::1,2001:db8::/32sfas,192.168.1.256,192.168.1.0/33tools.read,resources.write,*read,tools.,123.readSecurity Improvements
onclickhandlers with event delegation pattern to prevent XSSextractApiError()helper to properly parse Pydantic validation error arraysparseErrorResponse()helper to handle non-JSON error responses (500 errors)Closes #1915