diff --git a/docs/legacy/concepts/architecture.mdx b/docs/legacy/concepts/architecture.mdx index b2547ed8c..08d7f5280 100644 --- a/docs/legacy/concepts/architecture.mdx +++ b/docs/legacy/concepts/architecture.mdx @@ -201,6 +201,9 @@ enum ErrorCode { MethodNotFound = -32601, InvalidParams = -32602, InternalError = -32603, + + // MCP-specific error codes in the range [-32000, -32099] + UrlElicitationRequired = -32042, } ``` diff --git a/docs/specification/draft/basic/lifecycle.mdx b/docs/specification/draft/basic/lifecycle.mdx index e6ee219c9..350e9ed7a 100644 --- a/docs/specification/draft/basic/lifecycle.mdx +++ b/docs/specification/draft/basic/lifecycle.mdx @@ -64,7 +64,10 @@ The client **MUST** initiate this phase by sending an `initialize` request conta "listChanged": true }, "sampling": {}, - "elicitation": {} + "elicitation": { + "form": {}, + "url": {} + } }, "clientInfo": { "name": "ExampleClient", diff --git a/docs/specification/draft/changelog.mdx b/docs/specification/draft/changelog.mdx index 4c2c29225..90dae8814 100644 --- a/docs/specification/draft/changelog.mdx +++ b/docs/specification/draft/changelog.mdx @@ -14,6 +14,7 @@ the previous revision, [2025-06-18](/specification/2025-06-18). 3. Enhance authorization flows with incremental scope consent via `WWW-Authenticate` ([SEP-835](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/835)) 4. Provide guidance on tool names ([SEP-986](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1603)) 5. Update `ElicitResult` and `EnumSchema` to use a more standards-based approach and support titled, untitled, single-select, and multi-select enums ([SEP-1330](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330)). +6. Added support for [URL mode elicitation](/specification/draft/client/elicitation#url-elicitation-requests)([SEP-1036](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/887)) ## Minor changes diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx index 1a73b9272..f4856a04f 100644 --- a/docs/specification/draft/client/elicitation.mdx +++ b/docs/specification/draft/client/elicitation.mdx @@ -6,17 +6,15 @@ title: Elicitation **Protocol Revision**: draft - - -Elicitation is newly introduced in this version of the MCP specification and its design may evolve in future protocol versions. - - - The Model Context Protocol (MCP) provides a standardized way for servers to request additional information from users through the client during interactions. This flow allows clients to maintain control over user interactions and data sharing while enabling servers to gather necessary information dynamically. -Servers request structured data from users with JSON schemas to validate responses. + +Elicitation supports two modes: + +- **Form mode**: Servers can request structured data from users with optional JSON schemas to validate responses +- **URL mode**: Servers can direct users to external URLs for sensitive interactions that must _not_ pass through the MCP client ## User Interaction Model @@ -31,36 +29,206 @@ model. For trust & safety and security: -- Servers **MUST NOT** use elicitation to request sensitive information. +- Servers **MUST NOT** use form mode elicitation to request sensitive information +- Servers **MUST** use URL mode for interactions involving sensitive information, such as credentials +- URLs **MUST NOT** appear in any field of an elicitation request, other than the `url` field in an URL mode request -Applications **SHOULD**: +MCP clients **MUST**: - Provide UI that makes it clear which server is requesting information -- Allow users to review and modify their responses before sending - Respect user privacy and provide clear decline and cancel options +- For form mode, allow users to review and modify their responses before sending +- For URL mode, clearly display the target domain/host and gather user consent before navigation to the target URL ## Capabilities Clients that support elicitation **MUST** declare the `elicitation` capability during -[initialization](/specification/draft/basic/lifecycle#initialization): +[initialization](../basic/lifecycle#initialization): ```json { "capabilities": { - "elicitation": {} + "elicitation": { + "form": {}, + "url": {} + } } } ``` +For backwards compatibility, an empty capabilities object is equivalent to declaring support for `form` mode only: + +```jsonc +{ + "capabilities": { + "elicitation": {}, // Equivalent to { "form": {} } + }, +} +``` + +Clients declaring the `elicitation` capability **MUST** support at least one mode (`form` or `url`). + +Servers **MUST NOT** send elicitation requests with modes that are not supported by the client. + ## Protocol Messages -### Creating Elicitation Requests +### Elicitation Requests + +To request information from a user, servers send an `elicitation/create` request. + +All elicitation requests **MUST** include the following parameters: + +| Name | Type | Options | Description | +| --------- | ------ | ------------- | ------------------------------------------------------------------ | +| `mode` | string | `form`, `url` | The mode of the elicitation. | +| `message` | string | | A human-readable message explaining why the interaction is needed. | + +The `mode` parameter specifies the type of elicitation: + +- `"form"`: In-band structured data collection with optional schema validation. Data is exposed to the client. +- `"url"`: Out-of-band interaction via URL navigation. Data (other than the URL itself) is **not** exposed to the client. + +### Form Mode Elicitation Requests + +Form mode elicitation allows servers to collect structured data directly through the MCP client. + +Form mode elicitation requests **MUST** specify `mode: "form"` and include these additional parameters: + +| Name | Type | Description | +| ----------------- | ------ | -------------------------------------------------------------- | +| `requestedSchema` | object | A JSON Schema defining the structure of the expected response. | + +#### Requested Schema + +The `requestedSchema` parameter allows servers to define the structure of the expected +response using a restricted subset of JSON Schema. + +To simplify client user experience, form mode elicitation schemas are limited to flat objects +with primitive properties only. + +The schema is restricted to these primitive types: + +1. **String Schema** + + ```json + { + "type": "string", + "title": "Display Name", + "description": "Description text", + "minLength": 3, + "maxLength": 50, + "pattern": "^[A-Za-z]+$", + "format": "email", + "default": "user@example.com" + } + ``` + + Supported formats: `email`, `uri`, `date`, `date-time` + +2. **Number Schema** + + ```json + { + "type": "number", // or "integer" + "title": "Display Name", + "description": "Description text", + "minimum": 0, + "maximum": 100, + "default": 50 + } + ``` + +3. **Boolean Schema** + + ```json + { + "type": "boolean", + "title": "Display Name", + "description": "Description text", + "default": false + } + ``` + +4. **Enum Schema** + + Single-select enum (without titles): + + ```json + { + "type": "string", + "title": "Color Selection", + "description": "Choose your favorite color", + "enum": ["Red", "Green", "Blue"], + "default": "Red" + } + ``` + + Single-select enum (with titles): + + ```json + { + "type": "string", + "title": "Color Selection", + "description": "Choose your favorite color", + "oneOf": [ + { "const": "#FF0000", "title": "Red" }, + { "const": "#00FF00", "title": "Green" }, + { "const": "#0000FF", "title": "Blue" } + ], + "default": "#FF0000" + } + ``` + + Multi-select enum (without titles): + + ```json + { + "type": "array", + "title": "Color Selection", + "description": "Choose your favorite colors", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "string", + "enum": ["Red", "Green", "Blue"] + }, + "default": ["Red", "Green"] + } + ``` + + Multi-select enum (with titles): + + ```json + { + "type": "array", + "title": "Color Selection", + "description": "Choose your favorite colors", + "minItems": 1, + "maxItems": 2, + "items": { + "oneOf": [ + { "const": "#FF0000", "title": "Red" }, + { "const": "#00FF00", "title": "Green" }, + { "const": "#0000FF", "title": "Blue" } + ] + }, + "default": ["#FF0000", "#00FF00"] + } + ``` -To request information from a user, servers send an `elicitation/create` request: +Clients can use this schema to: -#### Simple Text Request +1. Generate appropriate input forms +2. Validate user input before sending +3. Provide better guidance to users + +All primitive types support optional default values to provide sensible starting points. Clients that support defaults SHOULD pre-populate form fields with these values. + +Note that complex nested structures, arrays of objects (beyond enums), and other advanced JSON Schema features are intentionally not supported to simplify client user experience. + +#### Example: Simple Text Request **Request:** @@ -70,6 +238,7 @@ To request information from a user, servers send an `elicitation/create` request "id": 1, "method": "elicitation/create", "params": { + "mode": "form", "message": "Please provide your GitHub username", "requestedSchema": { "type": "object", @@ -99,7 +268,7 @@ To request information from a user, servers send an `elicitation/create` request } ``` -#### Structured Data Request +#### Example: Structured Data Request **Request:** @@ -109,6 +278,7 @@ To request information from a user, servers send an `elicitation/create` request "id": 2, "method": "elicitation/create", "params": { + "mode": "form", "message": "Please provide your contact information", "requestedSchema": { "type": "object", @@ -151,199 +321,203 @@ To request information from a user, servers send an `elicitation/create` request } ``` -**Reject Response Example:** +### URL Mode Elicitation Requests + +URL mode elicitation enables servers to direct users to external URLs for out-of-band interactions that must not pass through the MCP client. This is essential for auth flows, payment processing, and other sensitive or secure operations. + + + **Important**: URL mode elicitation is *not* for authorizing the MCP client's + access to the MCP server (that's handled by [MCP + authorization](../basic/authorization)). Instead, it's used when the MCP + server needs to obtain sensitive information or third-party authorization on + behalf of the user. The MCP client's bearer token remains unchanged. The + client's only responsibility is to provide the user with context about the + elicitation URL the server wants them to open. + + +URL mode elicitation requests **MUST** specify `mode: "url"` and include these additional parameters: + +| Name | Type | Description | +| --------------- | ------ | ----------------------------------------- | +| `url` | string | The URL that the user should navigate to. | +| `elicitationId` | string | A unique identifier for the elicitation. | + +The `url` parameter **MUST** contain a valid URL. The `message` parameter **MUST NOT** contain a URL. + +#### Example: Request Sensitive Data + +This example shows a URL mode elicitation request directing the user to a secure URL where they can provide sensitive information (an API key, for example). +The same request could direct the user into an OAuth authorization flow, or a payment flow. The only difference is the URL and the message. + +**Request:** ```json { "jsonrpc": "2.0", - "id": 2, - "result": { - "action": "decline" + "id": 3, + "method": "elicitation/create", + "params": { + "mode": "url", + "elicitationId": "550e8400-e29b-41d4-a716-446655440000", + "url": "https://mcp.example.com/ui/set_api_key", + "message": "Please provide your API key to continue." } } ``` -**Cancel Response Example:** +**Response:** ```json { "jsonrpc": "2.0", - "id": 2, + "id": 3, "result": { - "action": "cancel" + "action": "accept" } } ``` -## Message Flow +The response with `action: "accept"` indicates that the user has consented to the +interaction. It does not mean that the interaction is complete. The interaction occurs out +of band and the client is not aware of the outcome until and unless the server sends a notification indicating completion. -```mermaid -sequenceDiagram - participant User - participant Client - participant Server +### Completion Notifications for URL Mode Elicitation - Note over Server,Client: Server initiates elicitation - Server->>Client: elicitation/create +Servers **SHOULD** send a `notifications/elicitation/complete` notification when an +out-of-band interaction started by URL mode elicitation is completed. This allows clients to react programmatically if appropriate. - Note over Client,User: Human interaction - Client->>User: Present elicitation UI - User-->>Client: Provide requested information +- The notification **MUST** only be sent to the client that initiated the elicitation request. +- The notification **MUST** include the `elicitationId` established in the original + `elicitation/create` request. +- Clients **MUST** ignore notifications referencing unknown or already-completed IDs. +- If a completion notification never arrives, clients **SHOULD** provide a manual + way for the user to continue the interaction. - Note over Server,Client: Complete request - Client-->>Server: Return user response +Clients **MAY** use the notification to automatically retry requests that received a [URLElicitationRequiredError](#error-handling), update the user interface, or otherwise continue an interaction. +However, because delivery of the notification is not guaranteed, clients must not wait indefinitely for a notification from the server. - Note over Server: Continue processing with new information +#### Example + +```json +{ + "jsonrpc": "2.0", + "method": "notifications/elicitation/complete", + "params": { + "elicitationId": "550e8400-e29b-41d4-a716-446655440000" + } +} ``` -## Request Schema +### URL Elicitation Required Error + +When a request cannot be processed until an elicitation is completed, the server **MAY** return a [`URLElicitationRequiredError`](#error-handling) (code `-32042`) to indicate to the client that a URL mode elicitation is required. The server **MUST NOT** return this error except when URL mode elicitation is required. -The `requestedSchema` field allows servers to define the structure of the expected response using a restricted subset of JSON Schema. To simplify client user experience, elicitation schemas are limited to flat objects with primitive properties only: +The error **MUST** include a list of elicitations that are required to complete before the original can be retried. + +Any elicitations returned in the error **MUST** be URL mode elicitations and have an `elicitationId` property. + +**Error Response:** ```json -"requestedSchema": { - "type": "object", - "properties": { - "propertyName": { - "type": "string", - "title": "Display Name", - "description": "Description of the property" - }, - "anotherProperty": { - "type": "number", - "minimum": 0, - "maximum": 100 +{ + "jsonrpc": "2.0", + "id": 2, + "error": { + "code": -32042, // URL_ELICITATION_REQUIRED + "message": "This request requires more information.", + "data": { + "elicitations": [ + { + "mode": "url", + "elicitationId": "550e8400-e29b-41d4-a716-446655440000", + "url": "https://mcp.example.com/connect?elicitationId=550e8400-e29b-41d4-a716-446655440000", + "message": "Authorization is required to access your Example Co files." + } + ] } - }, - "required": ["propertyName"] + } } ``` -### Supported Schema Types +## Message Flow -The schema is restricted to these primitive types: +### Form Mode Flow -1. **String Schema** +```mermaid +sequenceDiagram + participant User + participant Client + participant Server - ```json - { - "type": "string", - "title": "Display Name", - "description": "Description text", - "minLength": 3, - "maxLength": 50, - "pattern": "^[A-Za-z]+$", - "format": "email", - "default": "user@example.com" - } - ``` + Note over Server: Server initiates elicitation + Server->>Client: elicitation/create (mode: form) - Supported formats: `email`, `uri`, `date`, `date-time` + Note over User,Client: Present elicitation UI + User-->>Client: Provide requested information -2. **Number Schema** + Note over Server,Client: Complete request + Client->>Server: Return user response - ```json - { - "type": "number", // or "integer" - "title": "Display Name", - "description": "Description text", - "minimum": 0, - "maximum": 100, - "default": 50 - } - ``` + Note over Server: Continue processing with new information +``` -3. **Boolean Schema** +### URL Mode Flow - ```json - { - "type": "boolean", - "title": "Display Name", - "description": "Description text", - "default": false - } - ``` +```mermaid +sequenceDiagram + participant UserAgent as User Agent (Browser) + participant User + participant Client + participant Server -4. **Enum Schema** + Note over Server: Server initiates elicitation + Server->>Client: elicitation/create (mode: url) - Single-select enum (without titles): + Client->>User: Present consent to open URL + User-->>Client: Provide consent - ```json - { - "type": "string", - "title": "Color Selection", - "description": "Choose your favorite color", - "enum": ["Red", "Green", "Blue"], - "default": "Red" - } - ``` + Client->>UserAgent: Open URL + Client->>Server: Accept response - Single-select enum (with titles): + Note over User,UserAgent: User interaction + UserAgent-->>Server: Interaction complete + Server-->>Client: notifications/elicitation/complete (optional) - ```json - { - "type": "string", - "title": "Color Selection", - "description": "Choose your favorite color", - "oneOf": [ - { "const": "#FF0000", "title": "Red" }, - { "const": "#00FF00", "title": "Green" }, - { "const": "#0000FF", "title": "Blue" } - ], - "default": "#FF0000" - } - ``` + Note over Server: Continue processing with new information +``` - Multi-select enum (without titles): +### URL Mode With Elicitation Required Error Flow - ```json - { - "type": "array", - "title": "Color Selection", - "description": "Choose your favorite colors", - "minItems": 1, - "maxItems": 2, - "items": { - "type": "string", - "enum": ["Red", "Green", "Blue"] - }, - "default": ["Red", "Green"] - } - ``` +```mermaid +sequenceDiagram + participant UserAgent as User Agent (Browser) + participant User + participant Client + participant Server - Multi-select enum (with titles): + Client->>Server: tools/call - ```json - { - "type": "array", - "title": "Color Selection", - "description": "Choose your favorite colors", - "minItems": 1, - "maxItems": 2, - "items": { - "oneOf": [ - { "const": "#FF0000", "title": "Red" }, - { "const": "#00FF00", "title": "Green" }, - { "const": "#0000FF", "title": "Blue" } - ] - }, - "default": ["#FF0000", "#00FF00"] - } - ``` + Note over Server: Server needs authorization + Server->>Client: URLElicitationRequiredError + Note over Client: Client notes the original request can be retried after elicitation -Clients can use this schema to: + Client->>User: Present consent to open URL + User-->>Client: Provide consent -1. Generate appropriate input forms -2. Validate user input before sending -3. Provide better guidance to users + Client->>UserAgent: Open URL + Client->>Server: Accept response -All primitive types support optional default values to provide sensible starting points. Clients that support defaults SHOULD pre-populate form fields with these values. + Note over User,UserAgent: User interaction -Note that complex nested structures, arrays of objects (beyond enums), and other advanced JSON Schema features are intentionally not supported to simplify client user experience. + UserAgent-->>Server: Interaction complete + Server-->>Client: notifications/elicitation/complete (optional) + + Client->>Server: Retry tools/call (optional) +``` ## Response Actions -Elicitation responses use a three-action model to clearly distinguish between different user actions: +Elicitation responses use a three-action model to clearly distinguish between different user actions. These actions apply to both form and URL elicitation modes. ```json { @@ -362,7 +536,8 @@ Elicitation responses use a three-action model to clearly distinguish between di The three response actions are: 1. **Accept** (`action: "accept"`): User explicitly approved and submitted with data - - The `content` field contains the submitted data matching the requested schema + - For form mode: The `content` field contains the submitted data matching the requested schema + - For URL mode: The `content` field is omitted - Example: User clicked "Submit", "OK", "Confirm", etc. 2. **Decline** (`action: "decline"`): User explicitly declined the request @@ -371,7 +546,7 @@ The three response actions are: 3. **Cancel** (`action: "cancel"`): User dismissed without making an explicit choice - The `content` field is typically omitted - - Example: User closed the dialog, clicked outside, pressed Escape, etc. + - Example: User closed the dialog, clicked outside, pressed Escape, browser failed to load, etc. Servers should handle each state appropriately: @@ -379,12 +554,215 @@ Servers should handle each state appropriately: - **Decline**: Handle explicit decline (e.g., offer alternatives) - **Cancel**: Handle dismissal (e.g., prompt again later) +## Implementation Considerations + +### Statefulness + +Most practical uses of elicitation require that the server maintain state about users: + +- Whether required information has been collected (e.g., the user's display name via form mode elicitation) +- Status of resource access (e.g., API keys or a payment flow via URL mode elicitation) + +Servers implementing elicitation **MUST** securely associate this state with individual users following the guidelines in the [security best practices](../basic/security_best_practices) document. Specifically: + +- State **MUST NOT** be associated with session IDs alone +- State storage **MUST** be protected against unauthorized access +- For remote MCP servers, user identification **MUST** be derived from credentials acquired via [MCP authorization](../basic/authorization) when possible (e.g. `sub` claim) + + + The examples in this section are non-normative and illustrate potential uses + of elicitation. Implementers should adapt these patterns to their specific + requirements while maintaining security best practices. + + +### URL Mode Elicitation for Sensitive Data + +For servers that interact with external APIs requiring sensitive information (e.g., credentials, payment information), URL mode elicitation provides a secure mechanism for users to provide this information without exposing it to the MCP client. + +In this pattern: + +1. The server directs users to a secure web page (served over HTTPS) +2. The page presents a branded form UI on a domain the user trusts +3. Users enter sensitive credentials directly into the secure form +4. The server stores credentials securely, bound to the user's identity +5. Subsequent MCP requests use these stored credentials for API access + +This approach ensures that sensitive credentials never pass through the LLM context, MCP client or any intermediate MCP servers, reducing the risk of exposure through client-side logging or other attack vectors. + +### URL Mode Elicitation for OAuth Flows + +URL mode elicitation enables a pattern where MCP servers act as OAuth clients to third-party resource servers. +Authorization with external APIs enabled by URL mode elicitation is separate from [MCP authorization](../basic/authorization). MCP servers **MUST NOT** rely on URL mode elicitation to authorize users for themselves. + +#### Understanding the Distinction + +- **MCP Authorization**: Required OAuth flow between the MCP client and MCP server (covered in the [authorization specification](../basic/authorization)) +- **External (third-party) Authorization**: Optional authorization between the MCP server and a third-party resource server, initiated via URL mode elicitation + +In external authorization, the server acts as both: + +- An OAuth resource server (to the MCP client) +- An OAuth client (to the third-party resource server) + +Example scenario: + +- An MCP client connects to an MCP server +- The MCP server integrates with various different third-party services +- When the MCP client calls a tool that requires access to a third-party service, the MCP server needs credentials for that service + +The critical security requirements are: + +1. **The third-party credentials MUST NOT transit through the MCP client**: The client must never see third-party credentials to protect the security boundary +2. **The MCP server MUST NOT use the client's credentials for the third-party service**: That would be [token passthrough](../basic/security_best_practices#token-passthrough), which is forbidden +3. **The user MUST authorize the MCP server directly**: The interaction happens outside the MCP protocol, without involving the MCP client +4. **The MCP server is responsible for tokens**: The MCP server is responsible for storing and managing the third-party tokens obtained through the URL mode elicitation (in other words, the MCP server must be stateful). + +Credentials obtained via URL mode elicitation are distinct from the MCP server credentials used by the MCP client. The MCP server **MUST NOT** transmit credentials obtained through URL mode elicitation to the MCP client. + + + For additional background, refer to the [token passthrough + section](../basic/security_best_practices#token-passthrough) of the Security + Best Practices document to understand why MCP servers cannot act as + pass-through proxies. + + +#### Implementation Pattern + +When implementing external authorization via URL mode elicitation: + +1. The MCP server generates an authorization URL, acting as an OAuth client to the third-party service +2. The server creates a URL mode elicitation request with this URL +3. The user completes the OAuth flow directly with the third-party authorization server +4. The third-party authorization server redirects back to the MCP server +5. The MCP server securely stores the third-party tokens, bound to the user's identity +6. Future MCP requests can leverage these stored tokens for API access to the third-party resource server + +The following is a non-normative example of how this pattern could be implemented: + +```mermaid +sequenceDiagram + participant User + participant UserAgent as User Agent (Browser) + participant 3AS as 3rd Party AS + participant 3RS as 3rd Party RS + participant Client as MCP Client + participant Server as MCP Server + + Client->>Server: tools/call + Note over Server: Needs 3rd-party authorization for user + Note over Server: Store state (bind the elicitation request to the user) + Server->>Client: URLElicitationRequiredError
(mode: "url", url: "https://mcp.example.com/connect?...") + Note over Client: Client notes the tools/call request can be retried later + Client->>User: Present consent to open URL + User->>Client: Provide consent + Client->>UserAgent: Open URL + Client->>Server: Accept response + UserAgent->>Server: Load connect route + Note over Server: Confirm: user is logged into MCP Server or MCP AS
Confirm: elicitation user matches session user + Server->>UserAgent: Redirect to third-party authorization endpoint + UserAgent->>3AS: Load authorize route + Note over 3AS,User: User interaction (OAuth flow):
User consents to scoped MCP Server access + 3AS->>UserAgent: redirect to MCP Server's redirect_uri + UserAgent->>Server: load redirect_uri page + Note over Server: Confirm: redirect_uri belongs to MCP Server + Server->>3AS: Exchange authorization code for OAuth tokens + 3AS->>Server: Grants tokens + Note over Server: Bind tokens to MCP user identity + Server-->>Client: notifications/elicitation/complete (optional) + Client->>Server: Retry tools/call + Note over Server: Retrieve token bound to user identity + Server->>3RS: Call 3rd-party API +``` + +This pattern maintains clear security boundaries while enabling rich integrations with third-party services that require user authorization. + +## Error Handling + +Servers **MUST** return standard JSON-RPC errors for common failure cases: + +- When a request cannot be processed until an elicitation is completed: `-32042` (`URLElicitationRequiredError`) + +Clients **MUST** return standard JSON-RPC errors for common failure cases: + +- Server sends an `elicitation/create` request with a mode not declared in client capabilities: `-32602` (Invalid params) + ## Security Considerations -1. Servers **MUST NOT** request sensitive information through elicitation -2. Clients **SHOULD** implement user approval controls -3. Both parties **SHOULD** validate elicitation content against the provided schema -4. Clients **SHOULD** provide clear indication of which server is requesting information -5. Clients **SHOULD** allow users to decline elicitation requests at any time -6. Clients **SHOULD** implement rate limiting -7. Clients **SHOULD** present elicitation requests in a way that makes it clear what information is being requested and why +1. Servers **MUST** bind elicitation requests to the client and user identity +1. Clients **MUST** provide clear indication of which server is requesting information +1. Clients **SHOULD** implement user approval controls +1. Clients **SHOULD** allow users to decline elicitation requests at any time +1. Clients **SHOULD** implement rate limiting +1. Clients **SHOULD** present elicitation requests in a way that makes it clear what information is being requested and why + +### Safe URL Handling + +MCP servers requesting elicitation: + +1. **MUST NOT** include URLs in any message or schema fields as part of a form mode elicitation request. +1. **MUST NOT** include URLs in any message or schema fields as part of an URL mode elicitation request, except for the `url` field. +1. **MUST NOT** include plain text sensitive information about the end-user, including credentials, personal identifiable information, etc., in the URL sent to the client. +1. **MUST NOT** provide a URL which is pre-authenticated to access a protected resource, as the URL could be used to impersonate the user by a malicious client. +1. **SHOULD** use HTTPS URLs for non-development environments. + +These server requirements ensure that client implementations have clear rules about when to present a URL to the user, so that the client-side rules (below) can be consistently applied. + +Clients implementing URL mode elicitation **MUST** handle URLs carefully to prevent users from unknowingly clicking malicious links. + +When handling URL mode elicitation requests, MCP clients: + +1. **MUST NOT** automatically pre-fetch the URL or any of its metadata. +2. **MUST NOT** open the URL without explicit consent from the user. +3. **MUST** show the full URL to the user for examination before consent. +4. **MUST** open the URL provided by the server in a secure manner that does not enable the client or LLM to inspect the content or user inputs. + For example, on iOS, [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) is good, but [WkWebView](https://developer.apple.com/documentation/webkit/wkwebview) is not. +5. **SHOULD** highlight the domain of the URL to mitigate subdomain spoofing. +6. **SHOULD** have warnings for ambiguous/suspicious URIs (i.e., containing Punycode). + +### Identifying the User + +Servers **MUST NOT** rely on client-provided user identification without server verification, as this can be forged. +Instead, servers **SHOULD** follow [security best practices](../basic/security_best_practices). + +Non-normative examples: + +- Incorrect: Treat user input like "I am joe@example.com" as authoritative +- Correct: Rely on [authorization](../basic/authorization) to identify the user + +### Form Mode Security + +1. Servers **MUST NOT** request sensitive information (passwords, API keys, etc.) via form mode +2. Clients **SHOULD** validate all responses against the provided schema +3. Servers **SHOULD** validate received data matches the requested schema + +#### Phishing + +URL mode elicitation returns a URL that an attacker can use to send to a victim. The MCP Server **MUST** verify the identity of the user who opens the URL before accepting information. + +Typically identity verification is done by leveraging the [MCP authorization server](../basic/authorization) to identify the user, through a session cookie or equivalent in the browser. + +For example, URL mode elicitation may be used to perform OAuth flows where the server acts as an OAuth client of another resource server. Without proper mitigation, the following phishing attack is possible: + +1. A malicious user (Alice) connected to a benign server triggers an elicitation request +2. The benign server generates an authorization URL, acting as an OAuth client of a third-party authorization server +3. Alice's client displays the URL and asks for consent +4. Instead of clicking on the link, Alice tricks a victim user (Bob) of the same benign server into clicking it +5. Bob opens the link and completes the authorization, thinking they are authorizing their own connection to the benign server +6. The benign server receives a callback/redirect form the third-party authorization server, and assumes it's Alice's request +7. The tokens for the third-party server are bound to Alice's session and identity, instead of Bob's, resulting in an account takeover + +To prevent this attack, the server **MUST** ensure that the user who started the elicitation request (the end-user who is accessing the server via the MCP client) is the same user who completes the authorization flow. + +There are many ways to achieve this and the best way will depend on the specific implementation. + +As a common, non-normative example, consider a case where the MCP server is accessible via the web and desires to perform a third-party authorization code flow. +To prevent the phishing attack, the server would create a URL mode elicitation to `https://mcp.example.com/connect?elicitationId=...` rather than the third-party authorization endpoint. +This "connect URL" must ensure the user who opened the page is the same user who the elicitation was generated for. +It would, for example, check that the user has a valid session cookie and that the session cookie is for the same user who was using the MCP client to generate the URL mode elicitation. +This could be done by comparing the authoritative subject (`sub` claim) from the MCP server's authorization server to the subject from the session cookie. +Once that page ensures the same user, it can send the user to the third-party authorization server at `https://example.com/authorize?...` where a normal OAuth flow can be completed. + +In other cases, the server may not be accessible via the web and may not be able to use a session cookie to identify the user. +In this case, the server must use a different mechanism to identify the user who opens the elicitation URL is the same user who the elicitation was generated for. + +In all implementations, the server **MUST** ensure that the mechanism to determine the user's identity is resilient to attacks where an attacker can modify the elicitation URL. diff --git a/docs/specification/draft/schema.mdx b/docs/specification/draft/schema.mdx index d02ded5c0..ae78d2c61 100644 --- a/docs/specification/draft/schema.mdx +++ b/docs/specification/draft/schema.mdx @@ -148,22 +148,32 @@ if present).