diff --git a/docs-website/docs.json b/docs-website/docs.json
index 8372207002..6abd3fa225 100644
--- a/docs-website/docs.json
+++ b/docs-website/docs.json
@@ -26,10 +26,10 @@
"codeblocks": "system",
"eyebrows": "breadcrumbs"
},
- "banner": {
- "content": "Help map how teams scale Federated GraphQL in the State of Federation 2026 Survey. We donate $30 to UNICEF per response → [Take the survey](https://8bxwlo3ot55.typeform.com/to/zIJKRQUe).",
- "dismissible": false
- },
+ "banner": {
+ "content": "Help map how teams scale Federated GraphQL in the State of Federation 2026 Survey. We donate $30 to UNICEF per response → [Take the survey](https://8bxwlo3ot55.typeform.com/to/zIJKRQUe).",
+ "dismissible": false
+ },
"contextual": {
"options": ["copy", "view", "chatgpt", "claude"]
},
@@ -41,13 +41,7 @@
"groups": [
{
"group": " ",
- "pages": [
- "overview",
- "architecture",
- "enterprise",
- "security-and-compliance",
- "self-hosted"
- ]
+ "pages": ["overview", "architecture", "enterprise", "security-and-compliance", "self-hosted"]
},
{
"group": "Getting Started",
@@ -70,11 +64,7 @@
},
{
"group": "Cosmo Connect",
- "pages": [
- "connect/overview",
- "connect/plugins",
- "connect/grpc-services"
- ]
+ "pages": ["connect/overview", "connect/plugins", "connect/grpc-services"]
},
{
"group": "Cosmo ConnectRPC",
@@ -102,15 +92,32 @@
"router/configuration/template-expressions"
]
},
- "router/mcp",
{
- "group": "Custom Modules",
- "icon": "cubes",
+ "group": "MCP Gateway",
+ "icon": "robot",
"pages": [
- "router/custom-modules",
- "router/custom-modules-migration"
+ "router/mcp",
+ "router/mcp/quickstart",
+ "router/mcp/operations",
+ "router/mcp/configuration",
+ {
+ "group": "OAuth 2.1",
+ "icon": "shield-check",
+ "pages": [
+ "router/mcp/oauth/overview",
+ "router/mcp/oauth/quickstart",
+ "router/mcp/oauth/scopes",
+ "router/mcp/oauth/configuration"
+ ]
+ },
+ "router/mcp/ide-setup"
]
},
+ {
+ "group": "Custom Modules",
+ "icon": "cubes",
+ "pages": ["router/custom-modules", "router/custom-modules-migration"]
+ },
{
"group": "Cosmo Connect",
"icon": "network-wired",
@@ -215,10 +222,7 @@
{
"group": "Deployment",
"icon": "truck-ramp-couch",
- "pages": [
- "router/deployment",
- "router/deployment/config-hot-reload"
- ]
+ "pages": ["router/deployment", "router/deployment/config-hot-reload"]
},
{
"group": "Security",
@@ -234,11 +238,7 @@
{
"group": "Development",
"icon": "flask-round-potion",
- "pages": [
- "router/development",
- "router/development/debugging",
- "router/development/development-mode"
- ]
+ "pages": ["router/development", "router/development/debugging", "router/development/development-mode"]
},
"router/request-deduplication",
"router/performance-debugging",
@@ -246,10 +246,7 @@
{
"group": "Query Plan",
"icon": "file-contract",
- "pages": [
- "router/query-plan",
- "router/query-plan/batch-generate-query-plans"
- ]
+ "pages": ["router/query-plan", "router/query-plan/batch-generate-query-plans"]
},
{
"group": "Cosmo Streams (EDFS)",
@@ -338,11 +335,7 @@
{
"group": "API Keys",
"icon": "key",
- "pages": [
- "studio/api-keys",
- "studio/api-keys/api-key-permissions",
- "studio/api-keys/api-key-resources"
- ]
+ "pages": ["studio/api-keys", "studio/api-keys/api-key-permissions", "studio/api-keys/api-key-resources"]
},
"studio/migrate-from-apollo",
{
@@ -377,11 +370,7 @@
{
"group": "SCIM",
"icon": "file-user",
- "pages": [
- "studio/scim",
- "studio/scim/okta",
- "studio/scim/okta-oin-version"
- ]
+ "pages": ["studio/scim", "studio/scim/okta", "studio/scim/okta-oin-version"]
},
"studio/audit-log",
"studio/cosmo-ai",
@@ -396,11 +385,7 @@
},
{
"group": "Control Plane",
- "pages": [
- "control-plane/intro",
- "control-plane/configuration",
- "control-plane/webhooks"
- ]
+ "pages": ["control-plane/intro", "control-plane/configuration", "control-plane/webhooks"]
},
{
"group": "GraphQL / Federation",
@@ -463,10 +448,7 @@
{
"group": "Terraform",
"icon": "road-bridge",
- "pages": [
- "deployments-and-hosting/terraform",
- "deployments-and-hosting/terraform/aws-fargate"
- ]
+ "pages": ["deployments-and-hosting/terraform", "deployments-and-hosting/terraform/aws-fargate"]
},
"deployments-and-hosting/docker",
"deployments-and-hosting/release-management",
@@ -558,11 +540,7 @@
{
"group": "Version",
"icon": "code-branch",
- "pages": [
- "cli/monograph/version",
- "cli/monograph/version/get",
- "cli/monograph/version/set"
- ]
+ "pages": ["cli/monograph/version", "cli/monograph/version/get", "cli/monograph/version/set"]
}
]
},
@@ -592,10 +570,7 @@
{
"group": "Compatibility version",
"icon": "code-compare",
- "pages": [
- "cli/router/compatibility-version",
- "cli/router/compatibility-version/list"
- ]
+ "pages": ["cli/router/compatibility-version", "cli/router/compatibility-version/list"]
},
{
"group": "Router Plugin",
@@ -629,12 +604,7 @@
{
"group": "Auth",
"icon": "key",
- "pages": [
- "cli/auth",
- "cli/auth/login",
- "cli/auth/whoami",
- "cli/auth/logout"
- ]
+ "pages": ["cli/auth", "cli/auth/login", "cli/auth/whoami", "cli/auth/logout"]
},
{
"group": "Operations",
@@ -678,11 +648,7 @@
{
"group": "Proposal",
"icon": "file-circle-plus",
- "pages": [
- "cli/proposal",
- "cli/proposal/create",
- "cli/proposal/update"
- ]
+ "pages": ["cli/proposal", "cli/proposal/create", "cli/proposal/update"]
}
]
}
diff --git a/docs-website/router/mcp.mdx b/docs-website/router/mcp.mdx
index 0c47124db0..94197ce135 100644
--- a/docs-website/router/mcp.mdx
+++ b/docs-website/router/mcp.mdx
@@ -1,14 +1,13 @@
---
-title: "MCP Gateway"
-description: "Technical guide for using WunderGraph’s MCP Gateway to connect GraphQL APIs to AI models. Covers setup, configuration, and usage examples."
-icon: "robot"
+title: 'MCP Gateway'
+description: 'Connect AI models to your GraphQL APIs using the Model Context Protocol.'
+keywords: ['MCP', 'Model Context Protocol', 'MCP Gateway', 'Claude', 'Cursor', 'Windsurf', 'AI', 'GraphQL']
+icon: 'robot'
---
-# AI Integration with Model Context Protocol (MCP)
-
For a high-level introduction, see the [MCP Gateway overview](https://wundergraph.com/mcp-gateway).
-WunderGraph’s MCP Gateway is a feature of the Cosmo Router that enables AI models to interact with your GraphQL APIs using a structured protocol. This guide explains how to configure and use MCP safely and effectively.
+WunderGraph's MCP Gateway is a feature of the Cosmo Router that enables AI models to interact with your GraphQL APIs using a structured protocol. We can expose a predefined set of safelisted operations, or capabilities as MCP tools, or allow agents to execute GraphQL directly.
+We support only the latest MCP specification `2025-06-18` with Streamable HTTP support.
+
## What is MCP?
MCP (Model Context Protocol) is a protocol designed to help AI models interact with your APIs by providing context, schema information, and a standardized interface. The Cosmo Router implements an MCP server that exposes your GraphQL operations as tools that AI models can use.
- MCP enables AI models to understand and interact with your GraphQL API without
- requiring custom integration code for each model.
+ MCP enables AI models to understand and interact with your GraphQL API without requiring custom integration code for
+ each model.
-
- We support only the latest MCP specification `2025-06-18` with Streamable HTTP
- support.
-
-
The Cosmo MCP Server builds on top of the concept of persisted operations (also known as persisted queries or trusted documents). Instead of allowing AI models to execute arbitrary GraphQL operations, it exposes a predefined set of validated and approved operations. This provides a secure and controlled way for AI systems to interact with your data while maintaining tight control over what operations can be executed.
-## Capabilities Provided by MCP
+## Capabilities
- Make your GraphQL API automatically discoverable by AI models like OpenAI,
- Claude, and Cursor
+ Make your GraphQL API automatically discoverable by AI models like OpenAI, Claude, and Cursor
- Provide detailed schema information and input requirements for each
- operation
+ Provide detailed schema information and input requirements for each operation
- Enable controlled, precise access to your data with operation-level
- granularity
+ Enable controlled, precise access to your data with operation-level granularity and [OAuth 2.1
+ authorization](/router/mcp/oauth/overview)
- Empower AI assistants to work with your application's data through a
- standardized interface
+ Empower AI assistants to work with your application's data through a standardized interface
-## Why Use GraphQL with MCP?
+## Get Started
-The integration of GraphQL with MCP creates a uniquely powerful system for AI-API interactions:
+
+
+ Get MCP running in 5 minutes with a minimal configuration and your first operation.
+
+
+ Connect Claude, Cursor, Windsurf, VS Code, and other AI tools to your MCP server.
+
+
+ Learn how to create, describe, and organize GraphQL operations for AI consumption.
+
+
-- **Precise data selection**: GraphQL's nature allows you to define exactly what data AI models can access, from simple queries to complex operations across your entire graph.
-- **Declarative operation definition**: Create purpose-built `.graphql` files with operations tailored specifically for AI consumption. These function as persisted operations (trusted documents), giving you complete control over what queries AI models can execute.
-- **Self-documenting operations**: Using the September 2025 GraphQL spec, you can embed rich descriptions directly in your operation definitions, making them immediately understandable to AI models without external documentation.
-- **Flexible data exposure**: Control exactly which operations and fields are exposed to AI systems with granular precision.
-- **Compositional API design**: Build different operation sets for different AI use cases without changing your underlying API.
-- **Runtime safety**: GraphQL's strong typing ensures AI models can only request valid data patterns that match your schema.
-- **Built-in validation**: Operation validation prevents malformed queries from ever reaching your backend systems.
-- **Evolve without breaking**: Change your underlying data model while maintaining stable AI-facing operations.
-- **Federation-ready**: Works seamlessly with federated GraphQL schemas, giving AI access to data across your entire organization.
+
+
+ Full reference for all MCP configuration options, sessions, and storage providers.
+
+
+ Secure your MCP server with JWT-based authentication and multi-level scope enforcement.
+
+
+ Use the Cosmo MCP Server in your IDE for schema exploration, dream queries, and more.
+
+
+
+## Why GraphQL with MCP?
+
+The integration of GraphQL with MCP creates a uniquely powerful system for AI-API interactions:
-But what does this mean in practice? How do these technical benefits translate to real-world solutions? To truly understand the transformative power of GraphQL with MCP, let's explore a common scenario that organizations face when integrating AI with their existing systems.
+- **Precise data selection** — GraphQL's nature allows you to define exactly what data AI models can access, from simple queries to complex operations across your entire graph.
+- **Declarative operation definition** — Create purpose-built `.graphql` files with operations tailored specifically for AI consumption. These function as persisted operations (trusted documents), giving you complete control over what queries AI models can execute.
+- **Self-documenting operations** — Using the September 2025 GraphQL spec, you can embed rich descriptions directly in your operation definitions, making them immediately understandable to AI models without external documentation.
+- **Flexible data exposure** — Control exactly which operations and fields are exposed to AI systems with granular precision.
+- **Compositional API design** — Build different operation sets for different AI use cases without changing your underlying API.
+- **Runtime safety** — GraphQL's strong typing ensures AI models can only request valid data patterns that match your schema.
+- **Built-in validation** — Operation validation prevents malformed queries from ever reaching your backend systems.
+- **Evolve without breaking** — Change your underlying data model while maintaining stable AI-facing operations.
+- **Federation-ready** — Works seamlessly with federated GraphQL schemas, giving AI access to data across your entire organization.
## Real-World Example: AI Integration in Finance
-A large financial services company needed to integrate AI assistants into their support workflow—but faced a critical problem: how to allow access to transaction data without exposing sensitive financial details or breaching compliance.
+A large financial services company needed to integrate AI assistants into their support workflow — but faced a critical problem: how to allow access to transaction data without exposing sensitive financial details or breaching compliance.
- Without proper data boundaries, AI models might inadvertently access or expose
- sensitive customer information, creating security and compliance risks.
+ Without proper data boundaries, AI models might inadvertently access or expose sensitive customer information,
+ creating security and compliance risks.
Their existing REST APIs posed three major challenges:
@@ -89,7 +106,7 @@ Their existing REST APIs posed three major challenges:
### Using GraphQL and MCP to Define a Safe Access Layer
-The team adopted GraphQL with the Model Context Protocol (MCP) to expose only specific operations tailored for AI access. By using operation descriptions (following the September 2025 GraphQL spec), they could provide clear context to AI models about what each operation does and its limitations:
+The team adopted GraphQL with MCP to expose only specific operations tailored for AI access. By using operation descriptions (following the September 2025 GraphQL spec), they could provide clear context to AI models about what each operation does and its limitations:
```graphql
"""
@@ -113,6 +130,7 @@ query GetTransactionHistory($accountId: ID!, $last: Int!) {
```
The operation description becomes the tool description that AI models see, helping them understand:
+
- What data the operation provides
- What sensitive information is excluded
- When to use this operation appropriately
@@ -136,11 +154,9 @@ This approach helped the company:
- Maintain a single source of truth for internal and AI clients
- Future-proof their integration as the API evolved
-By combining GraphQL and MCP, they enabled a secure, flexible interface for AI models without having to rewrite their backend.
-
## How It Works
-The Cosmo Router server:
+The Cosmo Router MCP server:
1. Loads GraphQL operations from a specified directory
2. Validates them against your schema
@@ -164,15 +180,12 @@ The MCP server provides several tools out of the box to help AI models discover
- Retrieves detailed information about a specific GraphQL operation, including
- its input schema, query structure, and execution guidance. AI models use
- this to understand how to properly call an operation in real-world
- scenarios.
+ Retrieves detailed information about a specific GraphQL operation, including its input schema, query structure, and
+ execution guidance. AI models use this to understand how to properly call an operation in real-world scenarios.
- Provides the full GraphQL schema as a string. This helps AI models
- understand the entire API structure. This tool is only available if
- `expose_schema` is enabled.
+ Provides the full GraphQL schema as a string. This helps AI models understand the entire API structure. This tool is
+ only available if `expose_schema` is enabled.
@@ -187,351 +200,6 @@ The MCP server provides several tools out of the box to help AI models discover
-## Tool Naming and Schema Generation
-
-The operation execution tools provide a structured and controlled way for AI models to interact with your API:
-
-- **Tool naming**: Tools follow the pattern `execute_operation_` (with operation names converted to snake_case)
-- **Tool schema**: Generated from your GraphQL operation's variables, ensuring type safety
-- **Tool description**: Extracted from your GraphQL operation's description string (following the September 2025 GraphQL spec) or from comment-based descriptions. The description provides context to help AI models understand the operation's purpose.
-- **Mutation warnings**: Tools for mutation operations include a warning that the operation has side effects
-
-By default, all operations in your specified directory will be exposed as tools. Use the `exclude_mutations: true` configuration option to prevent mutation operations from being exposed if you want to ensure AI models can only read data.
-
-## Configuration
-
-To enable MCP in your Cosmo Router, add the following configuration to your `config.yaml`:
-
-```yaml
-mcp:
- enabled: true
- server:
- listen_addr: "localhost:5025"
- router_url: "https://your-public-router-url.example.com/graphql" # Optional: Used in MCP responses when your router is behind a proxy
- storage:
- provider_id: "mcp" # References a file_system provider defined below
- session:
- stateless: true # Optional: When true, no server-side session state is kept
- graph_name: "my-graph"
- exclude_mutations: true
- enable_arbitrary_operations: false
- expose_schema: false
- omit_tool_name_prefix: false # When true: GetUser → get_user (no execute_operation_ prefix)
-
-# Configure storage providers
-storage_providers:
- file_system:
- - id: "mcp"
- path: "operations" # Relative to the router binary
-```
-
-### Configuration Options
-
-| Option | Description | Default |
-| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
-| `enabled` | Enable or disable the MCP server | `false` |
-| `server.listen_addr` | The address and port where the MCP server will listen for requests | `localhost:5025` |
-| `router_url` | Custom URL to use for the router GraphQL endpoint in MCP responses. Use this when your router is behind a proxy. | - |
-| `storage.provider_id` | The ID of a storage provider to use for loading GraphQL operations. Only file_system providers are supported. | - |
-| `session.stateless` | Whether the MCP server should operate in stateless mode. When true, no server-side session state is maintained between requests. | `true` |
-| `graph_name` | The name of the graph this router exposes via MCP. Used to build the MCP server name (wundergraph-cosmo-$graph_name) and for logging; it does not select a different graph. | `mygraph` |
-| `exclude_mutations` | Whether to exclude mutation operations from being exposed | `false` |
-| `enable_arbitrary_operations` | Whether to allow arbitrary GraphQL operations to be executed. Security risk: Should only be enabled in secure, internal environments. | `false` |
-| `expose_schema` | Whether to expose the full GraphQL schema. Security risk: Should only be enabled in secure, internal environments. | `false` |
-| `omit_tool_name_prefix` | When enabled, MCP tool names generated from GraphQL operations omit the `execute_operation_` prefix. For example, the GraphQL operation `GetUser` results in a tool named `get_user` instead of `execute_operation_get_user`. This produces shorter tool names and is entirely optional. Can also be set via `MCP_OMIT_TOOL_NAME_PREFIX` environment variable. | `false` |
-
-## Session Handling
-
-By default, the MCP server runs in stateless mode (`session.stateless: true`). This avoids scalability issues in load‑balanced or serverless environments where sticky sessions may not be guaranteed. In stateless mode, no session data is retained between requests.
-
-In stateless mode, features that rely on long‑lived connections or server‑side session state are unavailable or limited:
-
-- No sampling
-- No elicitation flows
-- No session resumability
-- No bidirectional messaging (e.g. Notifications)
-
-### Stateful mode (sticky sessions required)
-
-If you set `session.stateless: false`, the MCP server maintains per‑session state. To ensure all requests for a session reach the same Router instance, configure sticky sessions keyed by `Mcp-Session-Id`:
-
-- The Router returns a unique `Mcp-Session-Id` response header when a session is established.
-- Clients must include that value in subsequent requests as the `Mcp-Session-Id` request header.
-- Your load balancer or reverse proxy must route requests with the same `Mcp-Session-Id` to the same instance.
-
-For details, see your load balancer or reverse proxy documentation (e.g., [F5 NGINX Plus - MCP Session Affinity](https://community.f5.com/kb/technicalarticles/mcp-session-affinity-with-f5-nginx-plus/341961)).
-
-### Session Storage
-
-In the future, we may add persistent session storage (e.g., Redis) to the MCP server. This would enable shared session state across instances and unlock features such as session‑based security, resource subscriptions, and bidirectional messaging without the need to solve it on the load balancer level.
-
-## Storage Providers
-
-MCP loads operations from a configured file system storage provider. This allows you to centralize the configuration of operation sources:
-
-```yaml
-storage_providers:
- file_system:
- - id: "mcp"
- path: "operations" # Relative to the router binary
-```
-
-Then reference this storage provider in your MCP configuration:
-
-```yaml
-mcp:
- storage:
- provider_id: "mcp"
-```
-
-A storage provider must be specified to load GraphQL operations.
-
-## Setting Up Operations
-
-1. Create a directory to store your GraphQL operations as specified in your `storage.provider_id` configuration.
-2. Add `.graphql` files containing named GraphQL operations.
-
-Each operation file should contain a single named operation. You can provide descriptions for AI models in two ways:
-
-1. **Operation description strings** (recommended, following September 2025 GraphQL spec)
-2. **Comment-based descriptions** (legacy approach)
-
-### Example Query Operation with Description String
-
-Create a file `operations/getUsers.graphql`:
-
-```graphql
-"""
-Returns a list of all users in the system with their basic information.
-This is a read-only operation that doesn't modify any data.
-"""
-query GetUsers {
- users {
- id
- name
- email
- }
-}
-```
-
-### Example Query Operation with Comment-Based Description
-
-Alternatively, you can use comment-based descriptions:
-
-```graphql
-# Returns a list of all users in the system with their basic information
-# This is a read-only operation that doesn't modify any data
-query GetUsers {
- users {
- id
- name
- email
- }
-}
-```
-
-### Example Mutation Operation
-
-Create a file `operations/createUser.graphql`:
-
-```graphql
-"""
-Creates a new user in the system.
-Required inputs: name and email
-"""
-mutation CreateUser($name: String!, $email: String!) {
- createUser(input: { name: $name, email: $email }) {
- id
- name
- email
- }
-}
-```
-
-### Directory Structure
-
-Here's an example of how your project directory might be structured:
-
-```
-my-router-project/
-├── config.yaml # Router configuration file
-├── operations/ # Operations directory (as configured in storage provider)
-│ ├── getUsers.graphql # Query operation
-│ ├── createUser.graphql # Mutation operation
-│ ├── getUserById.graphql # Query with parameters
-└── ...
-```
-
-The important points:
-
-- The path in your `storage_providers.file_system.path` should point to the operations directory
-- All `.graphql` files in this directory (and subdirectories) will be loaded
-- Each file should contain a single named GraphQL operation
-
-### Operation Naming and Tool Generation
-
-The MCP server converts each operation into a corresponding tool:
-
-- Operation name: `GetUsers` → Tool name: `execute_operation_get_users`
-- Operation name: `CreateUser` → Tool name: `execute_operation_create_user`
-
-Operations are converted to snake_case for tool naming consistency.
-
-#### Omitting the Tool Name Prefix
-
-By default, all operation tools include the `execute_operation_` prefix:
-
-- `GetUsers` becomes `execute_operation_get_users`
-- `CreateUser` becomes `execute_operation_create_user`
-
-When enabled, the `omit_tool_name_prefix` option generates tool names without this prefix:
-
-```yaml
-mcp:
- enabled: true
- omit_tool_name_prefix: true
-```
-
-- `GetUsers` becomes `get_users`
-- `CreateUser` becomes `create_user`
-
-
-Enabling this option changes all tool names and may break existing integrations that rely on the `execute_operation_` prefix. Only enable this for new deployments or when you can update all dependent systems.
-
-
-
-Operations with names that would collide with built-in MCP tools (`get_schema`, `execute_graphql`, `get_operation_info`) automatically retain the `execute_operation_` prefix to prevent conflicts.
-
-
-### Best Practices
-
-1. **Meaningful names**: Give operations clear, action-oriented names that describe what they do.
-2. **Add descriptions**: Use operation description strings (triple-quoted strings `"""`) following the September 2025 GraphQL spec to describe the operation's purpose, required inputs, and any side effects. These descriptions become the tool descriptions that AI models use to understand your operations.
-3. **Use explicit types**: Define all input variables with explicit types to ensure proper validation.
-4. **Create focused operations**: Design operations specifically for AI model consumption rather than exposing generic operations.
-5. **Security considerations**: For mutation operations, add checks and validations to prevent misuse.
-
-## Header Forwarding
-
-
- Available since Router [0.260.0](https://github.com/wundergraph/cosmo/releases/tag/router%400.260.0)
-
-
-The MCP server forwards **all headers** from MCP clients to the Router, including authorization headers, custom headers, and tracing headers. This allows you to:
-
-- Leverage all authentication and authorization capabilities of your Cosmo Router
-- Pass custom headers for tracing, debugging, or application-specific purposes
-- Maintain consistent security and observability across all API consumers
-
-
- All headers sent by MCP clients are forwarded through the complete chain: MCP Client -> MCP Server -> Router -> Subgraphs. The router's [header forwarding rules](/router/proxy-capabilities/subgraph-request-header-operations) determine what ultimately reaches your subgraphs.
-
-
-### Common Use Cases
-
-#### Authentication & Authorization
-
-Pass authorization tokens to secure your GraphQL operations
-
-```json
-{
- "headers": {
- "Authorization": "Bearer YOUR_API_KEY"
- }
-}
-```
-
-#### Tracing
-
-Include trace IDs for request correlation and debugging
-```json
-{
- "headers": {
- "X-Trace-Id": "trace-123",
- "X-Request-Id": "req-456"
- }
-}
-```
-
-#### Custom Headers
-
-Pass application-specific headers for business logic
-```json
-{
- "headers": {
- "X-Tenant-Id": "tenant-abc",
- "X-Feature-Flag": "new-feature-enabled"
- }
-}
-```
-
-## Installation Guides
-
-Headers can be configured in various AI tools and environments:
-
-### Claude
-
-Requires latest version of Claude Desktop.
-
-Go to `Settings` > `Developer` and click on `Edit Config`. Add the following to the `claude_desktop_config.json` file:
-
-```json
-{
- "mcpServers": {
- "mygraph": {
- "command": "npx",
- "args": ["-y", "mcp-remote", "http://localhost:5025/mcp"]
- }
- }
-}
-```
-
-After that, you need to restart Claude Desktop.
-
-### Cursor
-
-Requires Cursor v0.48.0+ for Streamable HTTP support.
-
-Go to `Settings` > `Tools & Integrations` > `MCP Servers` and add the following to the `mcp.json` file:
-
-```json
-{
- "mcpServers": {
- "mygraph": {
- "url": "http://localhost:5025/mcp",
- "headers": {
- "Authorization": "Bearer YOUR_API_KEY", // Optional: Auth
- "X-Trace-Id": "cursor-session-123", // Optional: Custom headers
- "X-Client": "cursor" // Optional: Client identification
- }
- }
- }
-}
-```
-
-### Windsurf
-
-Windsurf supports Streamable HTTP servers with a `serverUrl` field:
-
-```json
-{
- "mcpServers": {
- "mygraph": {
- "serverUrl": "http://localhost:5025/mcp",
- "headers": {
- "Authorization": "Bearer YOUR_API_KEY", // Optional: Auth
- "X-Trace-Id": "windsurf-session-456", // Optional: Custom headers
- "X-Client": "windsurf" // Optional: Client identification
- }
- }
- }
-}
-```
-
-### VS Code
-
-Click `View` > `Command Palette` > `"MCP: Add Server"` and use the URL `http://localhost:5025/mcp` to complete the configuration. For more information, see the [MCP Servers](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) documentation.
-
-### Other MCP-compatible Tools
-
-Other tools and AI models that support the MCP protocol typically provide similar ways to configure authentication headers. Always check the documentation for your specific AI tool for the exact configuration syntax.
+
+ Ready to get started? Follow the quickstart guide to have MCP running in 5 minutes.
+
diff --git a/docs-website/router/mcp/configuration.mdx b/docs-website/router/mcp/configuration.mdx
new file mode 100644
index 0000000000..4c0a5eac14
--- /dev/null
+++ b/docs-website/router/mcp/configuration.mdx
@@ -0,0 +1,122 @@
+---
+title: 'Configuration'
+description: 'Complete reference for all MCP Gateway configuration options, including session handling, storage providers, and environment variables.'
+icon: 'sliders-up'
+---
+
+## Basic Configuration
+
+To enable MCP in your Cosmo Router, add the following to your `config.yaml`:
+
+```yaml
+mcp:
+ enabled: true
+ server:
+ listen_addr: 'localhost:5025'
+ graph_name: 'my-graph'
+ exclude_mutations: true
+ storage:
+ provider_id: 'mcp'
+
+storage_providers:
+ file_system:
+ - id: 'mcp'
+ path: 'operations'
+```
+
+## Configuration Options
+
+| Option | Description | Default |
+| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
+| `enabled` | Enable or disable the MCP server | `false` |
+| `server.listen_addr` | The address and port where the MCP server will listen for requests | `localhost:5025` |
+| `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. | - |
+| `router_url` | Custom URL to use for the router GraphQL endpoint in MCP responses. Use this when your router is behind a proxy. | - |
+| `storage.provider_id` | The ID of a storage provider to use for loading GraphQL operations. Only `file_system` providers are supported. | - |
+| `session.stateless` | Whether the MCP server should operate in stateless mode. When `true`, no server-side session state is maintained between requests. | `true` |
+| `graph_name` | The name of the graph this router exposes via MCP. Converted to kebab-case and used to build the MCP server name (`wundergraph-cosmo-`) and for logging; it does not select a different graph. For example, `MyGraph` becomes `wundergraph-cosmo-my-graph`. | `mygraph` |
+| `exclude_mutations` | Whether to exclude mutation operations from being exposed | `false` |
+| `enable_arbitrary_operations` | Enables the `execute_graphql` built-in tool, allowing clients to run arbitrary GraphQL operations beyond the pre-defined operation set. | `false` |
+| `expose_schema` | Enables the `get_schema` built-in tool, exposing the full GraphQL schema to MCP clients. | `false` |
+| `omit_tool_name_prefix` | When enabled, MCP tool names omit the `execute_operation_` prefix. For example, `GetUser` becomes `get_user` instead of `execute_operation_get_user`. See [Operations - Omitting the Tool Name Prefix](/router/mcp/operations#omitting-the-tool-name-prefix). | `false` |
+
+For OAuth-specific configuration, see [OAuth 2.1 Authorization](/router/mcp/oauth/overview).
+
+## Environment Variables
+
+All MCP options can also be set via environment variables:
+
+| Environment Variable | Configuration Path |
+| --------------------------------- | --------------------------------- |
+| `MCP_ENABLED` | `mcp.enabled` |
+| `MCP_SERVER_LISTEN_ADDR` | `mcp.server.listen_addr` |
+| `MCP_SERVER_BASE_URL` | `mcp.server.base_url` |
+| `MCP_ROUTER_URL` | `mcp.router_url` |
+| `MCP_STORAGE_PROVIDER_ID` | `mcp.storage.provider_id` |
+| `MCP_SESSION_STATELESS` | `mcp.session.stateless` |
+| `MCP_GRAPH_NAME` | `mcp.graph_name` |
+| `MCP_EXCLUDE_MUTATIONS` | `mcp.exclude_mutations` |
+| `MCP_ENABLE_ARBITRARY_OPERATIONS` | `mcp.enable_arbitrary_operations` |
+| `MCP_EXPOSE_SCHEMA` | `mcp.expose_schema` |
+| `MCP_OMIT_TOOL_NAME_PREFIX` | `mcp.omit_tool_name_prefix` |
+
+For OAuth-related environment variables, see [OAuth Configuration Reference](/router/mcp/oauth/configuration#environment-variables).
+
+## Storage Providers
+
+MCP loads operations from a configured storage provider. Currently, only the `file_system` provider is supported:
+
+```yaml
+storage_providers:
+ file_system:
+ - id: 'mcp'
+ path: 'operations' # Relative to the router binary
+```
+
+Then reference this storage provider in your MCP configuration:
+
+```yaml
+mcp:
+ storage:
+ provider_id: 'mcp'
+```
+
+A storage provider **must** be specified to load GraphQL operations. See [Storage Providers](/router/storage-providers) for more details on configuring storage providers.
+
+## Session Handling
+
+The MCP server uses the Streamable HTTP transport and maintains per-session state via the `Mcp-Session-Id` header. When deploying multiple Router instances, you need **sticky sessions** to ensure all requests for a session reach the same instance.
+
+To configure sticky sessions:
+
+1. The Router returns a unique `Mcp-Session-Id` response header when a session is established
+2. Clients must include that value in subsequent requests as the `Mcp-Session-Id` request header
+3. Your load balancer or reverse proxy must route requests with the same `Mcp-Session-Id` to the same instance
+
+For details, see your load balancer or reverse proxy documentation (e.g., [F5 NGINX Plus - MCP Session Affinity](https://community.f5.com/kb/technicalarticles/mcp-session-affinity-with-f5-nginx-plus/341961)).
+
+## CORS
+
+The MCP server automatically configures CORS to allow cross-origin requests from MCP clients. It sets `Access-Control-Allow-Origin: *` and allows the required MCP headers (`Mcp-Protocol-Version`, `Mcp-Session-Id`, `Authorization`, `Last-Event-ID`). The `Mcp-Session-Id` and `WWW-Authenticate` headers are exposed in responses. If you have additional CORS headers configured on the router, they are merged with the MCP-specific headers.
+
+## Full Configuration Example
+
+```yaml
+mcp:
+ enabled: true
+ server:
+ listen_addr: 'localhost:5025'
+ router_url: 'https://your-public-router-url.example.com/graphql'
+ graph_name: 'my-graph'
+ exclude_mutations: true
+ enable_arbitrary_operations: false
+ expose_schema: false
+ omit_tool_name_prefix: false
+ storage:
+ provider_id: 'mcp'
+
+storage_providers:
+ file_system:
+ - id: 'mcp'
+ path: 'operations'
+```
diff --git a/docs-website/router/mcp/ide-setup.mdx b/docs-website/router/mcp/ide-setup.mdx
new file mode 100644
index 0000000000..7c705914f4
--- /dev/null
+++ b/docs-website/router/mcp/ide-setup.mdx
@@ -0,0 +1,135 @@
+---
+title: 'IDE & AI Tool Setup'
+description: 'Connect AI tools to your MCP Gateway. Includes header forwarding for authentication and tracing.'
+keywords: ['MCP', 'Claude Desktop', 'Cursor', 'Windsurf', 'VS Code', 'IDE', 'AI tools']
+icon: 'display-code'
+---
+
+This guide covers how to connect popular AI tools to your Cosmo Router MCP server and configure header forwarding for authentication, tracing, and custom headers.
+
+## Header Forwarding
+
+Available since Router [0.260.0](https://github.com/wundergraph/cosmo/releases/tag/router%400.260.0)
+
+The MCP server forwards most client headers to the Router - including authorization, custom, and tracing headers - but skips hop-by-hop and content negotiation headers (defined in [`headers.SkippedHeaders`](https://github.com/wundergraph/cosmo/blob/main/router/internal/headers/headers.go)). This allows you to:
+
+- Leverage all authentication and authorization capabilities of your Cosmo Router
+- Pass custom headers for tracing, debugging, or application-specific purposes
+- Maintain consistent security and observability across all API consumers
+
+
+ Headers are forwarded through the chain: MCP Client -> MCP Server -> Router -> Subgraphs. The router's
+ [header forwarding rules](/router/proxy-capabilities/subgraph-request-header-operations) determine what ultimately
+ reaches your subgraphs.
+
+
+## IDE Setup Guides
+
+### Cursor
+
+Requires Cursor v0.48.0+ for Streamable HTTP support.
+
+Go to **Settings** > **Tools & Integrations** > **MCP Servers** and add the following to the `mcp.json` file:
+
+```json
+{
+ "mcpServers": {
+ "my-graph": {
+ "url": "http://localhost:5025/mcp",
+ "headers": {
+ "Authorization": "Bearer YOUR_API_KEY",
+ "X-Trace-Id": "cursor-session-123",
+ "X-Client": "cursor"
+ }
+ }
+ }
+}
+```
+
+All `headers` fields are optional - include only what your setup requires.
+
+### Claude Desktop
+
+Requires the latest version of Claude Desktop. Go to **Settings** > **Developer** and click on **Edit Config**. Add the following to the `claude_desktop_config.json` file:
+
+```json
+{
+ "mcpServers": {
+ "my-graph": {
+ "command": "npx",
+ "args": ["-y", "mcp-remote", "http://localhost:5025/mcp"]
+ }
+ }
+}
+```
+
+After saving, **restart Claude Desktop** for changes to take effect.
+
+### Windsurf
+
+Windsurf supports Streamable HTTP servers with a `serverUrl` field:
+
+```json
+{
+ "mcpServers": {
+ "my-graph": {
+ "serverUrl": "http://localhost:5025/mcp",
+ "headers": {
+ "Authorization": "Bearer YOUR_API_KEY",
+ "X-Trace-Id": "windsurf-session-456",
+ "X-Client": "windsurf"
+ }
+ }
+ }
+}
+```
+
+### VS Code
+
+Click **View** > **Command Palette** > **MCP: Add Server** and use the URL `http://localhost:5025/mcp` to complete the configuration.
+
+For more information, see the [VS Code MCP Servers documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers).
+
+### Other MCP-compatible Tools
+
+Other tools and AI models that support the MCP protocol typically provide similar ways to configure the server URL and authentication headers. Check the documentation for your specific AI tool for the exact configuration syntax.
+
+## Common Header Patterns
+
+### Authentication & Authorization
+
+Pass authorization tokens to secure your GraphQL operations:
+
+```json
+{
+ "headers": {
+ "Authorization": "Bearer YOUR_API_KEY"
+ }
+}
+```
+
+### Tracing
+
+Include trace IDs for request correlation and debugging:
+
+```json
+{
+ "headers": {
+ "X-Trace-Id": "trace-123",
+ "X-Request-Id": "req-456"
+ }
+}
+```
+
+### Custom Headers
+
+Pass application-specific headers for business logic:
+
+```json
+{
+ "headers": {
+ "X-Tenant-Id": "tenant-abc",
+ "X-Feature-Flag": "new-feature-enabled"
+ }
+}
+```
diff --git a/docs-website/router/mcp/oauth/configuration.mdx b/docs-website/router/mcp/oauth/configuration.mdx
new file mode 100644
index 0000000000..054f288906
--- /dev/null
+++ b/docs-website/router/mcp/oauth/configuration.mdx
@@ -0,0 +1,205 @@
+---
+title: 'OAuth Configuration Reference'
+description: 'Complete reference for all MCP OAuth configuration options, JWKS settings, environment variables, error responses, and RFC 9728 metadata.'
+icon: 'sliders-up'
+---
+
+## Configuration Options
+
+| Option | Description | Default |
+| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
+| `oauth.enabled` | Enable OAuth 2.1 / JWKS-based authentication for the MCP server | `false` |
+| `oauth.authorization_server_url` | Base URL of the OAuth 2.0 authorization server. Advertised via the [RFC 9728 metadata endpoint](#rfc-9728-protected-resource-metadata) so clients can discover authorization endpoints. | - |
+| `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](/router/mcp/oauth/scopes#scope-challenge-behavior). | `false` |
+| `oauth.max_scope_combinations` | Maximum scope combinations computed per operation. Raise for schemas with many overlapping `@requiresScopes`. | `2048` |
+| `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. | `[]` |
+| `oauth.scopes.tools_list` | Scopes required for the `tools/list` MCP method. | `[]` |
+| `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. | `[]` |
+| `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`. | `[]` |
+| `oauth.scopes.get_operation_info` | Scopes required to call the `get_operation_info` built-in tool. Additive to `tools_call`. | `[]` |
+| `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`. | `[]` |
+| `oauth.jwks` | List of JWKS providers for JWT verification. Supports remote JWKS URLs or symmetric secrets. | `[]` |
+
+## JWKS Configuration
+
+The `oauth.jwks` array configures one or more JWKS providers for JWT verification.
+
+### Remote JWKS URL
+
+```yaml
+oauth:
+ jwks:
+ - url: 'https://auth.example.com/.well-known/jwks.json'
+ audiences:
+ - 'https://mcp.example.com'
+ algorithms:
+ - 'RS256'
+ - 'ES256'
+ refresh_interval: '1m' # How often to refresh the key set
+```
+
+| Field | Description | Default |
+| ------------------ | ------------------------------------------------------------- | ---------- |
+| `url` | URL of the JWKS endpoint | (required) |
+| `audiences` | Allowed JWT `aud` claim values | (any) |
+| `algorithms` | Allowed signing algorithms (RS256, ES256, PS256, EdDSA, etc.) | (all) |
+| `refresh_interval` | How often to refresh the JWKS key set | `1m` |
+
+For the full JWKS configuration reference including all options (`refresh_unknown_kid`, `allowed_use`, etc.), see [Router Authentication](/router/authentication-and-authorization).
+
+### Symmetric Secret
+
+For development or testing, you can use a shared symmetric secret instead of a remote JWKS endpoint:
+
+```yaml
+oauth:
+ jwks:
+ - secret: 'your-shared-secret'
+ symmetric_algorithm: 'HS256' # HS256, HS384, or HS512. For other algorithms, use a remote JWKS URL.
+ header_key_id: 'my-key-id'
+```
+
+## Environment Variables
+
+| Environment Variable | Configuration Path |
+| ------------------------------------------------ | ------------------------------------------------ |
+| `MCP_OAUTH_ENABLED` | `mcp.oauth.enabled` |
+| `MCP_OAUTH_AUTHORIZATION_SERVER_URL` | `mcp.oauth.authorization_server_url` |
+| `MCP_OAUTH_SCOPE_CHALLENGE_INCLUDE_TOKEN_SCOPES` | `mcp.oauth.scope_challenge_include_token_scopes` |
+| `MCP_OAUTH_MAX_SCOPE_COMBINATIONS` | `mcp.oauth.max_scope_combinations` |
+
+## HTTP Error Responses
+
+### 401 Unauthorized
+
+Returned when the token is missing, invalid, expired, or signature verification fails.
+
+```
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Bearer realm="mcp",
+ scope="mcp:connect",
+ resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp"
+```
+
+The `scope` parameter contains the `initialize` scopes (minimum scopes needed to connect). The `resource_metadata` URL points to the [RFC 9728 metadata endpoint](#rfc-9728-protected-resource-metadata) for OAuth discovery.
+
+### 403 Forbidden
+
+Returned when the token is valid but lacks required scopes. The exact `scope` parameter depends on which level of enforcement rejected the request:
+
+**Method-level rejection** (e.g., missing `tools_call` scopes):
+
+```
+HTTP/1.1 403 Forbidden
+WWW-Authenticate: Bearer error="insufficient_scope",
+ scope="mcp:tools:execute",
+ resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp",
+ error_description="missing required scopes: mcp:tools:execute"
+```
+
+**Per-tool rejection** (e.g., calling a tool that requires `read:fact`):
+
+```
+HTTP/1.1 403 Forbidden
+WWW-Authenticate: Bearer error="insufficient_scope",
+ scope="read:fact",
+ resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp",
+ error_description="insufficient scopes for tool execute_operation_get_top_secret_facts"
+```
+
+The `scope` parameter always contains only the scopes needed for the specific operation that failed (unless `scope_challenge_include_token_scopes` is enabled).
+
+
+ Per the MCP specification, HTTP-level authentication failures return only HTTP status codes and headers - no JSON-RPC
+ response body is included.
+
+
+## RFC 9728 Protected Resource Metadata
+
+When OAuth is enabled and `authorization_server_url` is configured, the MCP server exposes a public (unauthenticated) metadata endpoint at:
+
+```
+GET /.well-known/oauth-protected-resource/mcp
+```
+
+This follows the [RFC 9728](https://datatracker.ietf.org/doc/rfc9728/) path-aware format. MCP clients use this endpoint to automatically discover the authorization server and all supported scopes.
+
+**Example response:**
+
+```json
+{
+ "resource": "https://mcp.example.com",
+ "authorization_servers": ["https://auth.example.com"],
+ "bearer_methods_supported": ["header"],
+ "resource_documentation": "https://mcp.example.com/mcp",
+ "scopes_supported": [
+ "mcp:connect",
+ "mcp:tools:execute",
+ "mcp:tools:read",
+ "read:all",
+ "read:employee",
+ "read:fact",
+ "read:private"
+ ]
+}
+```
+
+The `scopes_supported` field is **automatically computed** as the union of:
+
+- All configured static scopes (`initialize`, `tools_list`, `tools_call`)
+- All scopes extracted from `@requiresScopes` directives on fields used by registered operations
+
+## Startup Validation
+
+The router performs startup validation when OAuth is enabled:
+
+- If `oauth.jwks` is empty, the router exits with a fatal error to prevent starting an unprotected endpoint
+- If `server.base_url` is empty, the router exits with a fatal error because it is required for [RFC 9728](https://datatracker.ietf.org/doc/rfc9728/) metadata discovery
+
+## Full Configuration Example
+
+```yaml
+mcp:
+ enabled: true
+ server:
+ listen_addr: '0.0.0.0:5025'
+ base_url: 'https://mcp.example.com'
+ graph_name: 'my-graph'
+ exclude_mutations: true
+ enable_arbitrary_operations: true # Enables execute_graphql tool
+ expose_schema: true # Enables get_schema tool
+ oauth:
+ enabled: true
+ authorization_server_url: 'https://auth.example.com'
+ scope_challenge_include_token_scopes: false # Set to true for MCP clients with scope accumulation bugs
+ scopes:
+ initialize:
+ - 'mcp:connect'
+ tools_list:
+ - 'mcp:tools:read'
+ tools_call:
+ - 'mcp:tools:execute'
+ # Built-in tool scopes (additive to tools_call)
+ execute_graphql:
+ - 'mcp:graphql:execute'
+ get_schema:
+ - 'mcp:schema:read'
+ get_operation_info:
+ - 'mcp:ops:read'
+ jwks:
+ - url: 'https://auth.example.com/.well-known/jwks.json'
+ audiences:
+ - 'https://mcp.example.com'
+ algorithms:
+ - 'RS256'
+ refresh_interval: '1m'
+ storage:
+ provider_id: 'mcp'
+ session:
+ stateless: true
+
+storage_providers:
+ file_system:
+ - id: 'mcp'
+ path: 'operations'
+```
diff --git a/docs-website/router/mcp/oauth/overview.mdx b/docs-website/router/mcp/oauth/overview.mdx
new file mode 100644
index 0000000000..3708c17bf1
--- /dev/null
+++ b/docs-website/router/mcp/oauth/overview.mdx
@@ -0,0 +1,41 @@
+---
+title: 'Overview'
+description: 'Understand how OAuth 2.1 authorization works in the MCP server, including token validation, scope enforcement, and integration with identity providers.'
+icon: 'shield-check'
+---
+
+The MCP server supports OAuth 2.1 authorization, enabling integration with identity providers like Keycloak, Auth0, and Okta.
+
+OAuth is disabled by default. Existing MCP configurations continue to work unchanged.
+
+## How It Works
+
+When OAuth is enabled, every HTTP request to the MCP server must include a valid JWT bearer token in the `Authorization` header. The server validates the token using configured JWKS providers and enforces scope requirements at multiple levels.
+
+All scope enforcement happens at the HTTP transport level per the MCP specification, returning `403 Forbidden` responses with `WWW-Authenticate` headers that enable [step-up authorization](/router/mcp/oauth/scopes#token-upgrade-flow).
+
+## Token Validation
+
+The MCP server validates JWT bearer tokens using JWKS (JSON Web Key Sets). You can configure one or more JWKS providers - either remote JWKS URLs (for production with providers like Keycloak, Auth0, Okta) or symmetric secrets (for development and testing).
+
+The MCP OAuth config uses the **same JWKS format** as the router's top-level [authentication configuration](/router/authentication-and-authorization), though it is configured independently. You can point the MCP JWKS to the same JWKS URL as your router authentication, or to a different identity provider entirely.
+
+## OAuth Discovery (RFC 9728)
+
+When OAuth is enabled, the MCP server exposes a public metadata endpoint at `/.well-known/oauth-protected-resource/mcp` following [RFC 9728](https://datatracker.ietf.org/doc/rfc9728/). MCP clients use this endpoint to automatically discover the authorization server and all supported scopes without any manual configuration.
+
+The `scopes_supported` field is **automatically computed** as the union of all configured static scopes and all scopes extracted from `@requiresScopes` directives on fields used by registered operations. This means MCP clients can request all supported scopes upfront during the initial OAuth authorization, avoiding step-up challenges entirely.
+
+## Get Started
+
+
+
+ Step-by-step guide to adding OAuth to your MCP server with a working example.
+
+
+ Understand the multi-level scope enforcement model and how scopes combine.
+
+
+ Complete reference for all OAuth configuration options, JWKS settings, and error responses.
+
+
diff --git a/docs-website/router/mcp/oauth/quickstart.mdx b/docs-website/router/mcp/oauth/quickstart.mdx
new file mode 100644
index 0000000000..f39fef80cf
--- /dev/null
+++ b/docs-website/router/mcp/oauth/quickstart.mdx
@@ -0,0 +1,137 @@
+---
+title: 'OAuth Quickstart'
+description: 'Add OAuth 2.1 authorization to your MCP server in minutes. Step-by-step setup with JWKS configuration and verification.'
+icon: 'rocket'
+---
+
+This tutorial walks you through adding OAuth 2.1 authorization to an existing MCP server. By the end, your MCP server will require valid JWT tokens for all requests.
+
+## Prerequisites
+
+- A working MCP server (see [MCP Quickstart](/router/mcp/quickstart))
+- An OAuth 2.0 / OpenID Connect provider (Keycloak, Auth0, Okta, or similar) with a JWKS endpoint
+
+## Step 1: Configure OAuth
+
+Add the `oauth` section to your existing MCP configuration in `config.yaml`:
+
+```yaml
+mcp:
+ enabled: true
+ server:
+ listen_addr: '0.0.0.0:5025'
+ base_url: 'https://mcp.example.com' # Required when OAuth is enabled
+ oauth:
+ enabled: true
+ authorization_server_url: 'https://auth.example.com'
+ jwks:
+ - url: 'https://auth.example.com/.well-known/jwks.json'
+ refresh_interval: '1m'
+ storage:
+ provider_id: 'mcp'
+
+storage_providers:
+ file_system:
+ - id: 'mcp'
+ path: 'operations'
+```
+
+
+ `server.base_url` is required when OAuth is enabled. It is used for the RFC 9728 metadata endpoint and
+ `resource_metadata` in `WWW-Authenticate` headers. Set this to your externally-reachable URL.
+
+
+## Step 2: Add Scope Requirements
+
+Define which scopes are required at each level:
+
+```yaml
+oauth:
+ enabled: true
+ authorization_server_url: 'https://auth.example.com'
+ scopes:
+ initialize:
+ - 'mcp:connect' # Required for all MCP requests
+ tools_list:
+ - 'mcp:tools:read' # Required to list available tools
+ tools_call:
+ - 'mcp:tools:execute' # Required to execute any tool
+ jwks:
+ - url: 'https://auth.example.com/.well-known/jwks.json'
+ refresh_interval: '1m'
+```
+
+See [Scope Enforcement](/router/mcp/oauth/scopes) for a full explanation of how scopes work at each level.
+
+## Step 3: Restart and Verify
+
+Restart your router. You should see the MCP server start with OAuth enabled in the logs.
+
+### Verify the metadata endpoint
+
+The RFC 9728 metadata endpoint should be publicly accessible:
+
+```bash
+curl https://mcp.example.com/.well-known/oauth-protected-resource/mcp
+```
+
+You should see a response like:
+
+```json
+{
+ "resource": "https://mcp.example.com",
+ "authorization_servers": ["https://auth.example.com"],
+ "bearer_methods_supported": ["header"],
+ "scopes_supported": ["mcp:connect", "mcp:tools:read", "mcp:tools:execute"]
+}
+```
+
+### Verify token enforcement
+
+A request without a token should return `401 Unauthorized`:
+
+```bash
+curl -i https://mcp.example.com/mcp
+```
+
+```
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Bearer realm="mcp", scope="mcp:connect", resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/mcp"
+```
+
+## Step 4: Connect an MCP Client
+
+Your MCP client needs to obtain a token from your authorization server and include it in requests. How this works depends on the client.
+
+
+ Well-behaved MCP clients will read `scopes_supported` from the metadata endpoint and request all supported scopes
+ during the initial authorization. This avoids step-up challenges entirely when the authorization server grants all
+ requested scopes.
+
+
+## Development Setup with Symmetric Secrets
+
+For local development, you can use a symmetric secret instead of a remote JWKS endpoint:
+
+```yaml
+oauth:
+ enabled: true
+ authorization_server_url: 'https://auth.example.com'
+ jwks:
+ - secret: 'your-shared-secret'
+ symmetric_algorithm: 'HS256'
+ header_key_id: 'my-key-id'
+```
+
+This lets you generate test tokens locally without running an identity provider.
+
+## What's Next
+
+
+
+ Understand how scopes are enforced at multiple levels and how to use `@requiresScopes` for per-tool authorization.
+
+
+ Full reference for all OAuth options, JWKS settings, environment variables, and error responses.
+
+
diff --git a/docs-website/router/mcp/oauth/scopes.mdx b/docs-website/router/mcp/oauth/scopes.mdx
new file mode 100644
index 0000000000..06b4b6e44b
--- /dev/null
+++ b/docs-website/router/mcp/oauth/scopes.mdx
@@ -0,0 +1,197 @@
+---
+title: 'Scope Enforcement'
+description: 'How the MCP server enforces OAuth scopes at multiple levels, from connection to per-tool authorization, using an additive model with step-up token upgrades.'
+icon: 'layer-group'
+---
+
+The MCP server enforces scopes at multiple levels, all at the HTTP transport layer per the MCP specification. Each level is **additive** - a request must satisfy all applicable scope gates.
+
+## Enforcement Levels
+
+```
+HTTP Request
+ -> Initialize scopes (all requests)
+ -> Method scopes (tools/list, tools/call)
+ -> Built-in tool scopes (execute_graphql, get_schema, get_operation_info)
+ -> Per-tool scopes (registered operations, from @requiresScopes)
+ -> Runtime scopes (execute_graphql inline queries, per-query)
+```
+
+### Initialize Scopes
+
+The `scopes.initialize` list defines scopes required for **every** HTTP request to the MCP server. These are checked before the JSON-RPC payload is parsed, serving as the baseline authorization to establish an MCP connection.
+
+```yaml
+oauth:
+ scopes:
+ initialize:
+ - 'mcp:connect'
+```
+
+### Method-Level Scopes
+
+Additional scopes can be required for specific MCP methods:
+
+```yaml
+oauth:
+ scopes:
+ tools_list:
+ - 'mcp:tools:read' # Required to discover available tools
+ tools_call:
+ - 'mcp:tools:execute' # Required to execute any tool
+```
+
+When both `initialize` and method-level scopes are configured, the token must contain **all** of them. For example, calling `tools/call` requires both the `initialize` scopes and the `tools_call` scopes.
+
+
+ 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.
+
+
+### Built-in Tool Scopes
+
+The MCP server provides three built-in tools: `execute_graphql`, `get_operation_info`, and `get_schema`. Each can have its own scope requirements:
+
+```yaml
+oauth:
+ scopes:
+ tools_call:
+ - 'mcp:tools:execute' # Base gate for any tool
+ execute_graphql:
+ - 'mcp:graphql:execute' # Additional scope for execute_graphql
+ get_operation_info:
+ - 'mcp:ops:read' # Additional scope for get_operation_info
+ get_schema:
+ - 'mcp:schema:read' # Additional scope for get_schema
+```
+
+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.
+
+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.
+
+### Per-Tool Scopes (registered operations)
+
+When your GraphQL schema uses the `@requiresScopes` directive on fields, the MCP server automatically extracts scope requirements for each registered operation at startup. If a tool's underlying GraphQL operation touches fields that require specific scopes, those scopes are enforced when the tool is called.
+
+This level only applies to registered operations exposed as tools. The `execute_graphql` built-in tool is checked at the next level instead.
+
+For example, if your schema defines:
+
+```graphql
+type Query {
+ topSecretFacts: [Fact!]! @requiresScopes(scopes: [["read:fact"], ["read:all"]])
+ employee(id: ID!): Employee @requiresScopes(scopes: [["read:employee", "read:private"], ["read:all"]])
+}
+```
+
+And you have an operation `getTopSecretFacts.graphql` that queries `topSecretFacts`, calling that tool will require either `read:fact` OR `read:all` in addition to any `initialize` and `tools_call` scopes.
+
+The `@requiresScopes` directive uses OR-of-AND semantics. When an operation touches multiple fields with `@requiresScopes`, the MCP server computes the combined scope requirement using the [Cartesian product rules](/federation/directives/requiresscopes#combining-scopes-in-the-same-subgraph). For a full explanation of how scopes combine, see the [`@requiresScopes` directive documentation](/federation/directives/requiresscopes).
+
+Per-tool scopes are computed at startup (and on config reload), so they are enforced at the HTTP level with zero runtime overhead per request.
+
+### Runtime Scopes (`execute_graphql` inline queries)
+
+When `enable_arbitrary_operations` is enabled, the `execute_graphql` tool allows AI models to craft custom GraphQL queries. Since the server cannot know which fields will be queried ahead of time, scope checking happens at request time by parsing the GraphQL query and extracting `@requiresScopes` requirements for the fields it references.
+
+This runtime check uses the same [OR-of-AND semantics](/federation/directives/requiresscopes) and smart challenge selection as per-tool scopes. If the token lacks required scopes, the server returns a `403 Forbidden` with an appropriate scope challenge before the query is executed.
+
+
+ If the GraphQL query cannot be parsed, the request is passed through to the GraphQL engine, which handles the error.
+ Scope checking is best-effort and does not block malformed queries.
+
+
+## Scope Discovery with `get_operation_info`
+
+The `get_operation_info` tool includes scope requirements in its response, allowing AI models to discover what scopes a tool needs before calling it:
+
+```
+Required Scopes (OR-of-AND):
+ - read:employee AND read:private
+ OR
+ - read:all
+```
+
+## Summary
+
+| Level | When Checked | Configured Via | Failure Response |
+| ------------- | ------------------------------- | -------------------------------------------------------------------------------------------- | ----------------------------- |
+| Initialize | Every HTTP request | `oauth.scopes.initialize` | 403 with required scopes |
+| Method | `tools/list`, `tools/call` | `oauth.scopes.tools_list`, `oauth.scopes.tools_call` | 403 with required scopes |
+| 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 |
+| Per-tool | `tools/call` for a registered operation | `@requiresScopes` in GraphQL schema | 403 with best scope challenge |
+| Runtime | `execute_graphql` inline queries | `@requiresScopes` in GraphQL schema | 403 with best scope challenge |
+
+## Token Upgrade Flow
+
+Tokens can be upgraded **on the same MCP session** without reconnecting:
+
+
+
+ Client connects with a token that has `mcp:connect` scope.
+
+
+ Client calls `tools/call` and receives `403 Forbidden` with `insufficient_scope`.
+
+
+ Client obtains a new token with additional scopes from the authorization server. Requires client support for step-up authorization.
+
+
+ Client retries with the new token on the same session (same `Mcp-Session-Id`).
+
+
+
+
+ **MCP client limitation (as of April 2026)**: Most MCP clients - including Claude Code and the MCP TypeScript SDK -
+ do not yet support step-up re-authorization when they receive a `403 insufficient_scope` response. The server
+ implements the flow correctly per the MCP spec, but clients may fail to obtain a new token with broader scopes.
+
+ **Workarounds:**
+ - Include all required scopes in the `initialize` configuration so they are part of the initial `401` challenge
+ - Pre-register OAuth clients on the authorization server with all needed scopes
+ - Use the `scope_challenge_include_token_scopes: true` option to prevent clients from losing existing scopes
+
+ See [Claude Code issue #44652](https://github.com/anthropics/claude-code/issues/44652) for tracking.
+
+
+## Scope Challenge Behavior
+
+When the server returns a `403 Forbidden` response, the `WWW-Authenticate` header includes a `scope` parameter per [RFC 6750](https://datatracker.ietf.org/doc/rfc6750/) telling the client which scopes to request.
+
+For per-tool and runtime challenges where multiple scope groups can satisfy the requirement (OR-of-AND), the server selects the **best** group - the one requiring the fewest additional scopes based on what the token already has:
+
+1. For each AND-group, count how many scopes the token is **missing**
+2. Pick the group with the **fewest missing** scopes (ties go to the first group)
+
+For example, suppose a tool requires `(read:employee AND read:private AND read:fact) OR (read:all)` and a client presents a token with scopes `read:employee read:private`:
+
+| AND-group | Missing scopes | Count |
+| -------------------------------------------- | -------------- | ----- |
+| `read:employee`, `read:private`, `read:fact` | `read:fact` | 1 |
+| `read:all` | `read:all` | 1 |
+
+Both groups have 1 missing scope. The server picks the first, returning the **complete AND-group** (not just the missing scopes):
+
+```
+WWW-Authenticate: Bearer error="insufficient_scope",
+ scope="read:employee read:private read:fact"
+```
+
+The client can then request the additional `read:fact` scope from the authorization server and retry.
+
+### `scope_challenge_include_token_scopes`
+
+Some MCP client SDKs do not correctly accumulate scopes when performing step-up authorization - they request **only** the scopes from the `WWW-Authenticate` challenge, discarding the scopes they already had. This causes a loop where gaining a new scope loses a previous one. This is a [known issue in the MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk/issues/1582).
+
+To work around this, set `scope_challenge_include_token_scopes: true` to include the token's existing scopes alongside the required scopes in the challenge.
+
+| Value | Behavior | Trade-off |
+| ----------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
+| `false` (default) | Returns only the scopes the operation requires (strict RFC 6750). | Spec-compliant and more secure, but requires the client to correctly accumulate scopes. |
+| `true` | Returns the union of the token's existing scopes and the required scopes in the challenge. | More compatible with current MCP clients, but reveals the token's existing scopes in the response header. |
+
+
+ Setting `scope_challenge_include_token_scopes: true` reveals the token's existing scopes in the `WWW-Authenticate`
+ response header. If this is a concern, leave it as `false` and ensure your MCP clients correctly accumulate scopes
+ when requesting new tokens.
+
diff --git a/docs-website/router/mcp/operations.mdx b/docs-website/router/mcp/operations.mdx
new file mode 100644
index 0000000000..f80e321c09
--- /dev/null
+++ b/docs-website/router/mcp/operations.mdx
@@ -0,0 +1,181 @@
+---
+title: 'Operations'
+description: 'How to create, describe, and organize GraphQL operations that the MCP server exposes as tools for AI models.'
+icon: 'file-code'
+---
+
+The MCP server exposes your GraphQL operations as tools that AI models can discover and execute. Each `.graphql` file in your operations directory becomes a tool with a name, description, and input schema.
+
+## Creating Operations
+
+Create a directory for your operations (as specified in your [storage provider configuration](/router/mcp/configuration#storage-providers)) and add `.graphql` or `.gql` files containing GraphQL operations.
+
+Each file should contain a **single operation**. Named operations are recommended, but if an operation is unnamed, the filename (without extension) is used as the operation name.
+
+Use triple-quoted description strings (following the September 2025 GraphQL spec) to provide descriptions for AI models:
+
+```graphql
+"""
+Returns a list of all users in the system with their basic information.
+This is a read-only operation that doesn't modify any data.
+"""
+query GetUsers {
+ users {
+ id
+ name
+ email
+ }
+}
+```
+
+The description becomes the tool's description, which is the primary way AI models understand what an operation does. If no description is provided, a default description is generated from the operation name and type.
+
+
+ Only triple-quoted description strings (`"""..."""`) are supported. Standard GraphQL comments (`# comment`) are not
+ extracted as tool descriptions.
+
+
+### Validation
+
+Operations are validated against your GraphQL schema at load time. Invalid operations are logged as errors and skipped - they will not appear as MCP tools. Subscription operations are not supported and are also skipped.
+
+## Mutation Operations
+
+Mutations follow the same pattern. The MCP server automatically adds a warning that the operation has side effects:
+
+```graphql
+"""
+Creates a new user in the system.
+Required inputs: name and email
+"""
+mutation CreateUser($name: String!, $email: String!) {
+ createUser(input: { name: $name, email: $email }) {
+ id
+ name
+ email
+ }
+}
+```
+
+
+ To prevent AI models from making unintended changes, consider setting `exclude_mutations: true` in your configuration
+ until you've validated your mutation operations thoroughly.
+
+
+## Directory Structure
+
+Here's an example of how your project directory should be structured:
+
+```
+my-router-project/
+├── config.yaml # Router configuration file
+├── operations/ # Operations directory (as configured in storage provider)
+│ ├── getUsers.graphql # Query operation
+│ ├── createUser.graphql # Mutation operation
+│ ├── getUserById.graphql # Query with parameters
+│ └── billing/ # Subdirectory for grouping
+│ ├── getInvoices.graphql
+│ └── getPayments.graphql
+└── ...
+```
+
+Key points:
+
+- The path in your `storage_providers.file_system.path` should point to the operations directory
+- All `.graphql` and `.gql` files in this directory **and subdirectories** will be loaded
+- Each file should contain a single GraphQL operation
+- Duplicate operation names across files are rejected (the second file is skipped with an error log)
+
+## Tool Naming
+
+The MCP server converts each operation into a corresponding tool:
+
+| Operation Name | Tool Name |
+| -------------- | ---------------------------------- |
+| `GetUsers` | `execute_operation_get_users` |
+| `CreateUser` | `execute_operation_create_user` |
+| `GetUserById` | `execute_operation_get_user_by_id` |
+
+Operations are converted to `snake_case` for tool naming consistency.
+
+### Tool Schema
+
+The tool's input schema is automatically generated from your GraphQL operation's variables, ensuring type safety. AI models use this schema to understand what parameters are required and their types.
+
+### Omitting the Tool Name Prefix
+
+By default, all operation tools include the `execute_operation_` prefix. You can enable `omit_tool_name_prefix` to generate shorter tool names:
+
+```yaml
+mcp:
+ enabled: true
+ omit_tool_name_prefix: true
+```
+
+| Operation Name | Default | With `omit_tool_name_prefix` |
+| -------------- | ------------------------------- | ---------------------------- |
+| `GetUsers` | `execute_operation_get_users` | `get_users` |
+| `CreateUser` | `execute_operation_create_user` | `create_user` |
+
+
+ Enabling this option changes all tool names and may break existing integrations that rely on the `execute_operation_`
+ prefix. Only enable this for new deployments or when you can update all dependent systems.
+
+
+
+ Operations with names that would collide with any already-registered tool (including built-in tools like `get_schema`,
+ `execute_graphql`, `get_operation_info`, or a previously registered operation) are **skipped** and logged as errors.
+ Rename the operation to avoid the conflict.
+
+
+## Best Practices
+
+### Write Effective Descriptions
+
+Descriptions are the most important part of your operations for AI consumption. A good description tells the AI model:
+
+- **What** data the operation provides or changes
+- **When** to use this operation (and when not to)
+- **What** is excluded or restricted (especially for security-sensitive data)
+
+```graphql
+"""
+Retrieves recent transaction history for a customer account.
+Returns only non-sensitive transaction details suitable for AI assistant responses.
+Excludes: account numbers, routing information, precise location data, and full merchant details.
+Use this to answer customer questions about recent purchases and payment status.
+"""
+query GetTransactionHistory($accountId: ID!, $last: Int!) {
+ account(id: $accountId) {
+ transactions(last: $last) {
+ id
+ date
+ merchantNameMasked
+ category
+ amount
+ status
+ }
+ }
+}
+```
+
+### Design for AI Consumption
+
+
+
+ Give operations clear, action-oriented names that describe what they do: `GetActiveUsers`, `SearchProducts`,
+ `CreateSupportTicket`.
+
+
+ Define all input variables with explicit types to ensure proper validation and help AI models understand required
+ inputs.
+
+
+ Design operations specifically for AI model consumption rather than exposing generic operations. An operation that
+ returns exactly what the AI needs is better than one that returns everything.
+
+
+ For mutation operations, add checks and validations in your backend to prevent misuse. Consider requiring
+ confirmation parameters for destructive operations.
+
+
diff --git a/docs-website/router/mcp/quickstart.mdx b/docs-website/router/mcp/quickstart.mdx
new file mode 100644
index 0000000000..b54b3c7f1f
--- /dev/null
+++ b/docs-website/router/mcp/quickstart.mdx
@@ -0,0 +1,173 @@
+---
+title: 'Quickstart'
+description: 'Get the Cosmo Router MCP Gateway running in 5 minutes. Create your first GraphQL operation and connect an AI tool.'
+icon: 'rocket'
+---
+
+This tutorial walks you through enabling MCP on the Cosmo Router, creating your first GraphQL operation, and connecting an AI tool to test it.
+
+## Prerequisites
+
+- A running Cosmo Router with a configured GraphQL schema (see [Router Introduction](/router/intro))
+- An AI tool that supports MCP (Claude Desktop, Cursor, Windsurf, VS Code, or similar)
+
+## Step 1: Create an Operations Directory
+
+Create a directory to store the GraphQL operations that will be exposed to AI models:
+
+```bash
+mkdir operations
+```
+
+## Step 2: Add Your First Operation
+
+Create a file `operations/getUsers.graphql` with a named GraphQL operation. The description string becomes the tool description that AI models see:
+
+```graphql
+"""
+Returns a list of all users in the system with their basic information.
+This is a read-only operation that doesn't modify any data.
+"""
+query GetUsers {
+ users {
+ id
+ name
+ email
+ }
+}
+```
+
+
+ Replace the operation above with a query that matches your actual GraphQL schema. The operation must be valid against
+ your schema.
+
+
+## Step 3: Configure the Router
+
+Add the MCP configuration to your `config.yaml`:
+
+```yaml
+mcp:
+ enabled: true
+ server:
+ listen_addr: 'localhost:5025'
+ graph_name: 'my-graph'
+ exclude_mutations: true # Start with read-only access
+ storage:
+ provider_id: 'mcp'
+
+storage_providers:
+ file_system:
+ - id: 'mcp'
+ path: 'operations'
+```
+
+
+ Setting `exclude_mutations: true` is a good starting point. You can enable mutations later once you're comfortable
+ with the setup.
+
+
+## Step 4: Start the Router
+
+Start (or restart) your Cosmo Router. You should see a log message indicating the MCP server is listening:
+
+```
+MCP server listening on localhost:5025
+```
+
+## Step 5: Connect Your AI Tool
+
+Choose your AI tool and add the MCP server configuration:
+
+
+
+ Go to **Settings** > **Tools & Integrations** > **MCP Servers** and add:
+
+ ```json
+ {
+ "mcpServers": {
+ "my-graph": {
+ "url": "http://localhost:5025/mcp"
+ }
+ }
+ }
+ ```
+
+ Requires Cursor v0.48.0+ for Streamable HTTP support.
+
+
+
+ Go to **Settings** > **Developer** > **Edit Config** and add:
+
+ ```json
+ {
+ "mcpServers": {
+ "my-graph": {
+ "command": "npx",
+ "args": ["-y", "mcp-remote", "http://localhost:5025/mcp"]
+ }
+ }
+ }
+ ```
+
+ Restart Claude Desktop after saving.
+
+
+
+ Open **View** > **Command Palette** > **MCP: Add Server** and enter the URL:
+
+ ```
+ http://localhost:5025/mcp
+ ```
+
+ See the [VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) for details.
+
+
+
+ Add to your MCP configuration:
+
+ ```json
+ {
+ "mcpServers": {
+ "my-graph": {
+ "serverUrl": "http://localhost:5025/mcp"
+ }
+ }
+ }
+ ```
+
+
+
+
+## Step 6: Test It
+
+In your AI tool, try a prompt like:
+
+```
+What tools are available? List all the operations I can use.
+```
+
+The AI model should discover your `GetUsers` operation (exposed as `execute_operation_get_users`) and be able to describe it. Then try:
+
+```
+Get all users from the system.
+```
+
+The AI model will call the `execute_operation_get_users` tool and return the results.
+
+## What's Next?
+
+
+
+ Learn how to write effective operations with descriptions, handle mutations, and organize your operations directory.
+
+
+ Explore all configuration options including session handling, storage providers, and advanced settings.
+
+
+ Add OAuth 2.1 authorization with JWT validation and multi-level scope enforcement.
+
+
+ Detailed setup guides for each AI tool, including header forwarding and authentication.
+
+