Skip to content

Commit 3323eb5

Browse files
committed
docs(mcp): comprehensive OAuth scope enforcement documentation
Update MCP docs to cover multi-level scope enforcement including per-tool scopes from @requiresScopes, built-in tool scopes, runtime execute_graphql scope checking, scope challenge behavior, and RFC 9728 metadata with scopes_supported discovery.
1 parent aa7b966 commit 3323eb5

1 file changed

Lines changed: 38 additions & 3 deletions

File tree

docs/router/mcp.mdx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,10 @@ storage_providers:
244244
| `oauth.scope_challenge_include_token_scopes` | When `true`, includes the token's existing scopes in the `scope` parameter of 403 responses. Works around MCP SDK scope accumulation bugs. See [Scope Challenge Behavior](#scope-challenge-behavior). | `false` |
245245
| `oauth.scopes.initialize` | Scopes required for **all** HTTP requests (checked before JSON-RPC parsing). This is the baseline scope needed to establish an MCP connection. | `[]` |
246246
| `oauth.scopes.tools_list` | Scopes required for the `tools/list` MCP method. | `[]` |
247-
| `oauth.scopes.tools_call` | Scopes required for the `tools/call` MCP method (any tool invocation). Per-tool scopes from `@requiresScopes` are enforced additively. | `[]` |
247+
| `oauth.scopes.tools_call` | Scopes required for the `tools/call` MCP method (any tool invocation). Per-tool and built-in tool scopes are enforced additively. | `[]` |
248+
| `oauth.scopes.execute_graphql` | Scopes required to call the `execute_graphql` built-in tool. Additive to `tools_call`. Only relevant when `enable_arbitrary_operations` is `true`. | `[]` |
249+
| `oauth.scopes.get_operation_info` | Scopes required to call the `get_operation_info` built-in tool. Additive to `tools_call`. | `[]` |
250+
| `oauth.scopes.get_schema` | Scopes required to call the `get_schema` built-in tool. Additive to `tools_call`. Only relevant when `expose_schema` is `true`. | `[]` |
248251
| `oauth.jwks` | List of JWKS providers for JWT verification. Supports remote JWKS URLs or symmetric secrets. See [JWKS Configuration](#jwks-configuration). | `[]` |
249252
| `server.base_url` | The public base URL of the MCP server. **Required when OAuth is enabled.** Used for the RFC 9728 metadata endpoint and `resource_metadata` in `WWW-Authenticate` headers. Set this to your externally-reachable URL when behind a reverse proxy or load balancer. | - |
250253

@@ -508,8 +511,9 @@ Scopes are enforced at multiple levels, all at the HTTP transport layer per the
508511
HTTP Request
509512
→ Initialize scopes (all requests)
510513
→ Method scopes (tools/list, tools/call)
511-
→ Per-tool scopes (from @requiresScopes on operation fields)
512-
→ Runtime scopes (execute_graphql only, per-query)
514+
→ Built-in tool scopes (execute_graphql, get_schema, get_operation_info)
515+
→ Per-tool scopes (from @requiresScopes on operation fields)
516+
→ Runtime scopes (execute_graphql only, per-query)
513517
```
514518
515519
#### Initialize Scopes (HTTP Level)
@@ -542,6 +546,27 @@ When both `initialize` and method-level scopes are configured, the token must co
542546
Scopes in the JWT must be provided as a **space-separated string** in the `scope` claim (per OAuth 2.0 convention). Array-format scope claims are not supported.
543547
</Info>
544548

549+
#### Built-in Tool Scopes
550+
551+
The MCP server provides three built-in tools: `execute_graphql`, `get_operation_info`, and `get_schema`. Each can have its own scope requirements, configured independently from `tools_call`:
552+
553+
```yaml
554+
oauth:
555+
scopes:
556+
tools_call:
557+
- "mcp:tools:execute" # Base gate for any tool
558+
execute_graphql:
559+
- "mcp:graphql:execute" # Additional scope for execute_graphql
560+
get_operation_info:
561+
- "mcp:ops:read" # Additional scope for get_operation_info
562+
get_schema:
563+
- "mcp:schema:read" # Additional scope for get_schema
564+
```
565+
566+
Built-in tool scopes are **additive** to `tools_call` — the token must satisfy both. If `tools_call` is empty, only the built-in tool scope is checked.
567+
568+
Scopes for `execute_graphql` are only relevant when `enable_arbitrary_operations: true`, and scopes for `get_schema` are only relevant when `expose_schema: true`. When the corresponding feature is disabled, the tool is not registered and its scopes are excluded from the `scopes_supported` metadata.
569+
545570
#### Per-Tool Scopes (from `@requiresScopes`)
546571

547572
When your GraphQL schema uses the `@requiresScopes` directive on fields, the MCP server automatically extracts scope requirements for each tool at startup. If a tool's underlying GraphQL operation touches fields that require specific scopes, those scopes are enforced when the tool is called.
@@ -583,6 +608,7 @@ This runtime check uses the same OR-of-AND semantics and smart challenge selecti
583608
| --- | --- | --- | --- |
584609
| Initialize | Every HTTP request | `oauth.scopes.initialize` | 403 with required scopes |
585610
| Method | `tools/list`, `tools/call` | `oauth.scopes.tools_list`, `oauth.scopes.tools_call` | 403 with required scopes |
611+
| Built-in tool | `tools/call` for built-in tools | `oauth.scopes.execute_graphql`, `oauth.scopes.get_schema`, `oauth.scopes.get_operation_info` | 403 with required scopes |
586612
| Per-tool | `tools/call` for specific tool | `@requiresScopes` in GraphQL schema | 403 with best scope challenge |
587613
| Runtime | `execute_graphql` calls | `@requiresScopes` in GraphQL schema | 403 with best scope challenge |
588614

@@ -732,6 +758,8 @@ mcp:
732758
base_url: "https://mcp.example.com"
733759
graph_name: "my-graph"
734760
exclude_mutations: true
761+
enable_arbitrary_operations: true # Enables execute_graphql tool
762+
expose_schema: true # Enables get_schema tool
735763
oauth:
736764
enabled: true
737765
authorization_server_url: "https://auth.example.com"
@@ -743,6 +771,13 @@ mcp:
743771
- "mcp:tools:read"
744772
tools_call:
745773
- "mcp:tools:execute"
774+
# Built-in tool scopes (additive to tools_call)
775+
execute_graphql:
776+
- "mcp:graphql:execute"
777+
get_schema:
778+
- "mcp:schema:read"
779+
get_operation_info:
780+
- "mcp:ops:read"
746781
jwks:
747782
- url: "https://auth.example.com/.well-known/jwks.json"
748783
audiences:

0 commit comments

Comments
 (0)