From a17b1732b169790759474cb970020af595cd6f81 Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Tue, 24 Jun 2025 16:35:57 -0700
Subject: [PATCH 01/62] Out of band elicitation
---
docs/docs/concepts/architecture.mdx | 1 +
docs/specification/draft/changelog.mdx | 3 +
.../draft/client/elicitation.mdx | 399 +++++++++++++++++-
schema/draft/schema.json | 37 +-
schema/draft/schema.ts | 47 ++-
5 files changed, 452 insertions(+), 35 deletions(-)
diff --git a/docs/docs/concepts/architecture.mdx b/docs/docs/concepts/architecture.mdx
index e431a1216..8acdc2776 100644
--- a/docs/docs/concepts/architecture.mdx
+++ b/docs/docs/concepts/architecture.mdx
@@ -201,6 +201,7 @@ enum ErrorCode {
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
+ ElicitationRequired = -32604,
}
```
diff --git a/docs/specification/draft/changelog.mdx b/docs/specification/draft/changelog.mdx
index 7fbe7aa97..a7f9d83a2 100644
--- a/docs/specification/draft/changelog.mdx
+++ b/docs/specification/draft/changelog.mdx
@@ -9,6 +9,9 @@ the previous revision, [2025-06-18](/specification/2025-06-18).
## Major changes
+1. Added support for [out-of-band elicitation](/specification/draft/client/elicitation#out-of-band-mode)
+ (PR TBD)
+
## Other schema changes
## Full changelog
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 6f992b197..0c8549276 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -16,7 +16,11 @@ The Model Context Protocol (MCP) provides a standardized way for servers to requ
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** (in-band): Servers can request structured data from users with optional JSON schemas to validate responses
+- **Out-of-band mode**: Servers can direct users to external URLs for interactions that should not pass through the MCP client, such as OAuth authorization flows
## User Interaction Model
@@ -31,11 +35,14 @@ 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 out-of-band mode for OAuth flows and other security-sensitive interactions
+- URLs **MUST NOT** appear in form mode messages or schemas
Applications **SHOULD**:
- Provide UI that makes it clear which server is requesting information
+- For out-of-band mode, clearly display the target domain/host before navigation
- Allow users to review and modify their responses before sending
- Respect user privacy and provide clear reject and cancel options
@@ -54,13 +61,39 @@ Clients that support elicitation **MUST** declare the `elicitation` capability d
}
```
+Clients **MAY** specify which elicitation modes they support:
+
+```json
+{
+ "capabilities": {
+ "elicitation": {
+ "modes": ["form", "oob"]
+ }
+ }
+}
+```
+
+If the `modes` array is not present, servers **MUST** assume the client only supports `form` mode for backward compatibility.
+
+Servers **MUST NOT** send elicitation requests with modes that are not explicitly declared by the client.
+
## Protocol Messages
### Creating Elicitation Requests
-To request information from a user, servers send an `elicitation/create` request:
+To request information from a user, servers send an `elicitation/create` request. The request **MUST** include a `mode` parameter that specifies the type of elicitation:
+
+- `"form"` (default): In-band structured data collection with optional schema validation
+- `"oob"`: Out-of-band interaction via URL navigation
+
+The elicitation request **MAY** include a `correlatedRequestId` parameter that indicates
+the request is related to an earlier request (e.g. a failed tool call).
+
+#### Form Mode (In-Band)
-#### Simple Text Request
+Form mode allows servers to collect structured data directly through the MCP client.
+
+##### Simple Text Request
**Request:**
@@ -70,6 +103,7 @@ To request information from a user, servers send an `elicitation/create` request
"id": 1,
"method": "elicitation/create",
"params": {
+ "mode": "form", // Optional, defaults to "form"
"message": "Please provide your GitHub username",
"requestedSchema": {
"type": "object",
@@ -99,7 +133,7 @@ To request information from a user, servers send an `elicitation/create` request
}
```
-#### Structured Data Request
+##### Structured Data Request
**Request:**
@@ -109,6 +143,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,6 +186,114 @@ To request information from a user, servers send an `elicitation/create` request
}
```
+#### Out-of-Band Mode
+
+Out-of-band mode enables servers to direct users to external URLs for interactions that
+should not pass through the MCP client. This is essential for OAuth flows, payment
+processing, and other security-sensitive operations.
+
+**Request:**
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 3,
+ "method": "elicitation/create",
+ "params": {
+ "mode": "oob",
+ "url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
+ "message": "Authorization is required to access your Example Co files.",
+ "correlatedRequestId": 2 // Optional
+ }
+}
+```
+
+**Response with Progress Tracking:**
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 3,
+ "result": {
+ "_meta": {
+ "progressToken": "oob-progress-456" // Client wants progress updates (TODO needs to be a separate `elicitation/track` request?)
+ },
+ "action": "accept",
+ "codeVerifier": "a1b2c3"
+ }
+}
+```
+
+The server can then send [progress notifications](/docs/specification/draft/basic/utilities/progress.mdx):
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "notifications/progress",
+ "params": {
+ "progressToken": "oob-progress-456",
+ "progress": 100,
+ "total": 100,
+ "message": "Authorization completed successfully"
+ }
+}
+```
+
+For sensitive flows (e.g. authorization), the server **MAY** send the client an additional
+`elicitation/verify` request containing the request ID of an earlier elicitation request.
+
+The client **MUST** validate that it received the elicitation request with the given request ID, and respond accordingly:
+- Respond with `success` if the given request ID was received by this client, and the code verifier matches the cryptographic hash of the code
+- Respond with an error if the given request ID was NOT received by this client
+
+// TODO: Finish describing a PKCE-like challenge/verifier mechanism here,
+// so that the client knows something cryptographically that the server doesn't know.
+// I think it's necessary in chained scenarios like MCP client->MCP server 1->MCP server 2->...,
+// to avoid a malicious server in the middle spoofing the response to `/elicitation/verify`.
+
+**Confirm Request:**
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 4,
+ "method": "elicitation/confirm",
+ "params": {
+ "confirmRequestId": 3,
+ "codeVerifier": "a1b2c3"
+ }
+}
+```
+
+**Response (Request ID Valid):**
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 4,
+ "result": {
+ "confirmedRequestId": 3
+ }
+}
+```
+
+**Response (Request ID Invalid):**
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 4,
+ "error": {
+ "code": -32600,
+ "message": "Unknown elicitation request: 3"
+ }
+}
+```
+
+#### Decline and Cancel Response Examples
+
+For all non-accept responses, the `content` field is omitted. The response payloads are identical for either form or out-of-band mode.
+
**Reject Response Example:**
```json
@@ -177,14 +320,16 @@ To request information from a user, servers send an `elicitation/create` request
## Message Flow
+### Form Mode Flow
+
```mermaid
sequenceDiagram
participant User
participant Client
participant Server
- Note over Server,Client: Server initiates elicitation
- Server->>Client: elicitation/create
+ Note over Server,Client: Server initiates form elicitation
+ Server->>Client: elicitation/create (mode: form)
Note over Client,User: Human interaction
Client->>User: Present elicitation UI
@@ -196,9 +341,127 @@ sequenceDiagram
Note over Server: Continue processing with new information
```
+### Out-of-Band Mode Flow
+
+```mermaid
+sequenceDiagram
+ participant Server
+ participant Client
+ participant User
+ participant UserAgent as User Agent (Browser)
+
+ Note over Server,Client: Server initiates out-of-band elicitation
+ Server->>Client: elicitation/create (mode: oob)
+
+ Client->>User: Present consent to open URL
+ User->>Client: Provide consent
+
+ Client->>UserAgent: Open URL
+ Client->>Server: Response (action: accept), with optional progressToken
+
+ Note over User,UserAgent: User interaction (e.g. OAuth flow)
+ UserAgent-->>Server: Interaction complete
+
+ Server->>Client: notifications/progress (optional)
+```
+
+### Example: Elicitation Required for Tool Call
+
+When an elicitation interaction is required as part of another request, the server **SHOULD**
+return error -32604 to indicate to the client that an elicitation message is expected.
+TODO: Finalize this error code and do a find-replace in the whole repo if it needs to change
+
+In subsequent elicitation message(s), the server **SHOULD** set the `correlatedRequestId`
+property to the JSON-RPC request ID of the original request.
+
+When an elicitation is needed in response to another request (e.g., a tool call requiring payment):
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Server
+ participant User
+ participant UserAgent as User Agent
+
+ Client->>Server: tools/call (id: 123)
+
+ Note over Server: Server needs authorization
+ Server->>Client: Error acknowledging need for auth (code: -32604)
+ Server->>Client: elicitation/create (id: 124, mode: oob, correlatedRequestId: 123)
+ Note over Client: Client associates elicitation request 124 with tool call 123
+
+ Client->>User: Present consent to open URL
+ User->>Client: Provide consent
+
+ Client->>UserAgent: Open URL
+ Client->>Server: Response (action: accept), with optional progressToken
+
+ Note over User,UserAgent: User interaction (e.g. OAuth flow)
+ UserAgent-->>Server: Interaction complete
+
+ Server->>Client: notifications/progress (optional)
+
+ Client->>Server: Retry tools/call (optional)
+```
+
+TODO: I'm on the fence whether we should add an even more detailed example of doing downstream OAuth.
+I don't want to fixate the whole OOB section on OAuth, but it is the most-requested thing to do.
+We could keep it here, or alternatively move it to a new doc about "OAuth best practices" or even a blog post.
+Adding it below in case we decide to keep it:
+
+### Example: OAuth to Downstream Resource Server (TODO decide to keep?)
+
+A variation on the above example is downstream OAuth authorization for a tool or resource
+call.
+
+In this scenario, the MCP client acts as an OAuth 2.1 client to the MCP server (as
+described in [MCP authorization](/docs/specification/draft/basic/authorization.mdx)). The
+MCP server then acts as an OAuth client to a downstream (third-party) Authorization Server
+and Resource Server.
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Server
+ participant User
+ participant UserAgent as User Agent
+ participant 3PAS as 3rd-party Authorization Server
+ participant 3PRS as 3rd-party Resource Server
+
+ Client->>Server: tools/call (id: 123)
+
+ Note over Server: Server needs authorization
+ Note over Server: Generate OAuth 2.1 authorization URL to downstream AS
+ Server->>Client: Error acknowledging need for auth (code: -32604)
+ Server->>Client: elicitation/create (id: 124, mode: oob, correlatedRequestId: 123)
+ Note over Client: Client associates elicitation request 124 with tool call 123
+
+ Client->>User: Present consent to open URL
+ User->>Client: Provide consent
+
+ Client->>UserAgent: Open URL
+ Client->>Server: Response (action: accept), with optional progressToken
+
+ UserAgent-->>3PAS: Redirect
+ Note over User,UserAgent,3PAS: OAuth flow
+ 3PAS-->>Server: Callback
+ Server-->>3PAS: Token exchange (server acting as OAuth 2.1 client)
+ Note over Server: Server binds 3rd-party tokens to MCP user
+
+ Server->>Client: notifications/progress (optional)
+
+ Client->>Server: Retry tools/call (optional)
+ Note over Server: Retrieve 3rd-party tokens for MCP user
+ Server-->>3PRS: API request to resource server (server acting as OAuth 2.1 client)
+ 3PRS-->>Server: API response
+ Server->>Client: Tool response
+```
+
## Request Schema
-The `requestedSchema` field allows servers to define the structure of the expected response using a restricted subset of JSON Schema. To simplify implementation for clients, elicitation schemas are limited to flat objects with primitive properties only:
+### Form Mode Schema
+
+For `form` mode, the `requestedSchema` field allows servers to define the structure of the expected response using a restricted subset of JSON Schema. To simplify implementation for clients, elicitation schemas are limited to flat objects with primitive properties only:
```json
"requestedSchema": {
@@ -219,7 +482,7 @@ The `requestedSchema` field allows servers to define the structure of the expect
}
```
-### Supported Schema Types
+#### Supported Schema Types
The schema is restricted to these primitive types:
@@ -281,9 +544,27 @@ Clients can use this schema to:
Note that complex nested structures, arrays of objects, and other advanced JSON Schema features are intentionally not supported to simplify client implementation.
+### Out-of-Band Mode Parameters
+
+For `oob` mode, the request parameters are:
+
+- `mode`: **MUST** be `"oob"`
+- `url`: **REQUIRED** - The URL that the user should navigate to
+// TODO: should it be `url` or `uri`? There was a question on 475 about other protocols like tel://
+// I am leaning towards `url` because then we can keep a clean MUST in Security Considerations about always requiring https://
+// My only sticking point is mobile app schemes - would being able to redirect to my-app:// be useful, or a bigger can of worms?
+- `message`: **OPTIONAL** - Human-readable explanation of why the interaction is needed
+
+Parameters **MUST NOT** include:
+
+- `requestedSchema` - This is only for form mode
+- Any URLs in the `message` field. URLs must only appear in the `url` field
+
## 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.
+
+Additionally, responses **MAY** include a progress token to enable progress tracking for long-running operations.
```json
{
@@ -294,6 +575,20 @@ Elicitation responses use a three-action model to clearly distinguish between di
"content": {
"propertyName": "value",
"anotherProperty": 42
+ },
+ "_meta": {
+ "progressToken": "client-token-123" // Optional: enables progress tracking.
+ // TODO: According to a strict reading of the progress spec, this is incorrect(!)
+ // because this is a JSONRPCResponse.Result payload. While Result does contain a `_meta` key,
+ // `_meta.progressToken` is only defined on JSONRPCRequest, not JSONRPCResponse.Result
+ // We worked within the boundaries of a strict reading of the progress spec in the original
+ // UI PR 475 by introducing another request message, `interactions/track` so that the progressToken
+ // could be passed in a proper JSONRPCRequest.
+ // @ggoodman noted that this felt very inefficient (he's right). I still feel like this PR
+ // isn't the place to amend the progress spec, but maybe worth opening a discussion
+ // on the MCP github to see if there's an appetite for adding `_meta.progressToken` to JSONRPCResponse.Result
+ // Unless/until the progress spec is updated, I believe the correct spec-compliant thing to do here
+ // is to reintroduce something like `elicitations/track` :/
}
}
}
@@ -303,7 +598,8 @@ 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 out-of-band mode: The `content` field is omitted
- Example: User clicked "Submit", "OK", "Confirm", etc.
2. **Reject** (`action: "reject"`): User explicitly rejected the request
@@ -317,16 +613,81 @@ The three response actions are:
Servers should handle each state appropriately:
-- **Accept**: Process the submitted data
-- **Reject**: Handle explicit rejection (e.g., offer alternatives)
+- **Accept**: Process the submitted data or proceed with the interaction
+- **Decline**: Handle explicit rejection (e.g., offer alternatives)
- **Cancel**: Handle dismissal (e.g., prompt again later)
+### Progress Tracking
+
+When the client includes a `progressToken` in its response, the server **MAY** send progress notifications:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "notifications/progress",
+ "params": {
+ "progressToken": "client-token-123",
+ "progress": 50,
+ "total": 100,
+ "message": "User completing authorization..."
+ }
+}
+```
+
+This is particularly useful for out-of-band mode where the interaction is a disconnected flow that may take time to complete.
+
## Security Considerations
-1. Servers **MUST NOT** request sensitive information through elicitation
+1. Clients **MUST** provide clear indication of which server is requesting information
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 reject 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
+3. Clients **SHOULD** allow users to reject elicitation requests at any time
+4. Clients **SHOULD** implement rate limiting
+5. Clients **SHOULD** present elicitation requests in a way that makes it clear what information is being requested and why
+
+### Identifying the User
+
+Servers **MUST NOT** rely on client-provided user identification, as this can be forged.
+Instead, servers **SHOULD** follow [security best practices](/specification/draft/basic/security_best_practices).
+
+Non-normative examples:
+- Incorrect: Treat user input like "I am joe@example.com" as authoritative
+- Correct: Rely on the [MCP authorization server](/docs/specification/draft/basic/authorization.mdx) to identify the user
+
+### Form Mode Security
+
+1. Servers **MUST NOT** request sensitive information (passwords, API keys, etc.) via form mode
+2. Servers **MUST NOT** place URLs intended for user interaction in form mode messages or schemas
+3. Clients **SHOULD** validate all responses against the provided schema
+4. Servers **SHOULD** validate received data matches the requested schema
+
+### Out-of-Band Mode Security
+
+1. Clients **MUST NOT** open a user agent (e.g. browser) without explicit consent from the user
+
+#### Server-Side Request Forgery (SSRF)
+
+Since clients open URLs provided by servers, they **MUST** implement SSRF protections:
+
+- Block requests to internal IP ranges (e.g., 127.0.0.1, 10.0.0.0/8, etc.)
+- Require the `https://` scheme for all out-of-band URLs (no HTTP, file://, etc.)
+- Clearly render or distinguish Unicode characters (e.g. punycode URLs) to avoid "look-alike" misdirections
+- Clearly communicate the destination server and target URL to the user when asking for consent
+
+#### Phishing
+
+One use of out of band elicitation is to perform OAuth flows where the server acts as an
+OAuth client of another resource server. In this case, the server generates an
+authorization URL to the third-party resource server and passes it to the client in the
+form of an `oob` elicitation request.
+
+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 resource server
+3. Instead of clicking on the link, Alice tricks a victim user (Bob) of the same benign server into clicking it
+4. Bob follows the link and completes the authorization, thinking they are authorizing their own connection to the benign server
+5. 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**:
+- Send an `elicitation/verify` message after the out-of-band interaction is complete, but _before_ the elicitation interaction is considered complete
+- Bind out-of-band elicitation requests to the identity of the user, and ensure the `elicitation/verify` response is sent from the same identity // TODO might need to word better, what I really mean is "the Bearer token is for the same person"
+- Bind out-of-band elicitation requests to the MCP session, and ensure the `elicitation/verify` response belongs to the same session // TODO: Is this too narrow? Not all transports support sessions. What if the session expires too soon?
\ No newline at end of file
diff --git a/schema/draft/schema.json b/schema/draft/schema.json
index 1edd7ea1f..cf73245cf 100644
--- a/schema/draft/schema.json
+++ b/schema/draft/schema.json
@@ -216,9 +216,20 @@
"description": "Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.",
"properties": {
"elicitation": {
- "additionalProperties": true,
"description": "Present if the client supports elicitation from the server.",
- "properties": {},
+ "properties": {
+ "modes": {
+ "description": "The elicitation modes that the client supports.\nIf not specified, the server MUST assume the client only supports \"form\" mode.",
+ "items": {
+ "enum": [
+ "form",
+ "oob"
+ ],
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
"type": "object"
},
"experimental": {
@@ -563,11 +574,19 @@
"params": {
"properties": {
"message": {
- "description": "The message to present to the user.",
+ "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor out-of-band mode: Explains why the interaction is needed.",
+ "type": "string"
+ },
+ "mode": {
+ "description": "The mode of elicitation.\n- \"form\": In-band structured data collection with optional schema validation\n- \"oob\": Out-of-band interaction via URL navigation\n\nIf not specified, \"form\" is assumed.",
+ "enum": [
+ "form",
+ "oob"
+ ],
"type": "string"
},
"requestedSchema": {
- "description": "A restricted subset of JSON Schema.\nOnly top-level properties are allowed, without nesting.",
+ "description": "For form mode only: A restricted subset of JSON Schema.\nOnly top-level properties are allowed, without nesting.\n\nRequired when mode is \"form\" or unspecified.\nMust NOT be present when mode is \"oob\".",
"properties": {
"properties": {
"additionalProperties": {
@@ -591,11 +610,15 @@
"type"
],
"type": "object"
+ },
+ "url": {
+ "description": "For out-of-band mode only: The URL that the user should navigate to.\n\nRequired when mode is \"oob\".\nMust NOT be present when mode is \"form\".",
+ "format": "uri",
+ "type": "string"
}
},
"required": [
- "message",
- "requestedSchema"
+ "message"
],
"type": "object"
}
@@ -631,7 +654,7 @@
"boolean"
]
},
- "description": "The submitted form data, only present when action is \"accept\".\nContains values matching the requested schema.",
+ "description": "The submitted form data, only present when action is \"accept\" and mode was \"form\".\nContains values matching the requested schema.\nOmitted for out-of-band mode responses.",
"type": "object"
}
},
diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts
index 5d00b75ee..5a811ccb8 100644
--- a/schema/draft/schema.ts
+++ b/schema/draft/schema.ts
@@ -93,6 +93,7 @@ export const INVALID_REQUEST = -32600;
export const METHOD_NOT_FOUND = -32601;
export const INVALID_PARAMS = -32602;
export const INTERNAL_ERROR = -32603;
+export const ELICITATION_REQUIRED = -32604; // TODO finalize error number
/**
* A response to a request that indicates an error occurred.
@@ -215,7 +216,13 @@ export interface ClientCapabilities {
/**
* Present if the client supports elicitation from the server.
*/
- elicitation?: object;
+ elicitation?: {
+ /**
+ * The elicitation modes that the client supports.
+ * If not specified, the server MUST assume the client only supports "form" mode.
+ */
+ modes?: ("form" | "oob")[];
+ };
}
/**
@@ -1304,21 +1311,46 @@ export interface RootsListChangedNotification extends Notification {
export interface ElicitRequest extends Request {
method: "elicitation/create";
params: {
+ /**
+ * The mode of elicitation.
+ * - "form": In-band structured data collection with optional schema validation
+ * - "oob": Out-of-band interaction via URL navigation
+ *
+ * If not specified, "form" is assumed.
+ */
+ mode?: "form" | "oob";
+
/**
* The message to present to the user.
+ * For form mode: Describes what information is being requested.
+ * For out-of-band mode: Explains why the interaction is needed.
*/
message: string;
+
/**
- * A restricted subset of JSON Schema.
+ * For form mode only: A restricted subset of JSON Schema.
* Only top-level properties are allowed, without nesting.
+ *
+ * Required when mode is "form" or unspecified.
+ * Must NOT be present when mode is "oob".
*/
- requestedSchema: {
+ requestedSchema?: {
type: "object";
properties: {
[key: string]: PrimitiveSchemaDefinition;
};
required?: string[];
};
+
+ /**
+ * For out-of-band mode only: The URL that the user should navigate to.
+ *
+ * Required when mode is "oob".
+ * Must NOT be present when mode is "form".
+ *
+ * @format uri
+ */
+ url?: string;
};
}
@@ -1377,8 +1409,9 @@ export interface ElicitResult extends Result {
action: "accept" | "reject" | "cancel";
/**
- * The submitted form data, only present when action is "accept".
+ * The submitted form data, only present when action is "accept" and mode was "form".
* Contains values matching the requested schema.
+ * Omitted for out-of-band mode responses.
*/
content?: { [key: string]: string | number | boolean };
}
@@ -1405,11 +1438,7 @@ export type ClientNotification =
| InitializedNotification
| RootsListChangedNotification;
-export type ClientResult =
- | EmptyResult
- | CreateMessageResult
- | ListRootsResult
- | ElicitResult;
+export type ClientResult = EmptyResult | CreateMessageResult | ListRootsResult | ElicitResult;
/* Server messages */
export type ServerRequest =
From 6906c2cc8c8229d2704e5d9b785b2c0b94b4db4e Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Fri, 27 Jun 2025 17:36:49 -0700
Subject: [PATCH 02/62] Revisions
---
.../draft/client/elicitation.mdx | 346 ++++++++----------
1 file changed, 150 insertions(+), 196 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 0c8549276..6a69bf408 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -8,7 +8,7 @@ title: Elicitation
-Elicitation is newly introduced in this version of the MCP specification and its design may evolve in future protocol versions.
+The design of the Elicitation capability may evolve in future protocol versions.
@@ -36,7 +36,7 @@ model.
For trust & safety and security:
- Servers **MUST NOT** use form mode elicitation to request sensitive information
-- Servers **MUST** use out-of-band mode for OAuth flows and other security-sensitive interactions
+- Servers **MUST** use out-of-band mode for auth flows and other security-sensitive interactions
- URLs **MUST NOT** appear in form mode messages or schemas
Applications **SHOULD**:
@@ -61,19 +61,20 @@ Clients that support elicitation **MUST** declare the `elicitation` capability d
}
```
-Clients **MAY** specify which elicitation modes they support:
+Clients **MAY** specify sub-capabilities for elicitation modes they support:
```json
{
"capabilities": {
"elicitation": {
- "modes": ["form", "oob"]
+ "form": {},
+ "oob": {}
}
}
}
```
-If the `modes` array is not present, servers **MUST** assume the client only supports `form` mode for backward compatibility.
+If sub-capabilities are not present, servers **MUST** assume the client _only_ supports `form` mode for backward compatibility.
Servers **MUST NOT** send elicitation requests with modes that are not explicitly declared by the client.
@@ -81,13 +82,10 @@ Servers **MUST NOT** send elicitation requests with modes that are not explicitl
### Creating Elicitation Requests
-To request information from a user, servers send an `elicitation/create` request. The request **MUST** include a `mode` parameter that specifies the type of elicitation:
+To request information from a user, servers send an `elicitation/create` request. The request **SHOULD** include a `mode` parameter that specifies the type of elicitation:
-- `"form"` (default): In-band structured data collection with optional schema validation
-- `"oob"`: Out-of-band interaction via URL navigation
-
-The elicitation request **MAY** include a `correlatedRequestId` parameter that indicates
-the request is related to an earlier request (e.g. a failed tool call).
+- `"form"` (default): In-band structured data collection with optional schema validation. Data is exposed to the client.
+- `"oob"`: Out-of-band interaction via URL navigation. Data is **not** exposed to the client.
#### Form Mode (In-Band)
@@ -103,7 +101,7 @@ Form mode allows servers to collect structured data directly through the MCP cli
"id": 1,
"method": "elicitation/create",
"params": {
- "mode": "form", // Optional, defaults to "form"
+ "mode": "form",
"message": "Please provide your GitHub username",
"requestedSchema": {
"type": "object",
@@ -189,8 +187,8 @@ Form mode allows servers to collect structured data directly through the MCP cli
#### Out-of-Band Mode
Out-of-band mode enables servers to direct users to external URLs for interactions that
-should not pass through the MCP client. This is essential for OAuth flows, payment
-processing, and other security-sensitive operations.
+should not pass through the MCP client. This is essential for auth flows, payment
+processing, and other sensitive or secure operations.
**Request:**
@@ -201,123 +199,139 @@ processing, and other security-sensitive operations.
"method": "elicitation/create",
"params": {
"mode": "oob",
+ "elicitationId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
"message": "Authorization is required to access your Example Co files.",
- "correlatedRequestId": 2 // Optional
}
}
```
-**Response with Progress Tracking:**
+**Response:**
```json
{
"jsonrpc": "2.0",
"id": 3,
"result": {
- "_meta": {
- "progressToken": "oob-progress-456" // Client wants progress updates (TODO needs to be a separate `elicitation/track` request?)
- },
"action": "accept",
- "codeVerifier": "a1b2c3"
}
}
```
-The server can then send [progress notifications](/docs/specification/draft/basic/utilities/progress.mdx):
+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. To be aware of the outcome, the client can leverage the
+[Progress Utility](/specification/draft/basic/utilities/progress), when supported by the server, to
+track the progress of the interaction.
+
+
+**Progress Tracking Request (from client to server):**
```json
{
"jsonrpc": "2.0",
- "method": "notifications/progress",
+ "id": 3,
+ "method": "elicitation/track",
"params": {
- "progressToken": "oob-progress-456",
- "progress": 100,
- "total": 100,
- "message": "Authorization completed successfully"
- }
+ "elicitationId": "550e8400-e29b-41d4-a716-446655440000",
+ "_meta": {
+ "progressToken": "abc123"
+ }
}
```
-For sensitive flows (e.g. authorization), the server **MAY** send the client an additional
-`elicitation/verify` request containing the request ID of an earlier elicitation request.
-
-The client **MUST** validate that it received the elicitation request with the given request ID, and respond accordingly:
-- Respond with `success` if the given request ID was received by this client, and the code verifier matches the cryptographic hash of the code
-- Respond with an error if the given request ID was NOT received by this client
-
-// TODO: Finish describing a PKCE-like challenge/verifier mechanism here,
-// so that the client knows something cryptographically that the server doesn't know.
-// I think it's necessary in chained scenarios like MCP client->MCP server 1->MCP server 2->...,
-// to avoid a malicious server in the middle spoofing the response to `/elicitation/verify`.
-
-**Confirm Request:**
+**Progress Tracking Notification (from server to client):**
```json
{
"jsonrpc": "2.0",
- "id": 4,
- "method": "elicitation/confirm",
+ "method": "notifications/progress",
"params": {
- "confirmRequestId": 3,
- "codeVerifier": "a1b2c3"
+ "progressToken": "abc123",
+ "progress": 42,
+ "message": "Consent pending..."
}
}
```
-**Response (Request ID Valid):**
+**Progress Tracking Response (from server to client):**
```json
{
"jsonrpc": "2.0",
- "id": 4,
+ "id": 3,
"result": {
- "confirmedRequestId": 3
+ "status": "complete"
}
}
```
-**Response (Request ID Invalid):**
+#### Decline and Cancel Responses
+
+For all non-accept responses, the `content` field is omitted.
+The response payloads are identical for either form or out-of-band mode.
+
+**Reject Response Example:**
```json
{
"jsonrpc": "2.0",
- "id": 4,
- "error": {
- "code": -32600,
- "message": "Unknown elicitation request: 3"
+ "id": 2,
+ "result": {
+ "action": "reject"
}
}
```
-#### Decline and Cancel Response Examples
-
-For all non-accept responses, the `content` field is omitted. The response payloads are identical for either form or out-of-band mode.
-
-**Reject Response Example:**
+**Cancel Response Example:**
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
- "action": "reject"
+ "action": "cancel"
}
}
```
-**Cancel Response Example:**
+### ElicitationRequired Errors
+
+When another request cannot be processed until an elicitation is completed, the server **SHOULD**
+return an [ElicitationRequired](/docs/concepts/architecture#error-handling) error to indicate to
+the client that an elicitation message is expected.
+
+The error **MAY** include a list of elicitations that are required to complete before the original
+can be retried.
+
+Elicitations returned in the error **MUST** be out-of-band mode elicitations and have an `elicitationId` property.
+Servers that want form mode elicitations before another request can be retried **SHOULD** make a separate elicitation request for each form mode elicitation.
+
+**Error Response:**
```json
{
"jsonrpc": "2.0",
"id": 2,
- "result": {
- "action": "cancel"
+ "error": {
+ "code": -32604,
+ "message": "ElicitationRequired",
+ "data": {
+ "elicitations": [
+ {
+ "mode": "oob",
+ "elicitionId": "550e8400-e29b-41d4-a716-446655440000",
+ "url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
+ "message": "Authorization is required to access your Example Co files.",
+ }
+ ]
+ }
}
}
```
+Clients can use the `elicitationId` to track the progress of the elicitation by sending a `elicitation/track` request.
+
## Message Flow
### Form Mode Flow
@@ -328,15 +342,14 @@ sequenceDiagram
participant Client
participant Server
- Note over Server,Client: Server initiates form elicitation
+ Note over Server: Server initiates elicitation
Server->>Client: elicitation/create (mode: form)
- Note over Client,User: Human interaction
- Client->>User: Present elicitation UI
+ Note over User,Client: Present elicitation UI
User-->>Client: Provide requested information
Note over Server,Client: Complete request
- Client-->>Server: Return user response
+ Client->>Server: Return user response
Note over Server: Continue processing with new information
```
@@ -345,125 +358,77 @@ sequenceDiagram
```mermaid
sequenceDiagram
- participant Server
- participant Client
- participant User
participant UserAgent as User Agent (Browser)
-
- Note over Server,Client: Server initiates out-of-band elicitation
- Server->>Client: elicitation/create (mode: oob)
-
- Client->>User: Present consent to open URL
- User->>Client: Provide consent
-
- Client->>UserAgent: Open URL
- Client->>Server: Response (action: accept), with optional progressToken
-
- Note over User,UserAgent: User interaction (e.g. OAuth flow)
- UserAgent-->>Server: Interaction complete
-
- Server->>Client: notifications/progress (optional)
-```
-
-### Example: Elicitation Required for Tool Call
-
-When an elicitation interaction is required as part of another request, the server **SHOULD**
-return error -32604 to indicate to the client that an elicitation message is expected.
-TODO: Finalize this error code and do a find-replace in the whole repo if it needs to change
-
-In subsequent elicitation message(s), the server **SHOULD** set the `correlatedRequestId`
-property to the JSON-RPC request ID of the original request.
-
-When an elicitation is needed in response to another request (e.g., a tool call requiring payment):
-
-```mermaid
-sequenceDiagram
+ participant User
participant Client
participant Server
- participant User
- participant UserAgent as User Agent
- Client->>Server: tools/call (id: 123)
-
- Note over Server: Server needs authorization
- Server->>Client: Error acknowledging need for auth (code: -32604)
- Server->>Client: elicitation/create (id: 124, mode: oob, correlatedRequestId: 123)
- Note over Client: Client associates elicitation request 124 with tool call 123
+ Note over Server: Server initiates elicitation
+ Server->>Client: elicitation/create (mode: oob)
Client->>User: Present consent to open URL
- User->>Client: Provide consent
+ User-->>Client: Provide consent
Client->>UserAgent: Open URL
- Client->>Server: Response (action: accept), with optional progressToken
+ Client->>Server: Accept response
+ Client-->>Server: elicitation/track (optional)
- Note over User,UserAgent: User interaction (e.g. OAuth flow)
+ Note over User,UserAgent: User interaction
+ Server-->>Client: notifications/progress (optional)
UserAgent-->>Server: Interaction complete
+ Server-->>Client: elicitation/track complete (optional)
- Server->>Client: notifications/progress (optional)
-
- Client->>Server: Retry tools/call (optional)
+ Note over Server: Continue processing with new information
```
-TODO: I'm on the fence whether we should add an even more detailed example of doing downstream OAuth.
-I don't want to fixate the whole OOB section on OAuth, but it is the most-requested thing to do.
-We could keep it here, or alternatively move it to a new doc about "OAuth best practices" or even a blog post.
-Adding it below in case we decide to keep it:
-
-### Example: OAuth to Downstream Resource Server (TODO decide to keep?)
-
-A variation on the above example is downstream OAuth authorization for a tool or resource
-call.
-
-In this scenario, the MCP client acts as an OAuth 2.1 client to the MCP server (as
-described in [MCP authorization](/docs/specification/draft/basic/authorization.mdx)). The
-MCP server then acts as an OAuth client to a downstream (third-party) Authorization Server
-and Resource Server.
+### Elicitation Required Error Flow
```mermaid
sequenceDiagram
+ participant UserAgent as User Agent (Browser)
+ participant User
participant Client
participant Server
- participant User
- participant UserAgent as User Agent
- participant 3PAS as 3rd-party Authorization Server
- participant 3PRS as 3rd-party Resource Server
- Client->>Server: tools/call (id: 123)
+ Client->>Server: tools/call
Note over Server: Server needs authorization
- Note over Server: Generate OAuth 2.1 authorization URL to downstream AS
- Server->>Client: Error acknowledging need for auth (code: -32604)
- Server->>Client: elicitation/create (id: 124, mode: oob, correlatedRequestId: 123)
- Note over Client: Client associates elicitation request 124 with tool call 123
+ Server->>Client: ElicitationRequired error
+ Note over Client: Client notes the tools/call can be retried after elicitation
Client->>User: Present consent to open URL
- User->>Client: Provide consent
+ User-->>Client: Provide consent
Client->>UserAgent: Open URL
- Client->>Server: Response (action: accept), with optional progressToken
+ Client-->>Server: elicitation/track (optional)
- UserAgent-->>3PAS: Redirect
- Note over User,UserAgent,3PAS: OAuth flow
- 3PAS-->>Server: Callback
- Server-->>3PAS: Token exchange (server acting as OAuth 2.1 client)
- Note over Server: Server binds 3rd-party tokens to MCP user
+ Note over User,UserAgent: User interaction
+ Server-->>Client: notifications/progress (optional)
- Server->>Client: notifications/progress (optional)
+ UserAgent-->>Server: Interaction complete
+ Server-->>Client: elicitation/track complete (optional)
Client->>Server: Retry tools/call (optional)
- Note over Server: Retrieve 3rd-party tokens for MCP user
- Server-->>3PRS: API request to resource server (server acting as OAuth 2.1 client)
- 3PRS-->>Server: API response
- Server->>Client: Tool response
```
## Request Schema
+Common parameters for all elicitation requests are:
+
+| Name | Type | Required | Options | Description |
+|-----------------|--------|-------------|-------------------|-------------|
+| `mode` | string | RECOMMENDED | `"form"`, `"oob"` | The mode of the elicitation. Default is `"form"`. |
+| `elicitationId` | string | REQUIRED for `"oob"` | | A unique identifier for the elicitation. |
+
### Form Mode Schema
-For `form` mode, the `requestedSchema` field allows servers to define the structure of the expected response using a restricted subset of JSON Schema. To simplify implementation for clients, elicitation schemas are limited to flat objects with primitive properties only:
+For `form` mode, the `requestedSchema` parameter allows servers to define the structure of the expected
+response using a restricted subset of JSON Schema. To simplify implementation for clients,
+elicitation schemas are limited to flat objects with primitive properties only:
```json
+"mode": "form",
+"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
"requestedSchema": {
"type": "object",
"properties": {
@@ -546,26 +511,48 @@ Note that complex nested structures, arrays of objects, and other advanced JSON
### Out-of-Band Mode Parameters
-For `oob` mode, the request parameters are:
+For `oob` mode elicitation, the `mode` parameter **MUST** be set to `"oob"` and `elicitationId` **MUST** be provided.
+
+Request parameters specific to `oob` mode are:
-- `mode`: **MUST** be `"oob"`
-- `url`: **REQUIRED** - The URL that the user should navigate to
-// TODO: should it be `url` or `uri`? There was a question on 475 about other protocols like tel://
-// I am leaning towards `url` because then we can keep a clean MUST in Security Considerations about always requiring https://
-// My only sticking point is mobile app schemes - would being able to redirect to my-app:// be useful, or a bigger can of worms?
-- `message`: **OPTIONAL** - Human-readable explanation of why the interaction is needed
+| Name | Type | Required | Description |
+|-----------|--------|----------|-------------|
+| `url` | string | REQUIRED | The URL that the user should navigate to. |
+| `message` | string | REQUIRED | Human-readable explanation of why the interaction is needed. |
Parameters **MUST NOT** include:
- `requestedSchema` - This is only for form mode
-- Any URLs in the `message` field. URLs must only appear in the `url` field
+- Any URLs in the `message` field; URLs must only appear in the `url` field
+
+```json
+"mode": "oob",
+"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
+"url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
+"message": "Authorization is required to access your Example Co files.",
+```
+
+## Progress Tracking
+
+Particularly for out-of-band mode, where the client is not involved in the interaction, the client **MAY** choose to request progress updates from the server.
+Elicitation leverages MCP's [Progress Utility](/specification/draft/basic/utilities/progress) to track the progress of the interaction.
+
+The client **MAY** send a `elicitation/track` request to the server to request progress updates.
+
+The client **MUST** include an `elicitationId` in the request to signal to the server which elicitation to send progress updates for.
+
+The client, per the Progress Utility protocol, **MUST** include a `progressToken` in the request to disambiguate across various progress tracking requests.
+
+How that progressToken is generated is left to the client implementation.
+
+The server **MAY** send a `notifications/progress` notification to the client with the progress token and the progress status.
+
+The server **SHOULD** send a `elicitation/track` response to the client once the elicitation is complete.=
## Response Actions
Elicitation responses use a three-action model to clearly distinguish between different user actions.
-Additionally, responses **MAY** include a progress token to enable progress tracking for long-running operations.
-
```json
{
"jsonrpc": "2.0",
@@ -575,20 +562,6 @@ Additionally, responses **MAY** include a progress token to enable progress trac
"content": {
"propertyName": "value",
"anotherProperty": 42
- },
- "_meta": {
- "progressToken": "client-token-123" // Optional: enables progress tracking.
- // TODO: According to a strict reading of the progress spec, this is incorrect(!)
- // because this is a JSONRPCResponse.Result payload. While Result does contain a `_meta` key,
- // `_meta.progressToken` is only defined on JSONRPCRequest, not JSONRPCResponse.Result
- // We worked within the boundaries of a strict reading of the progress spec in the original
- // UI PR 475 by introducing another request message, `interactions/track` so that the progressToken
- // could be passed in a proper JSONRPCRequest.
- // @ggoodman noted that this felt very inefficient (he's right). I still feel like this PR
- // isn't the place to amend the progress spec, but maybe worth opening a discussion
- // on the MCP github to see if there's an appetite for adding `_meta.progressToken` to JSONRPCResponse.Result
- // Unless/until the progress spec is updated, I believe the correct spec-compliant thing to do here
- // is to reintroduce something like `elicitations/track` :/
}
}
}
@@ -617,25 +590,6 @@ Servers should handle each state appropriately:
- **Decline**: Handle explicit rejection (e.g., offer alternatives)
- **Cancel**: Handle dismissal (e.g., prompt again later)
-### Progress Tracking
-
-When the client includes a `progressToken` in its response, the server **MAY** send progress notifications:
-
-```json
-{
- "jsonrpc": "2.0",
- "method": "notifications/progress",
- "params": {
- "progressToken": "client-token-123",
- "progress": 50,
- "total": 100,
- "message": "User completing authorization..."
- }
-}
-```
-
-This is particularly useful for out-of-band mode where the interaction is a disconnected flow that may take time to complete.
-
## Security Considerations
1. Clients **MUST** provide clear indication of which server is requesting information
@@ -651,7 +605,7 @@ Instead, servers **SHOULD** follow [security best practices](/specification/draf
Non-normative examples:
- Incorrect: Treat user input like "I am joe@example.com" as authoritative
-- Correct: Rely on the [MCP authorization server](/docs/specification/draft/basic/authorization.mdx) to identify the user
+- Correct: Rely on the [MCP authorization server](/specification/draft/basic/authorization) to identify the user
### Form Mode Security
@@ -675,7 +629,7 @@ Since clients open URLs provided by servers, they **MUST** implement SSRF protec
#### Phishing
-One use of out of band elicitation is to perform OAuth flows where the server acts as an
+One use of out-of-band elicitation is to perform OAuth flows where the server acts as an
OAuth client of another resource server. In this case, the server generates an
authorization URL to the third-party resource server and passes it to the client in the
form of an `oob` elicitation request.
@@ -687,7 +641,7 @@ Without proper mitigation, the following phishing attack is possible:
4. Bob follows the link and completes the authorization, thinking they are authorizing their own connection to the benign server
5. 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**:
-- Send an `elicitation/verify` message after the out-of-band interaction is complete, but _before_ the elicitation interaction is considered complete
-- Bind out-of-band elicitation requests to the identity of the user, and ensure the `elicitation/verify` response is sent from the same identity // TODO might need to word better, what I really mean is "the Bearer token is for the same person"
-- Bind out-of-band elicitation requests to the MCP session, and ensure the `elicitation/verify` response belongs to the same session // TODO: Is this too narrow? Not all transports support sessions. What if the session expires too soon?
\ No newline at end of file
+To prevent this attack, the server **MUST**, upon recieving the redirect_uri from the third-party authorization server,
+ensure the user who is completing the authorization is the same user who initiated the elicitation request. Typically this
+is done by leveraging the [MCP authorization server](/specification/draft/basic/authorization) to identify the user,
+through a session cookie or equivalent in the browser.
From 0b661e868c32274a89912e16140ebb53baf0434b Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Sat, 28 Jun 2025 22:43:26 -0600
Subject: [PATCH 03/62] Fixing errata
---
docs/specification/draft/basic/lifecycle.mdx | 5 +-
.../draft/client/elicitation.mdx | 184 +++++----
schema/draft/schema.json | 389 +++++++++++++-----
schema/draft/schema.ts | 157 ++++---
4 files changed, 481 insertions(+), 254 deletions(-)
diff --git a/docs/specification/draft/basic/lifecycle.mdx b/docs/specification/draft/basic/lifecycle.mdx
index b6a84a3f0..0dc25f084 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": {},
+ "oob": {}
+ }
},
"clientInfo": {
"name": "ExampleClient",
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 6a69bf408..f7e8dacd9 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -20,7 +20,7 @@ necessary information dynamically.
Elicitation supports two modes:
- **Form mode** (in-band): Servers can request structured data from users with optional JSON schemas to validate responses
-- **Out-of-band mode**: Servers can direct users to external URLs for interactions that should not pass through the MCP client, such as OAuth authorization flows
+- **Out-of-band mode**: Servers can direct users to external URLs for interactions that must _not_ pass through the MCP client, such as OAuth authorization flows
## User Interaction Model
@@ -53,16 +53,6 @@ Applications **SHOULD**:
Clients that support elicitation **MUST** declare the `elicitation` capability during
[initialization](/specification/draft/basic/lifecycle#initialization):
-```json
-{
- "capabilities": {
- "elicitation": {}
- }
-}
-```
-
-Clients **MAY** specify sub-capabilities for elicitation modes they support:
-
```json
{
"capabilities": {
@@ -74,9 +64,9 @@ Clients **MAY** specify sub-capabilities for elicitation modes they support:
}
```
-If sub-capabilities are not present, servers **MUST** assume the client _only_ supports `form` mode for backward compatibility.
+Clients declaring the `elicitation` capability **MUST** support at least one mode (`form` or `oob`).
-Servers **MUST NOT** send elicitation requests with modes that are not explicitly declared by the client.
+Servers **MUST NOT** send elicitation requests with modes that are not supported by the client.
## Protocol Messages
@@ -84,7 +74,7 @@ Servers **MUST NOT** send elicitation requests with modes that are not explicitl
To request information from a user, servers send an `elicitation/create` request. The request **SHOULD** include a `mode` parameter that specifies the type of elicitation:
-- `"form"` (default): In-band structured data collection with optional schema validation. Data is exposed to the client.
+- `"form"`: In-band structured data collection with optional schema validation. Data is exposed to the client.
- `"oob"`: Out-of-band interaction via URL navigation. Data is **not** exposed to the client.
#### Form Mode (In-Band)
@@ -187,7 +177,7 @@ Form mode allows servers to collect structured data directly through the MCP cli
#### Out-of-Band Mode
Out-of-band mode enables servers to direct users to external URLs for interactions that
-should not pass through the MCP client. This is essential for auth flows, payment
+must not pass through the MCP client. This is essential for auth flows, payment
processing, and other sensitive or secure operations.
**Request:**
@@ -218,19 +208,22 @@ processing, and other sensitive or secure operations.
}
```
-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. To be aware of the outcome, the client can leverage the
-[Progress Utility](/specification/draft/basic/utilities/progress), when supported by the server, to
-track the progress of the interaction.
+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.
+
+The client **MAY** send an `elicitation/track` request and use the [Progress utility](/specification/draft/basic/utilities/progress),
+when supported by the server, to track the progress of the interaction.
-**Progress Tracking Request (from client to server):**
+**Progress Tracking Request:**
+
+The client **MAY** send an `elicitation/track` request to the server to track the progress of the interaction:
```json
{
"jsonrpc": "2.0",
- "id": 3,
+ "id": 4,
"method": "elicitation/track",
"params": {
"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
@@ -240,7 +233,9 @@ track the progress of the interaction.
}
```
-**Progress Tracking Notification (from server to client):**
+**Progress Tracking Notification:**
+
+The server **MAY** send a `notifications/progress` notification to the client with the progress token and the progress status:
```json
{
@@ -254,12 +249,14 @@ track the progress of the interaction.
}
```
-**Progress Tracking Response (from server to client):**
+**Progress Tracking Response:**
+
+The server **SHOULD** send a `elicitation/track` response to the client once the elicitation is complete.
```json
{
"jsonrpc": "2.0",
- "id": 3,
+ "id": 4,
"result": {
"status": "complete"
}
@@ -295,17 +292,17 @@ The response payloads are identical for either form or out-of-band mode.
}
```
-### ElicitationRequired Errors
+### Elicitation Required Error
When another request cannot be processed until an elicitation is completed, the server **SHOULD**
-return an [ElicitationRequired](/docs/concepts/architecture#error-handling) error to indicate to
-the client that an elicitation message is expected.
+return an [ElicitationRequired error](/docs/concepts/architecture#error-handling) (code `-32604`) to indicate to
+the client that an elicitation is required.
-The error **MAY** include a list of elicitations that are required to complete before the original
+The error **MUST** include a list of elicitations that are required to complete before the original
can be retried.
-Elicitations returned in the error **MUST** be out-of-band mode elicitations and have an `elicitationId` property.
-Servers that want form mode elicitations before another request can be retried **SHOULD** make a separate elicitation request for each form mode elicitation.
+Any elicitations returned in the error **MUST** be out-of-band mode elicitations and have an `elicitationId` property.
+Servers that want elicit data from the user via form mode **SHOULD** make a separate elicitation request for each form mode elicitation.
**Error Response:**
@@ -314,8 +311,8 @@ Servers that want form mode elicitations before another request can be retried *
"jsonrpc": "2.0",
"id": 2,
"error": {
- "code": -32604,
- "message": "ElicitationRequired",
+ "code": -32604, // ELICITATION_REQUIRED
+ "message": "This request requires more information.",
"data": {
"elicitations": [
{
@@ -330,7 +327,6 @@ Servers that want form mode elicitations before another request can be retried *
}
```
-Clients can use the `elicitationId` to track the progress of the elicitation by sending a `elicitation/track` request.
## Message Flow
@@ -415,35 +411,45 @@ sequenceDiagram
Common parameters for all elicitation requests are:
-| Name | Type | Required | Options | Description |
-|-----------------|--------|-------------|-------------------|-------------|
-| `mode` | string | RECOMMENDED | `"form"`, `"oob"` | The mode of the elicitation. Default is `"form"`. |
-| `elicitationId` | string | REQUIRED for `"oob"` | | A unique identifier for the elicitation. |
+| Name | Type | Options | Description |
+|-----------------|--------|-------------------|----------------------------------------------------------------------|
+| `mode` | string | `"form"`, `"oob"` | The mode of the elicitation. |
+| `message` | string | | A human-readable message explaining why the interaction is needed. |
### Form Mode Schema
For `form` mode, the `requestedSchema` parameter allows servers to define the structure of the expected
-response using a restricted subset of JSON Schema. To simplify implementation for clients,
-elicitation schemas are limited to flat objects with primitive properties only:
+response using a restricted subset of JSON Schema.
+
+Request parameters specific to `form` mode are:
+
+| Name | Type | Description |
+|------------------|--------|------------------------------------------------------------------|
+| `requestedSchema`| object | A JSON Schema defining the structure of the expected response. |
+
+To simplify implementation for clients, elicitation schemas are limited to flat objects
+with primitive properties only:
```json
-"mode": "form",
-"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
-"requestedSchema": {
- "type": "object",
- "properties": {
- "propertyName": {
- "type": "string",
- "title": "Display Name",
- "description": "Description of the property"
+{
+ "mode": "form",
+ "message": "Please provide some required information",
+ "requestedSchema": {
+ "type": "object",
+ "properties": {
+ "propertyName": {
+ "type": "string",
+ "title": "Display Name",
+ "description": "Description of the property"
+ },
+ "anotherProperty": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 100
+ }
},
- "anotherProperty": {
- "type": "number",
- "minimum": 0,
- "maximum": 100
- }
- },
- "required": ["propertyName"]
+ "required": ["propertyName"]
+ }
}
```
@@ -515,35 +521,35 @@ For `oob` mode elicitation, the `mode` parameter **MUST** be set to `"oob"` and
Request parameters specific to `oob` mode are:
-| Name | Type | Required | Description |
-|-----------|--------|----------|-------------|
-| `url` | string | REQUIRED | The URL that the user should navigate to. |
-| `message` | string | REQUIRED | Human-readable explanation of why the interaction is needed. |
+| Name | Type | Description |
+|-----------------|--------|---------------------------------------------|
+| `url` | string | The URL that the user should navigate to. |
+| `elicitationId` | string | A unique identifier for the elicitation. |
Parameters **MUST NOT** include:
-- `requestedSchema` - This is only for form mode
+- `requestedSchema` - Only used for form mode
- Any URLs in the `message` field; URLs must only appear in the `url` field
```json
-"mode": "oob",
-"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
-"url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
-"message": "Authorization is required to access your Example Co files.",
+{
+ "mode": "oob",
+ "elicitationId": "550e8400-e29b-41d4-a716-446655440000",
+ "url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
+ "message": "Authorization is required to access your Example Co files."
+}
```
## Progress Tracking
-Particularly for out-of-band mode, where the client is not involved in the interaction, the client **MAY** choose to request progress updates from the server.
-Elicitation leverages MCP's [Progress Utility](/specification/draft/basic/utilities/progress) to track the progress of the interaction.
+The client **MAY** choose to request progress updates from the server. This is particularly useful in out-of-band mode, because the client is not involved in the interaction.
+Elicitation leverages MCP's [Progress utility](/specification/draft/basic/utilities/progress) to track the progress of the interaction.
The client **MAY** send a `elicitation/track` request to the server to request progress updates.
-The client **MUST** include an `elicitationId` in the request to signal to the server which elicitation to send progress updates for.
+The client **MUST** include an `elicitationId` in the request to identify which elicitation to send progress updates for. The server **MUST** ignore any `elicitation/track` requests containing an `elicitationId` that is not known or does not belong to the client.
-The client, per the Progress Utility protocol, **MUST** include a `progressToken` in the request to disambiguate across various progress tracking requests.
-
-How that progressToken is generated is left to the client implementation.
+The client **MUST** include a `progressToken` in the request. How that progress token is generated is left to the client implementation.
The server **MAY** send a `notifications/progress` notification to the client with the progress token and the progress status.
@@ -598,6 +604,14 @@ Servers should handle each state appropriately:
4. Clients **SHOULD** implement rate limiting
5. Clients **SHOULD** present elicitation requests in a way that makes it clear what information is being requested and why
+### URL Safety
+
+Clients implementing out-of-band elicitation **MUST** implement the safety checks for URLs described below. These strict controls, including obtaining consent from the user, help prevent users from unknowingly clicking malicious links.
+
+URLs **MUST NOT** be present in any message or schema fields as part of an out-of-band elicitation request EXCEPT for the `url` field.
+
+URLs **MUST NOT** be present in any message or schema fields as part of a form elicitation request.
+
### Identifying the User
Servers **MUST NOT** rely on client-provided user identification, as this can be forged.
@@ -610,9 +624,8 @@ Non-normative examples:
### Form Mode Security
1. Servers **MUST NOT** request sensitive information (passwords, API keys, etc.) via form mode
-2. Servers **MUST NOT** place URLs intended for user interaction in form mode messages or schemas
-3. Clients **SHOULD** validate all responses against the provided schema
-4. Servers **SHOULD** validate received data matches the requested schema
+2. Clients **SHOULD** validate all responses against the provided schema
+3. Servers **SHOULD** validate received data matches the requested schema
### Out-of-Band Mode Security
@@ -620,7 +633,7 @@ Non-normative examples:
#### Server-Side Request Forgery (SSRF)
-Since clients open URLs provided by servers, they **MUST** implement SSRF protections:
+Since clients open URLs provided by servers, they **MUST** implement SSRF protection, including:
- Block requests to internal IP ranges (e.g., 127.0.0.1, 10.0.0.0/8, etc.)
- Require the `https://` scheme for all out-of-band URLs (no HTTP, file://, etc.)
@@ -636,12 +649,15 @@ form of an `oob` elicitation request.
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 resource server
-3. Instead of clicking on the link, Alice tricks a victim user (Bob) of the same benign server into clicking it
-4. Bob follows the link and completes the authorization, thinking they are authorizing their own connection to the benign server
-5. 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**, upon recieving the redirect_uri from the third-party authorization server,
-ensure the user who is completing the authorization is the same user who initiated the elicitation request. Typically this
-is done by leveraging the [MCP authorization server](/specification/draft/basic/authorization) to identify the user,
-through a session cookie or equivalent in the browser.
+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** check the identity of the user (step 6 in the
+above example), and confirm that the user who is completing the authorization is the same
+user who initiated the elicitation request. Typically this is done by
+leveraging the [MCP authorization server](/specification/draft/basic/authorization) to
+identify the user, through a session cookie or equivalent in the browser.
diff --git a/schema/draft/schema.json b/schema/draft/schema.json
index cf73245cf..e4398fe3c 100644
--- a/schema/draft/schema.json
+++ b/schema/draft/schema.json
@@ -216,21 +216,64 @@
"description": "Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.",
"properties": {
"elicitation": {
- "description": "Present if the client supports elicitation from the server.",
- "properties": {
- "modes": {
- "description": "The elicitation modes that the client supports.\nIf not specified, the server MUST assume the client only supports \"form\" mode.",
- "items": {
- "enum": [
- "form",
- "oob"
- ],
- "type": "string"
+ "anyOf": [
+ {
+ "properties": {
+ "form": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ },
+ "oob": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ }
},
- "type": "array"
+ "required": [
+ "form"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "form": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ },
+ "oob": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ }
+ },
+ "required": [
+ "oob"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "form": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ },
+ "oob": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ }
+ },
+ "required": [
+ "form",
+ "oob"
+ ],
+ "type": "object"
}
- },
- "type": "object"
+ ],
+ "description": "Present if the client supports elicitation from the server."
},
"experimental": {
"additionalProperties": {
@@ -572,55 +615,14 @@
"type": "string"
},
"params": {
- "properties": {
- "message": {
- "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor out-of-band mode: Explains why the interaction is needed.",
- "type": "string"
- },
- "mode": {
- "description": "The mode of elicitation.\n- \"form\": In-band structured data collection with optional schema validation\n- \"oob\": Out-of-band interaction via URL navigation\n\nIf not specified, \"form\" is assumed.",
- "enum": [
- "form",
- "oob"
- ],
- "type": "string"
- },
- "requestedSchema": {
- "description": "For form mode only: A restricted subset of JSON Schema.\nOnly top-level properties are allowed, without nesting.\n\nRequired when mode is \"form\" or unspecified.\nMust NOT be present when mode is \"oob\".",
- "properties": {
- "properties": {
- "additionalProperties": {
- "$ref": "#/definitions/PrimitiveSchemaDefinition"
- },
- "type": "object"
- },
- "required": {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "type": {
- "const": "object",
- "type": "string"
- }
- },
- "required": [
- "properties",
- "type"
- ],
- "type": "object"
+ "anyOf": [
+ {
+ "$ref": "#/definitions/OutOfBandElicitRequestParams"
},
- "url": {
- "description": "For out-of-band mode only: The URL that the user should navigate to.\n\nRequired when mode is \"oob\".\nMust NOT be present when mode is \"form\".",
- "format": "uri",
- "type": "string"
+ {
+ "$ref": "#/definitions/FormElicitRequestParams"
}
- },
- "required": [
- "message"
- ],
- "type": "object"
+ ]
}
},
"required": [
@@ -629,6 +631,40 @@
],
"type": "object"
},
+ "ElicitRequestParams": {
+ "additionalProperties": {},
+ "description": "The parameters for a request to elicit additional information from the user via the client.",
+ "properties": {
+ "_meta": {
+ "additionalProperties": {},
+ "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
+ "properties": {
+ "progressToken": {
+ "$ref": "#/definitions/ProgressToken",
+ "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
+ }
+ },
+ "type": "object"
+ },
+ "message": {
+ "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor out-of-band mode: Explains why the interaction is needed.",
+ "type": "string"
+ },
+ "mode": {
+ "description": "The mode of elicitation.\n- \"form\": In-band structured data collection with optional schema validation\n- \"oob\": Out-of-band interaction via URL navigation",
+ "enum": [
+ "form",
+ "oob"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "message",
+ "mode"
+ ],
+ "type": "object"
+ },
"ElicitResult": {
"description": "The client's response to an elicitation request.",
"properties": {
@@ -663,6 +699,56 @@
],
"type": "object"
},
+ "ElicitationRequiredError": {
+ "description": "An error response that indicates that the server requires the client to provide additional information via an elicitation request.",
+ "properties": {
+ "error": {
+ "properties": {
+ "code": {
+ "const": -32604,
+ "type": "integer"
+ },
+ "data": {
+ "additionalProperties": {},
+ "properties": {
+ "elicitations": {
+ "items": {
+ "$ref": "#/definitions/OutOfBandElicitRequestParams"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "elicitations"
+ ],
+ "type": "object"
+ },
+ "message": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "code",
+ "data",
+ "message"
+ ],
+ "type": "object"
+ },
+ "id": {
+ "$ref": "#/definitions/RequestId"
+ },
+ "jsonrpc": {
+ "const": "2.0",
+ "type": "string"
+ }
+ },
+ "required": [
+ "error",
+ "id",
+ "jsonrpc"
+ ],
+ "type": "object"
+ },
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit\nof the LLM and/or the user.",
"properties": {
@@ -730,6 +816,61 @@
],
"type": "object"
},
+ "FormElicitRequestParams": {
+ "properties": {
+ "_meta": {
+ "additionalProperties": {},
+ "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
+ "properties": {
+ "progressToken": {
+ "$ref": "#/definitions/ProgressToken",
+ "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
+ }
+ },
+ "type": "object"
+ },
+ "message": {
+ "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor out-of-band mode: Explains why the interaction is needed.",
+ "type": "string"
+ },
+ "mode": {
+ "const": "form",
+ "description": "The mode of elicitation.",
+ "type": "string"
+ },
+ "requestedSchema": {
+ "description": "A restricted subset of JSON Schema.\nOnly top-level properties are allowed, without nesting.\n\nRequired when mode is \"form\" or unspecified.",
+ "properties": {
+ "properties": {
+ "additionalProperties": {
+ "$ref": "#/definitions/PrimitiveSchemaDefinition"
+ },
+ "type": "object"
+ },
+ "required": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "type": {
+ "const": "object",
+ "type": "string"
+ }
+ },
+ "required": [
+ "properties",
+ "type"
+ ],
+ "type": "object"
+ }
+ },
+ "required": [
+ "message",
+ "mode"
+ ],
+ "type": "object"
+ },
"GetPromptRequest": {
"description": "Used by the client to get a prompt provided by the server.",
"properties": {
@@ -1026,21 +1167,15 @@
"type": "string"
},
"params": {
- "additionalProperties": {},
- "properties": {
- "_meta": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/RequestParamsMeta"
+ },
+ {
"additionalProperties": {},
- "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
- "properties": {
- "progressToken": {
- "$ref": "#/definitions/ProgressToken",
- "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
- }
- },
"type": "object"
}
- },
- "type": "object"
+ ]
}
},
"required": [
@@ -1217,21 +1352,15 @@
"type": "string"
},
"params": {
- "additionalProperties": {},
- "properties": {
- "_meta": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/RequestParamsMeta"
+ },
+ {
"additionalProperties": {},
- "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
- "properties": {
- "progressToken": {
- "$ref": "#/definitions/ProgressToken",
- "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
- }
- },
"type": "object"
}
- },
- "type": "object"
+ ]
}
},
"required": [
@@ -1443,6 +1572,46 @@
],
"type": "object"
},
+ "OutOfBandElicitRequestParams": {
+ "properties": {
+ "_meta": {
+ "additionalProperties": {},
+ "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
+ "properties": {
+ "progressToken": {
+ "$ref": "#/definitions/ProgressToken",
+ "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
+ }
+ },
+ "type": "object"
+ },
+ "elicitationId": {
+ "description": "The ID of the elicitation, which must be unique within the context of the server.\nThe client MUST treat this ID as an opaque value.",
+ "type": "string"
+ },
+ "message": {
+ "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor out-of-band mode: Explains why the interaction is needed.",
+ "type": "string"
+ },
+ "mode": {
+ "const": "oob",
+ "description": "The mode of elicitation.",
+ "type": "string"
+ },
+ "url": {
+ "description": "The URL that the user should navigate to.",
+ "format": "uri",
+ "type": "string"
+ }
+ },
+ "required": [
+ "elicitationId",
+ "message",
+ "mode",
+ "url"
+ ],
+ "type": "object"
+ },
"PaginatedRequest": {
"properties": {
"method": {
@@ -1485,21 +1654,15 @@
"type": "string"
},
"params": {
- "additionalProperties": {},
- "properties": {
- "_meta": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/RequestParamsMeta"
+ },
+ {
"additionalProperties": {},
- "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
- "properties": {
- "progressToken": {
- "$ref": "#/definitions/ProgressToken",
- "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
- }
- },
"type": "object"
}
- },
- "type": "object"
+ ]
}
},
"required": [
@@ -1750,21 +1913,15 @@
"type": "string"
},
"params": {
- "additionalProperties": {},
- "properties": {
- "_meta": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/RequestParamsMeta"
+ },
+ {
"additionalProperties": {},
- "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
- "properties": {
- "progressToken": {
- "$ref": "#/definitions/ProgressToken",
- "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
- }
- },
"type": "object"
}
- },
- "type": "object"
+ ]
}
},
"required": [
@@ -1779,6 +1936,22 @@
"integer"
]
},
+ "RequestParamsMeta": {
+ "properties": {
+ "_meta": {
+ "additionalProperties": {},
+ "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
+ "properties": {
+ "progressToken": {
+ "$ref": "#/definitions/ProgressToken",
+ "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
"Resource": {
"description": "A known resource that the server is capable of reading.",
"properties": {
diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts
index 5a811ccb8..28f07ab6f 100644
--- a/schema/draft/schema.ts
+++ b/schema/draft/schema.ts
@@ -22,19 +22,22 @@ export type ProgressToken = string | number;
*/
export type Cursor = string;
-export interface Request {
- method: string;
- params?: {
+export interface RequestParamsMeta {
+ /**
+ * See [specification/draft/basic/index#general-fields] for notes on _meta usage.
+ */
+ _meta?: {
/**
- * See [specification/draft/basic/index#general-fields] for notes on _meta usage.
+ * If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
*/
- _meta?: {
- /**
- * If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
- */
- progressToken?: ProgressToken;
- [key: string]: unknown;
- };
+ progressToken?: ProgressToken;
+ [key: string]: unknown;
+ };
+}
+
+export interface Request {
+ method: string;
+ params?: RequestParamsMeta & {
[key: string]: unknown;
};
}
@@ -93,7 +96,7 @@ export const INVALID_REQUEST = -32600;
export const METHOD_NOT_FOUND = -32601;
export const INVALID_PARAMS = -32602;
export const INTERNAL_ERROR = -32603;
-export const ELICITATION_REQUIRED = -32604; // TODO finalize error number
+export const ELICITATION_REQUIRED = -32604;
/**
* A response to a request that indicates an error occurred.
@@ -117,6 +120,20 @@ export interface JSONRPCError {
};
}
+/**
+ * An error response that indicates that the server requires the client to provide additional information via an elicitation request.
+ */
+export interface ElicitationRequiredError extends JSONRPCError {
+ error: {
+ code: typeof ELICITATION_REQUIRED;
+ message: string;
+ data: {
+ elicitations: OutOfBandElicitRequestParams[];
+ [key: string]: unknown;
+ };
+ };
+}
+
/* Empty result */
/**
* A response that indicates success but carries no data.
@@ -216,13 +233,10 @@ export interface ClientCapabilities {
/**
* Present if the client supports elicitation from the server.
*/
- elicitation?: {
- /**
- * The elicitation modes that the client supports.
- * If not specified, the server MUST assume the client only supports "form" mode.
- */
- modes?: ("form" | "oob")[];
- };
+ elicitation?:
+ | { form: object; oob?: object }
+ | { form?: object; oob: object }
+ | { form: object; oob: object };
}
/**
@@ -1305,53 +1319,74 @@ export interface RootsListChangedNotification extends Notification {
method: "notifications/roots/list_changed";
}
+export interface FormElicitRequestParams extends ElicitRequestParams {
+ /**
+ * The mode of elicitation.
+ */
+ mode: "form";
+
+ /**
+ * A restricted subset of JSON Schema.
+ * Only top-level properties are allowed, without nesting.
+ *
+ * Required when mode is "form" or unspecified.
+ */
+ requestedSchema?: {
+ type: "object";
+ properties: {
+ [key: string]: PrimitiveSchemaDefinition;
+ };
+ required?: string[];
+ };
+}
+
+export interface OutOfBandElicitRequestParams extends ElicitRequestParams {
+ /**
+ * The mode of elicitation.
+ */
+ mode: "oob";
+
+ /**
+ * The ID of the elicitation, which must be unique within the context of the server.
+ * The client MUST treat this ID as an opaque value.
+ */
+ elicitationId: string;
+
+ /**
+ * The URL that the user should navigate to.
+ *
+ * @format uri
+ */
+ url: string;
+}
+
/**
- * A request from the server to elicit additional information from the user via the client.
+ * The parameters for a request to elicit additional information from the user via the client.
*/
-export interface ElicitRequest extends Request {
- method: "elicitation/create";
- params: {
- /**
- * The mode of elicitation.
- * - "form": In-band structured data collection with optional schema validation
- * - "oob": Out-of-band interaction via URL navigation
- *
- * If not specified, "form" is assumed.
- */
- mode?: "form" | "oob";
+export interface ElicitRequestParams extends RequestParamsMeta {
+ /**
+ * The mode of elicitation.
+ * - "form": In-band structured data collection with optional schema validation
+ * - "oob": Out-of-band interaction via URL navigation
+ */
+ mode: "form" | "oob";
- /**
- * The message to present to the user.
- * For form mode: Describes what information is being requested.
- * For out-of-band mode: Explains why the interaction is needed.
- */
- message: string;
+ /**
+ * The message to present to the user.
+ * For form mode: Describes what information is being requested.
+ * For out-of-band mode: Explains why the interaction is needed.
+ */
+ message: string;
- /**
- * For form mode only: A restricted subset of JSON Schema.
- * Only top-level properties are allowed, without nesting.
- *
- * Required when mode is "form" or unspecified.
- * Must NOT be present when mode is "oob".
- */
- requestedSchema?: {
- type: "object";
- properties: {
- [key: string]: PrimitiveSchemaDefinition;
- };
- required?: string[];
- };
+ [key: string]: unknown;
+}
- /**
- * For out-of-band mode only: The URL that the user should navigate to.
- *
- * Required when mode is "oob".
- * Must NOT be present when mode is "form".
- *
- * @format uri
- */
- url?: string;
- };
+/**
+ * A request from the server to elicit additional information from the user via the client.
+ */
+export interface ElicitRequest extends Request {
+ method: "elicitation/create";
+ params: FormElicitRequestParams | OutOfBandElicitRequestParams;
}
/**
From d576b0399ba67c395c56a5f24c851b5adec29e50 Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Mon, 30 Jun 2025 10:59:33 -0700
Subject: [PATCH 04/62] Fix format
---
.../draft/client/elicitation.mdx | 32 +++++++++----------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index f7e8dacd9..3a9f2e43e 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -191,7 +191,7 @@ processing, and other sensitive or secure operations.
"mode": "oob",
"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
- "message": "Authorization is required to access your Example Co files.",
+ "message": "Authorization is required to access your Example Co files."
}
}
```
@@ -203,7 +203,7 @@ processing, and other sensitive or secure operations.
"jsonrpc": "2.0",
"id": 3,
"result": {
- "action": "accept",
+ "action": "accept"
}
}
```
@@ -215,7 +215,6 @@ of band and the client is not aware of the outcome.
The client **MAY** send an `elicitation/track` request and use the [Progress utility](/specification/draft/basic/utilities/progress),
when supported by the server, to track the progress of the interaction.
-
**Progress Tracking Request:**
The client **MAY** send an `elicitation/track` request to the server to track the progress of the interaction:
@@ -319,7 +318,7 @@ Servers that want elicit data from the user via form mode **SHOULD** make a sepa
"mode": "oob",
"elicitionId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
- "message": "Authorization is required to access your Example Co files.",
+ "message": "Authorization is required to access your Example Co files."
}
]
}
@@ -327,7 +326,6 @@ Servers that want elicit data from the user via form mode **SHOULD** make a sepa
}
```
-
## Message Flow
### Form Mode Flow
@@ -411,10 +409,10 @@ sequenceDiagram
Common parameters for all elicitation requests are:
-| Name | Type | Options | Description |
-|-----------------|--------|-------------------|----------------------------------------------------------------------|
-| `mode` | string | `"form"`, `"oob"` | The mode of the elicitation. |
-| `message` | string | | A human-readable message explaining why the interaction is needed. |
+| Name | Type | Options | Description |
+| --------- | ------ | ----------------- | ------------------------------------------------------------------ |
+| `mode` | string | `"form"`, `"oob"` | The mode of the elicitation. |
+| `message` | string | | A human-readable message explaining why the interaction is needed. |
### Form Mode Schema
@@ -423,9 +421,9 @@ response using a restricted subset of JSON Schema.
Request parameters specific to `form` mode are:
-| Name | Type | Description |
-|------------------|--------|------------------------------------------------------------------|
-| `requestedSchema`| object | A JSON Schema defining the structure of the expected response. |
+| Name | Type | Description |
+| ----------------- | ------ | -------------------------------------------------------------- |
+| `requestedSchema` | object | A JSON Schema defining the structure of the expected response. |
To simplify implementation for clients, elicitation schemas are limited to flat objects
with primitive properties only:
@@ -521,10 +519,10 @@ For `oob` mode elicitation, the `mode` parameter **MUST** be set to `"oob"` and
Request parameters specific to `oob` mode are:
-| Name | Type | Description |
-|-----------------|--------|---------------------------------------------|
-| `url` | string | The URL that the user should navigate to. |
-| `elicitationId` | string | A unique identifier for the elicitation. |
+| Name | Type | Description |
+| --------------- | ------ | ----------------------------------------- |
+| `url` | string | The URL that the user should navigate to. |
+| `elicitationId` | string | A unique identifier for the elicitation. |
Parameters **MUST NOT** include:
@@ -618,6 +616,7 @@ Servers **MUST NOT** rely on client-provided user identification, as this can be
Instead, servers **SHOULD** follow [security best practices](/specification/draft/basic/security_best_practices).
Non-normative examples:
+
- Incorrect: Treat user input like "I am joe@example.com" as authoritative
- Correct: Rely on the [MCP authorization server](/specification/draft/basic/authorization) to identify the user
@@ -648,6 +647,7 @@ authorization URL to the third-party resource server and passes it to the client
form of an `oob` elicitation request.
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
From 80c6ac458503414f4d85fbfd276e67cbc550c890 Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Mon, 30 Jun 2025 16:07:25 -0700
Subject: [PATCH 05/62] Clean up document structure
---
.../draft/client/elicitation.mdx | 344 +++++++-----------
1 file changed, 141 insertions(+), 203 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 3a9f2e43e..087eac64a 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -37,7 +37,7 @@ For trust & safety and security:
- Servers **MUST NOT** use form mode elicitation to request sensitive information
- Servers **MUST** use out-of-band mode for auth flows and other security-sensitive interactions
-- URLs **MUST NOT** appear in form mode messages or schemas
+- URLs **MUST NOT** appear in any field of an elicitation request other than the `url` field for out-of-band mode
Applications **SHOULD**:
@@ -70,18 +70,102 @@ Servers **MUST NOT** send elicitation requests with modes that are not supported
## Protocol Messages
-### Creating Elicitation Requests
+### Elicitation Requests
-To request information from a user, servers send an `elicitation/create` request. The request **SHOULD** include a `mode` parameter that specifies the type of elicitation:
+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`, `oob` | 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.
- `"oob"`: Out-of-band interaction via URL navigation. Data is **not** exposed to the client.
-#### Form Mode (In-Band)
+### Form Elicitation Requests
+
+Form elicitation allows servers to collect structured data directly through the MCP client.
+
+Form elicitation requests **MUST** specify `mode: "form"` and include these parameters:
+
+| Name | Type | Description |
+| ----------------- | ------ | -------------------------------------------------------------- |
+| `requestedSchema` | object | A JSON Schema defining the structure of the expected response. |
+
+
+#### Request Schema
+
+The `requestedSchema` parameter allows servers to define the structure of the expected
+response using a restricted subset of JSON Schema.
+
+To simplify implementation for clients, 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"
+ }
+ ```
+
+ 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
+ }
+ ```
+
+3. **Boolean Schema**
+
+ ```json
+ {
+ "type": "boolean",
+ "title": "Display Name",
+ "description": "Description text",
+ "default": false
+ }
+ ```
+
+4. **Enum Schema**
+ ```json
+ {
+ "type": "string",
+ "title": "Display Name",
+ "description": "Description text",
+ "enum": ["option1", "option2", "option3"],
+ "enumNames": ["Option 1", "Option 2", "Option 3"]
+ }
+ ```
+
+Clients can use this schema to:
+
+1. Generate appropriate input forms
+2. Validate user input before sending
+3. Provide better guidance to users
-Form mode allows servers to collect structured data directly through the MCP client.
+Note that complex nested structures, arrays of objects, and other advanced JSON Schema features are intentionally not supported to simplify client implementation.
-##### Simple Text Request
+#### Example: Simple Text Request
**Request:**
@@ -121,7 +205,7 @@ Form mode allows servers to collect structured data directly through the MCP cli
}
```
-##### Structured Data Request
+#### Example: Structured Data Request
**Request:**
@@ -174,12 +258,30 @@ Form mode allows servers to collect structured data directly through the MCP cli
}
```
-#### Out-of-Band Mode
+### Out-of-Band Elicitation Requests
-Out-of-band mode enables servers to direct users to external URLs for interactions that
+Out-of-band elicitation enables servers to direct users to external URLs for interactions that
must not pass through the MCP client. This is essential for auth flows, payment
processing, and other sensitive or secure operations.
+Out-of-band elicitation requests **MUST** specify `mode: "oob"` and include these 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.
+
+
+In most cases, implementing out-of-band elicitation requires that the server be stateful: it must keep track of some state about the user (authorized/not authorized, paid/not paid, etc).
+
+
+#### Example: Request Sensitive Data
+
+This example shows an out-of-band 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
@@ -190,8 +292,8 @@ processing, and other sensitive or secure operations.
"params": {
"mode": "oob",
"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
- "url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
- "message": "Authorization is required to access your Example Co files."
+ "url": "https://mcp.example.com/ui/set_api_key",
+ "message": "Please provide your API key to continue."
}
}
```
@@ -210,14 +312,24 @@ processing, and other sensitive or secure operations.
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.
+of band and the client is not aware of the outcome, unless the client requests progress updates.
-The client **MAY** send an `elicitation/track` request and use the [Progress utility](/specification/draft/basic/utilities/progress),
-when supported by the server, to track the progress of the interaction.
-**Progress Tracking Request:**
+### Progress Tracking
+
+The client **MAY** request progress updates from the server by sending an `elicitation/track` request with a [progress token](/specification/draft/basic/utilities/progress#progress-token). This is particularly useful in out-of-band mode, because the client is not involved in the interaction.
+
+The client **MUST** include an `elicitationId` in the request to identify which elicitation to send progress updates for. The client **SHOULD** include a `progressToken` in the request's `_meta` field.
+
+The server **MUST** ignore any `elicitation/track` requests containing an `elicitationId` that is not known or does not belong to the client.
+
+The server **MAY** send a `notifications/progress` notification to the client with the progress token and the progress status.
+
+The server **SHOULD** send a `elicitation/track` response to the client once the elicitation is complete.
-The client **MAY** send an `elicitation/track` request to the server to track the progress of the interaction:
+#### Example
+
+**Progress Tracking Request:**
```json
{
@@ -225,17 +337,15 @@ The client **MAY** send an `elicitation/track` request to the server to track th
"id": 4,
"method": "elicitation/track",
"params": {
- "elicitationId": "550e8400-e29b-41d4-a716-446655440000",
"_meta": {
"progressToken": "abc123"
- }
+ },
+ "elicitationId": "550e8400-e29b-41d4-a716-446655440000"
}
```
**Progress Tracking Notification:**
-The server **MAY** send a `notifications/progress` notification to the client with the progress token and the progress status:
-
```json
{
"jsonrpc": "2.0",
@@ -250,8 +360,6 @@ The server **MAY** send a `notifications/progress` notification to the client wi
**Progress Tracking Response:**
-The server **SHOULD** send a `elicitation/track` response to the client once the elicitation is complete.
-
```json
{
"jsonrpc": "2.0",
@@ -262,35 +370,6 @@ The server **SHOULD** send a `elicitation/track` response to the client once the
}
```
-#### Decline and Cancel Responses
-
-For all non-accept responses, the `content` field is omitted.
-The response payloads are identical for either form or out-of-band mode.
-
-**Reject Response Example:**
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 2,
- "result": {
- "action": "reject"
- }
-}
-```
-
-**Cancel Response Example:**
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 2,
- "result": {
- "action": "cancel"
- }
-}
-```
-
### Elicitation Required Error
When another request cannot be processed until an elicitation is completed, the server **SHOULD**
@@ -365,17 +444,17 @@ sequenceDiagram
Client->>UserAgent: Open URL
Client->>Server: Accept response
- Client-->>Server: elicitation/track (optional)
+ Client-->>Server: elicitation/track request (optional)
Note over User,UserAgent: User interaction
Server-->>Client: notifications/progress (optional)
UserAgent-->>Server: Interaction complete
- Server-->>Client: elicitation/track complete (optional)
+ Server-->>Client: elicitation/track response (optional)
Note over Server: Continue processing with new information
```
-### Elicitation Required Error Flow
+### Out-of-Band Mode With Elicitation Required Error Flow
```mermaid
sequenceDiagram
@@ -388,174 +467,30 @@ sequenceDiagram
Note over Server: Server needs authorization
Server->>Client: ElicitationRequired error
- Note over Client: Client notes the tools/call can be retried after elicitation
+ Note over Client: Client notes the original request can be retried after elicitation
Client->>User: Present consent to open URL
User-->>Client: Provide consent
Client->>UserAgent: Open URL
- Client-->>Server: elicitation/track (optional)
+ Client->>Server: Accept response
+ Client-->>Server: elicitation/track request (optional)
Note over User,UserAgent: User interaction
Server-->>Client: notifications/progress (optional)
UserAgent-->>Server: Interaction complete
- Server-->>Client: elicitation/track complete (optional)
+ Server-->>Client: elicitation/track response (optional)
Client->>Server: Retry tools/call (optional)
```
-## Request Schema
-
-Common parameters for all elicitation requests are:
-
-| Name | Type | Options | Description |
-| --------- | ------ | ----------------- | ------------------------------------------------------------------ |
-| `mode` | string | `"form"`, `"oob"` | The mode of the elicitation. |
-| `message` | string | | A human-readable message explaining why the interaction is needed. |
-
-### Form Mode Schema
-
-For `form` mode, the `requestedSchema` parameter allows servers to define the structure of the expected
-response using a restricted subset of JSON Schema.
-
-Request parameters specific to `form` mode are:
-| Name | Type | Description |
-| ----------------- | ------ | -------------------------------------------------------------- |
-| `requestedSchema` | object | A JSON Schema defining the structure of the expected response. |
-To simplify implementation for clients, elicitation schemas are limited to flat objects
-with primitive properties only:
-
-```json
-{
- "mode": "form",
- "message": "Please provide some required information",
- "requestedSchema": {
- "type": "object",
- "properties": {
- "propertyName": {
- "type": "string",
- "title": "Display Name",
- "description": "Description of the property"
- },
- "anotherProperty": {
- "type": "number",
- "minimum": 0,
- "maximum": 100
- }
- },
- "required": ["propertyName"]
- }
-}
-```
-
-#### Supported Schema Types
-
-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"
- }
- ```
-
- 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
- }
- ```
-
-3. **Boolean Schema**
-
- ```json
- {
- "type": "boolean",
- "title": "Display Name",
- "description": "Description text",
- "default": false
- }
- ```
-
-4. **Enum Schema**
- ```json
- {
- "type": "string",
- "title": "Display Name",
- "description": "Description text",
- "enum": ["option1", "option2", "option3"],
- "enumNames": ["Option 1", "Option 2", "Option 3"]
- }
- ```
-
-Clients can use this schema to:
-
-1. Generate appropriate input forms
-2. Validate user input before sending
-3. Provide better guidance to users
-
-Note that complex nested structures, arrays of objects, and other advanced JSON Schema features are intentionally not supported to simplify client implementation.
-
-### Out-of-Band Mode Parameters
-
-For `oob` mode elicitation, the `mode` parameter **MUST** be set to `"oob"` and `elicitationId` **MUST** be provided.
-
-Request parameters specific to `oob` mode are:
-
-| Name | Type | Description |
-| --------------- | ------ | ----------------------------------------- |
-| `url` | string | The URL that the user should navigate to. |
-| `elicitationId` | string | A unique identifier for the elicitation. |
-
-Parameters **MUST NOT** include:
-
-- `requestedSchema` - Only used for form mode
-- Any URLs in the `message` field; URLs must only appear in the `url` field
-
-```json
-{
- "mode": "oob",
- "elicitationId": "550e8400-e29b-41d4-a716-446655440000",
- "url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
- "message": "Authorization is required to access your Example Co files."
-}
-```
-
-## Progress Tracking
-
-The client **MAY** choose to request progress updates from the server. This is particularly useful in out-of-band mode, because the client is not involved in the interaction.
-Elicitation leverages MCP's [Progress utility](/specification/draft/basic/utilities/progress) to track the progress of the interaction.
-
-The client **MAY** send a `elicitation/track` request to the server to request progress updates.
-
-The client **MUST** include an `elicitationId` in the request to identify which elicitation to send progress updates for. The server **MUST** ignore any `elicitation/track` requests containing an `elicitationId` that is not known or does not belong to the client.
-
-The client **MUST** include a `progressToken` in the request. How that progress token is generated is left to the client implementation.
-
-The server **MAY** send a `notifications/progress` notification to the client with the progress token and the progress status.
-
-The server **SHOULD** send a `elicitation/track` response to the client once the elicitation is complete.=
## 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 out-of-band elicitation modes.
```json
{
@@ -594,6 +529,9 @@ Servers should handle each state appropriately:
- **Decline**: Handle explicit rejection (e.g., offer alternatives)
- **Cancel**: Handle dismissal (e.g., prompt again later)
+## Implementation Considerations
+
+
## Security Considerations
1. Clients **MUST** provide clear indication of which server is requesting information
From 155e02bb6dda2045b95e3557bb7cd5261b16212d Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Mon, 30 Jun 2025 16:41:12 -0700
Subject: [PATCH 06/62] Implementation Considerations section
---
.../draft/client/elicitation.mdx | 120 ++++++++++++++++--
1 file changed, 107 insertions(+), 13 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 087eac64a..761b37de2 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -76,12 +76,12 @@ To request information from a user, servers send an `elicitation/create` request
All elicitation requests **MUST** include the following parameters:
-| Name | Type | Options | Description |
-| --------- | ------ | ----------------- | ------------------------------------------------------------------ |
+| Name | Type | Options | Description |
+| --------- | ------ | ------------- | ------------------------------------------------------------------ |
| `mode` | string | `form`, `oob` | The mode of the elicitation. |
-| `message` | string | | A human-readable message explaining why the interaction is needed. |
+| `message` | string | | A human-readable message explaining why the interaction is needed. |
- The `mode` parameter specifies the type of elicitation:
+The `mode` parameter specifies the type of elicitation:
- `"form"`: In-band structured data collection with optional schema validation. Data is exposed to the client.
- `"oob"`: Out-of-band interaction via URL navigation. Data is **not** exposed to the client.
@@ -96,7 +96,6 @@ Form elicitation requests **MUST** specify `mode: "form"` and include these para
| ----------------- | ------ | -------------------------------------------------------------- |
| `requestedSchema` | object | A JSON Schema defining the structure of the expected response. |
-
#### Request Schema
The `requestedSchema` parameter allows servers to define the structure of the expected
@@ -273,10 +272,6 @@ Out-of-band elicitation requests **MUST** specify `mode: "oob"` and include thes
The `url` parameter **MUST** contain a valid URL. The `message` parameter **MUST NOT** contain a URL.
-
-In most cases, implementing out-of-band elicitation requires that the server be stateful: it must keep track of some state about the user (authorized/not authorized, paid/not paid, etc).
-
-
#### Example: Request Sensitive Data
This example shows an out-of-band elicitation request directing the user to a secure URL where they can provide sensitive information (an API key, for example).
@@ -314,7 +309,6 @@ The response with `action: "accept"` indicates that the user has consented to th
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, unless the client requests progress updates.
-
### Progress Tracking
The client **MAY** request progress updates from the server by sending an `elicitation/track` request with a [progress token](/specification/draft/basic/utilities/progress#progress-token). This is particularly useful in out-of-band mode, because the client is not involved in the interaction.
@@ -485,9 +479,6 @@ sequenceDiagram
Client->>Server: Retry tools/call (optional)
```
-
-
-
## Response Actions
Elicitation responses use a three-action model to clearly distinguish between different user actions. These actions apply to both form and out-of-band elicitation modes.
@@ -531,6 +522,109 @@ Servers should handle each state appropriately:
## Implementation Considerations
+### Statefulness Requirements
+
+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 elicitation)
+- Authentication status for protected resources (e.g., API keys or OAuth via out-of-band elicitation)
+- Progress of multi-step workflows (e.g., a payment flow)
+
+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
+- User identification **MUST** be derived from authenticated tokens
+- State storage **MUST** be protected against unauthorized access
+
+
+ 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.
+
+
+### Out-of-Band Elicitation for Sensitive Data
+
+For servers that interact with APIs requiring sensitive credentials (e.g. LLM APIs), out-of-band elicitation provides a secure mechanism for collecting API keys without exposing them to the MCP client or host application.
+
+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 MCP client or any intermediate MCP servers, reducing the risk of exposure through client-side logging or other means.
+
+### Out-of-Band Elicitation for OAuth Flows
+
+Out-of-band elicitation enables a pattern where MCP servers act as OAuth clients to third-party resource servers. This "downstream authorization" is distinct from [MCP authorization](../basic/authorization) between clients and servers.
+
+#### Understanding the Distinction
+
+- **MCP Authorization**: Required OAuth flow between the MCP client and MCP server (covered in the [authorization specification](../basic/authorization))
+- **Downstream Authorization**: Optional OAuth flow between the MCP server and a third-party resource server, initiated via out-of-band elicitation
+
+In downstream authorization, the server acts as both:
+
+- An OAuth 2.1 resource server (to the MCP client)
+- An OAuth client (to the third-party resource server)
+
+The access token used by the client to communicate with the server does not change as a result of downstream authorization, because the client is intentionally excluded from the third-party OAuth flow. This separation is crucial to maintain the proper security boundary between the client and the server.
+
+
+ For more background, read 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 downstream authorization via out-of-band elicitation:
+
+1. The MCP server generates an authorization URL, acting as an OAuth client to the third-party service
+2. The server creates an out-of-band 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
+
+```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 (which user this auth flow is for)
+ Server->>Client: ElicitationRequired error (mode: "oob", url: "example.com/authorize?...")
+ 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
+ Client-->>Server: elicitation/track request (optional)
+ 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
+ Note over Server: Confirm: elicitation matches user session Confirm: user is logged into MCP Server or MCP AS
+ Server->>3AS: Exchange authorization code for OAuth tokens
+ 3AS->>Server: Grants tokens
+ Note over Server: Bind tokens to MCP user identity
+ Server-->>Client: elicitation/track response (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.
## Security Considerations
From 99ffabc681848723eebe29d5617eabf2eb8d3e6b Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Mon, 30 Jun 2025 16:54:40 -0700
Subject: [PATCH 07/62] Cleanup
---
.../draft/client/elicitation.mdx | 27 ++++++++-----------
1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 761b37de2..38f1198d1 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -633,6 +633,7 @@ This pattern maintains clear security boundaries while enabling rich integration
3. Clients **SHOULD** allow users to reject elicitation requests at any time
4. Clients **SHOULD** implement rate limiting
5. Clients **SHOULD** present elicitation requests in a way that makes it clear what information is being requested and why
+6. Servers **MUST** bind elicitation requests to the user's identity
### URL Safety
@@ -664,21 +665,18 @@ Non-normative examples:
#### Server-Side Request Forgery (SSRF)
-Since clients open URLs provided by servers, they **MUST** implement SSRF protection, including:
+Since clients facilitate the opening of URLs provided by servers, they **MUST** implement SSRF protections, including:
-- Block requests to internal IP ranges (e.g., 127.0.0.1, 10.0.0.0/8, etc.)
-- Require the `https://` scheme for all out-of-band URLs (no HTTP, file://, etc.)
-- Clearly render or distinguish Unicode characters (e.g. punycode URLs) to avoid "look-alike" misdirections
-- Clearly communicate the destination server and target URL to the user when asking for consent
+- Requiring the `https://` scheme for all out-of-band URLs (no HTTP, `file://`, etc.)
+- Blocking requests to internal IP ranges (e.g., `127.0.0.1`, `10.0.0.0/8`, etc.)
+- Clearly rendering or distinguishing Unicode characters (e.g. punycode URLs) to avoid "look-alike" misdirections
+- Clearly communicating the destination server and target URL to the user when asking for consent
-#### Phishing
+Further recommendations can be found in the OWASP [SSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html).
-One use of out-of-band elicitation is to perform OAuth flows where the server acts as an
-OAuth client of another resource server. In this case, the server generates an
-authorization URL to the third-party resource server and passes it to the client in the
-form of an `oob` elicitation request.
+#### Phishing
-Without proper mitigation, the following phishing attack is possible:
+Out-of-band 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
@@ -688,8 +686,5 @@ Without proper mitigation, the following phishing attack is possible:
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** check the identity of the user (step 6 in the
-above example), and confirm that the user who is completing the authorization is the same
-user who initiated the elicitation request. Typically this is done by
-leveraging the [MCP authorization server](/specification/draft/basic/authorization) to
-identify the user, through a session cookie or equivalent in the browser.
+To prevent this attack, the server **MUST** check the identity of the user (step 6 in the above example), and confirm that the user who is completing the authorization is the same user who initiated the elicitation request.
+Typically this is done by leveraging the [MCP authorization server](/specification/draft/basic/authorization) to identify the user, through a session cookie or equivalent in the browser.
From 57430b11c9c9ad4ad14e30a8782332510895bea3 Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Tue, 1 Jul 2025 09:14:40 -0700
Subject: [PATCH 08/62] Additional clarification on how OOBE is distinct from
MCP auth
---
.../draft/client/elicitation.mdx | 38 +++++++++++++++++--
1 file changed, 34 insertions(+), 4 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 38f1198d1..d99d2aa5b 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -263,6 +263,15 @@ Out-of-band elicitation enables servers to direct users to external URLs for int
must not pass through the MCP client. This is essential for auth flows, payment
processing, and other sensitive or secure operations.
+
+ **Important**: Out-of-band elicitation is *not* for re-authorizing the MCP
+ client's access to the MCP server (that is covered by [MCP
+ authorization](../basic/authorization)). It's specifically for scenarios where
+ the MCP server needs to obtain sensitive information or authorization for
+ third-party services on behalf of the user. The MCP client's authorization
+ (bearer) token remains unchanged throughout this process.
+
+
Out-of-band elicitation requests **MUST** specify `mode: "oob"` and include these parameters:
| Name | Type | Description |
@@ -522,7 +531,7 @@ Servers should handle each state appropriately:
## Implementation Considerations
-### Statefulness Requirements
+### Statefulness
Most practical uses of elicitation require that the server maintain state about users:
@@ -558,7 +567,16 @@ This approach ensures that sensitive credentials never pass through the MCP clie
### Out-of-Band Elicitation for OAuth Flows
-Out-of-band elicitation enables a pattern where MCP servers act as OAuth clients to third-party resource servers. This "downstream authorization" is distinct from [MCP authorization](../basic/authorization) between clients and servers.
+Out-of-band elicitation enables a pattern where MCP servers act as OAuth clients to third-party resource servers.
+The "downstream authorization" enabled by out-of-band elicitation is fundamentally separate from [MCP authorization](../basic/authorization).
+
+
+ This distinction is critical to understand. Out-of-band elicitation is *not*
+ about authorizing (or re-authorizing) the MCP client to access the MCP server.
+ It *can* be used to enable the MCP server to access third-party resources or
+ APIs on behalf of the user, without exposing sensitive credentials or tokens
+ to the MCP client.
+
#### Understanding the Distinction
@@ -567,10 +585,22 @@ Out-of-band elicitation enables a pattern where MCP servers act as OAuth clients
In downstream authorization, the server acts as both:
-- An OAuth 2.1 resource server (to the MCP client)
+- An OAuth resource server (to the MCP client)
- An OAuth client (to the third-party resource server)
-The access token used by the client to communicate with the server does not change as a result of downstream authorization, because the client is intentionally excluded from the third-party OAuth flow. This separation is crucial to maintain the proper security boundary between the client and the server.
+Consider this hypothetical scenario:
+
+- Claude Desktop (the MCP client) connects to Bob's Productivity Server (an HTTPS MCP server)
+- Bob's Productivity Server integrates with Dropbox and Google APIs
+- When Claude calls a tool that requires Dropbox access, the MCP server needs Dropbox credentials
+
+The critical security requirements are:
+
+1. **The Dropbox token MUST NOT transit through Claude Desktop**: The client should never see third-party credentials
+2. **The MCP server MUST NOT use its Claude access token for Dropbox**: 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
+
+The tokens from these flows are never mixed or passed through. The MCP client's token is for the MCP server only, and the third-party tokens never leave the MCP server.
For more background, read the [token passthrough
From bf8ee420f42e15e079bd2d6cbc3f4e08da09c5d5 Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Tue, 1 Jul 2025 09:23:43 -0700
Subject: [PATCH 09/62] Fix schema nits
---
schema/draft/schema.json | 6 +++---
schema/draft/schema.ts | 6 ++----
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/schema/draft/schema.json b/schema/draft/schema.json
index e4398fe3c..fae1ee512 100644
--- a/schema/draft/schema.json
+++ b/schema/draft/schema.json
@@ -835,11 +835,11 @@
},
"mode": {
"const": "form",
- "description": "The mode of elicitation.",
+ "description": "The elicitation mode.",
"type": "string"
},
"requestedSchema": {
- "description": "A restricted subset of JSON Schema.\nOnly top-level properties are allowed, without nesting.\n\nRequired when mode is \"form\" or unspecified.",
+ "description": "A restricted subset of JSON Schema.\nOnly top-level properties are allowed, without nesting.",
"properties": {
"properties": {
"additionalProperties": {
@@ -1595,7 +1595,7 @@
},
"mode": {
"const": "oob",
- "description": "The mode of elicitation.",
+ "description": "The elicitation mode.",
"type": "string"
},
"url": {
diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts
index 28f07ab6f..56011b383 100644
--- a/schema/draft/schema.ts
+++ b/schema/draft/schema.ts
@@ -1321,15 +1321,13 @@ export interface RootsListChangedNotification extends Notification {
export interface FormElicitRequestParams extends ElicitRequestParams {
/**
- * The mode of elicitation.
+ * The elicitation mode.
*/
mode: "form";
/**
* A restricted subset of JSON Schema.
* Only top-level properties are allowed, without nesting.
- *
- * Required when mode is "form" or unspecified.
*/
requestedSchema?: {
type: "object";
@@ -1342,7 +1340,7 @@ export interface FormElicitRequestParams extends ElicitRequestParams {
export interface OutOfBandElicitRequestParams extends ElicitRequestParams {
/**
- * The mode of elicitation.
+ * The elicitation mode.
*/
mode: "oob";
From fbd52681babf35a0cc677c73273073937b3cd11a Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Tue, 1 Jul 2025 09:40:13 -0700
Subject: [PATCH 10/62] Clean up nits
---
.../draft/client/elicitation.mdx | 30 +++++++------------
1 file changed, 11 insertions(+), 19 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index d99d2aa5b..1f431a674 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -20,7 +20,7 @@ necessary information dynamically.
Elicitation supports two modes:
- **Form mode** (in-band): Servers can request structured data from users with optional JSON schemas to validate responses
-- **Out-of-band mode**: Servers can direct users to external URLs for interactions that must _not_ pass through the MCP client, such as OAuth authorization flows
+- **Out-of-band mode**: Servers can direct users to external URLs for sensitive nteractions that must _not_ pass through the MCP client
## User Interaction Model
@@ -36,8 +36,8 @@ model.
For trust & safety and security:
- Servers **MUST NOT** use form mode elicitation to request sensitive information
-- Servers **MUST** use out-of-band mode for auth flows and other security-sensitive interactions
-- URLs **MUST NOT** appear in any field of an elicitation request other than the `url` field for out-of-band mode
+- Servers **MUST** use out-of-band 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 out-of-band mode request
Applications **SHOULD**:
@@ -96,7 +96,7 @@ Form elicitation requests **MUST** specify `mode: "form"` and include these para
| ----------------- | ------ | -------------------------------------------------------------- |
| `requestedSchema` | object | A JSON Schema defining the structure of the expected response. |
-#### Request Schema
+#### Requested Schema
The `requestedSchema` parameter allows servers to define the structure of the expected
response using a restricted subset of JSON Schema.
@@ -259,17 +259,11 @@ Note that complex nested structures, arrays of objects, and other advanced JSON
### Out-of-Band Elicitation Requests
-Out-of-band elicitation enables servers to direct users to external URLs for interactions that
-must not pass through the MCP client. This is essential for auth flows, payment
-processing, and other sensitive or secure operations.
+Out-of-band elicitation enables servers to direct users to external URLs for interactions that must not pass through the MCP client. This is essential for auth flows, payment processing, and other sensitive or secure operations.
- **Important**: Out-of-band elicitation is *not* for re-authorizing the MCP
- client's access to the MCP server (that is covered by [MCP
- authorization](../basic/authorization)). It's specifically for scenarios where
- the MCP server needs to obtain sensitive information or authorization for
- third-party services on behalf of the user. The MCP client's authorization
- (bearer) token remains unchanged throughout this process.
+ **Important**: Out-of-band elicitation is *not* for re-authorizing the MCP client's access to the MCP server (that is covered by [MCP authorization](../basic/authorization)).
+ It's specifically for scenarios where the MCP server needs to obtain sensitive information, or authorization for third-party services on behalf of the user. The MCP client's authorization (bearer) token remains unchanged throughout this process.
Out-of-band elicitation requests **MUST** specify `mode: "oob"` and include these parameters:
@@ -284,7 +278,7 @@ The `url` parameter **MUST** contain a valid URL. The `message` parameter **MUST
#### Example: Request Sensitive Data
This example shows an out-of-band 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.
+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:**
@@ -344,6 +338,7 @@ The server **SHOULD** send a `elicitation/track` response to the client once the
"progressToken": "abc123"
},
"elicitationId": "550e8400-e29b-41d4-a716-446655440000"
+ }
}
```
@@ -375,12 +370,9 @@ The server **SHOULD** send a `elicitation/track` response to the client once the
### Elicitation Required Error
-When another request cannot be processed until an elicitation is completed, the server **SHOULD**
-return an [ElicitationRequired error](/docs/concepts/architecture#error-handling) (code `-32604`) to indicate to
-the client that an elicitation is required.
+When another request cannot be processed until an elicitation is completed, the server **SHOULD** return an [ElicitationRequired error](/docs/concepts/architecture#error-handling) (code `-32604`) to indicate to the client that an elicitation is required.
-The error **MUST** include a list of elicitations that are required to complete before the original
-can be retried.
+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 out-of-band mode elicitations and have an `elicitationId` property.
Servers that want elicit data from the user via form mode **SHOULD** make a separate elicitation request for each form mode elicitation.
From dc4fc3bd0933a1dbae52874668a28d5081bd609f Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Tue, 1 Jul 2025 09:51:52 -0700
Subject: [PATCH 11/62] More nit cleanup
---
.../draft/client/elicitation.mdx | 34 +++++++------------
1 file changed, 13 insertions(+), 21 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 1f431a674..1f88ecea7 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -528,8 +528,7 @@ Servers should handle each state appropriately:
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 elicitation)
-- Authentication status for protected resources (e.g., API keys or OAuth via out-of-band elicitation)
-- Progress of multi-step workflows (e.g., a payment flow)
+- Status of resource access (e.g., API keys or a payment flow via out-of-band 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:
@@ -538,9 +537,7 @@ Servers implementing elicitation **MUST** securely associate this state with ind
- State storage **MUST** be protected against unauthorized access
- 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.
+ 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.
### Out-of-Band Elicitation for Sensitive Data
@@ -555,7 +552,7 @@ In this pattern:
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 MCP client or any intermediate MCP servers, reducing the risk of exposure through client-side logging or other means.
+This approach ensures that sensitive credentials never pass through the MCP client or any intermediate MCP servers, reducing the risk of exposure through client-side logging or other attack vectors.
### Out-of-Band Elicitation for OAuth Flows
@@ -563,11 +560,8 @@ Out-of-band elicitation enables a pattern where MCP servers act as OAuth clients
The "downstream authorization" enabled by out-of-band elicitation is fundamentally separate from [MCP authorization](../basic/authorization).
- This distinction is critical to understand. Out-of-band elicitation is *not*
- about authorizing (or re-authorizing) the MCP client to access the MCP server.
- It *can* be used to enable the MCP server to access third-party resources or
- APIs on behalf of the user, without exposing sensitive credentials or tokens
- to the MCP client.
+ This distinction is critical to understand. Out-of-band elicitation is *not* about authorizing (or re-authorizing) the MCP client to access the MCP server.
+ It *can* be used to enable the MCP server to access third-party resources or APIs on behalf of the user, without exposing sensitive credentials or tokens to the MCP client.
#### Understanding the Distinction
@@ -588,17 +582,14 @@ Consider this hypothetical scenario:
The critical security requirements are:
-1. **The Dropbox token MUST NOT transit through Claude Desktop**: The client should never see third-party credentials
+1. **The Dropbox token MUST NOT transit through Claude Desktop**: The client must never see third-party credentials
2. **The MCP server MUST NOT use its Claude access token for Dropbox**: 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
The tokens from these flows are never mixed or passed through. The MCP client's token is for the MCP server only, and the third-party tokens never leave the MCP server.
- For more background, read 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.
+ For more background, read 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
@@ -657,13 +648,14 @@ This pattern maintains clear security boundaries while enabling rich integration
5. Clients **SHOULD** present elicitation requests in a way that makes it clear what information is being requested and why
6. Servers **MUST** bind elicitation requests to the user's identity
-### URL Safety
+### Safe URL Handling
-Clients implementing out-of-band elicitation **MUST** implement the safety checks for URLs described below. These strict controls, including obtaining consent from the user, help prevent users from unknowingly clicking malicious links.
+Clients implementing out-of-band elicitation **MUST** handle URLs carefully to prevent users from unknowingly clicking malicious links.
-URLs **MUST NOT** be present in any message or schema fields as part of an out-of-band elicitation request EXCEPT for the `url` field.
+1. Servers **MUST NOT** include URLs in any message or schema fields as part of a form elicitation request.
+2. Servers **MUST NOT** include URLs in any message or schema fields as part of an out-of-band elicitation request, except for the `url` field.
-URLs **MUST NOT** be present in any message or schema fields as part of a form elicitation request.
+These requirements ensure that client implementations have clear rules about when to present a URL to the user, so that other rules about user consent and SSRF protection (below) can be consistently applied.
### Identifying the User
@@ -683,7 +675,7 @@ Non-normative examples:
### Out-of-Band Mode Security
-1. Clients **MUST NOT** open a user agent (e.g. browser) without explicit consent from the user
+Clients **MUST NOT** open a user agent (e.g. browser) without explicit consent from the user
#### Server-Side Request Forgery (SSRF)
From 4095f635a46e1955fa19629da8da2cb91ebd1969 Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Tue, 1 Jul 2025 10:13:40 -0700
Subject: [PATCH 12/62] Update changelog
---
docs/specification/draft/changelog.mdx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/specification/draft/changelog.mdx b/docs/specification/draft/changelog.mdx
index a7f9d83a2..912393520 100644
--- a/docs/specification/draft/changelog.mdx
+++ b/docs/specification/draft/changelog.mdx
@@ -9,8 +9,8 @@ the previous revision, [2025-06-18](/specification/2025-06-18).
## Major changes
-1. Added support for [out-of-band elicitation](/specification/draft/client/elicitation#out-of-band-mode)
- (PR TBD)
+1. Added support for [out-of-band elicitation](/specification/draft/client/elicitation#out-of-band-elicitation-requests) requests
+ (PR [#887](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/887))
## Other schema changes
From de5491c234d83688c2a9a6dc0d281066cd69fddc Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Tue, 1 Jul 2025 16:17:41 -0700
Subject: [PATCH 13/62] phishing applies outside of oauth
---
docs/specification/draft/client/elicitation.mdx | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 1f88ecea7..83073a5f6 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -690,7 +690,11 @@ Further recommendations can be found in the OWASP [SSRF Prevention Cheat Sheet](
#### Phishing
-Out-of-band 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:
+Out-of-band 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](/specification/draft/basic/authorization) to identify the user, through a session cookie or equivalent in the browser.
+
+For example, out-of-band 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
@@ -701,4 +705,3 @@ Out-of-band elicitation may be used to perform OAuth flows where the server acts
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** check the identity of the user (step 6 in the above example), and confirm that the user who is completing the authorization is the same user who initiated the elicitation request.
-Typically this is done by leveraging the [MCP authorization server](/specification/draft/basic/authorization) to identify the user, through a session cookie or equivalent in the browser.
From f587b909ea973955148e100b22bd40cce93c18e0 Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Tue, 1 Jul 2025 16:48:12 -0700
Subject: [PATCH 14/62] update schema request params
---
.../draft/client/elicitation.mdx | 24 +++++++---
schema/draft/schema.json | 44 +++----------------
schema/draft/schema.ts | 15 ++++---
3 files changed, 32 insertions(+), 51 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 83073a5f6..0c57617bf 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -262,8 +262,12 @@ Note that complex nested structures, arrays of objects, and other advanced JSON
Out-of-band elicitation enables servers to direct users to external URLs for interactions that must not pass through the MCP client. This is essential for auth flows, payment processing, and other sensitive or secure operations.
- **Important**: Out-of-band elicitation is *not* for re-authorizing the MCP client's access to the MCP server (that is covered by [MCP authorization](../basic/authorization)).
- It's specifically for scenarios where the MCP server needs to obtain sensitive information, or authorization for third-party services on behalf of the user. The MCP client's authorization (bearer) token remains unchanged throughout this process.
+ **Important**: Out-of-band elicitation is *not* for re-authorizing the MCP
+ client's access to the MCP server (that is covered by [MCP
+ authorization](../basic/authorization)). It's specifically for scenarios where
+ the MCP server needs to obtain sensitive information, or authorization for
+ third-party services on behalf of the user. The MCP client's authorization
+ (bearer) token remains unchanged throughout this process.
Out-of-band elicitation requests **MUST** specify `mode: "oob"` and include these parameters:
@@ -537,7 +541,9 @@ Servers implementing elicitation **MUST** securely associate this state with ind
- State storage **MUST** be protected against unauthorized access
- 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.
+ 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.
### Out-of-Band Elicitation for Sensitive Data
@@ -560,8 +566,11 @@ Out-of-band elicitation enables a pattern where MCP servers act as OAuth clients
The "downstream authorization" enabled by out-of-band elicitation is fundamentally separate from [MCP authorization](../basic/authorization).
- This distinction is critical to understand. Out-of-band elicitation is *not* about authorizing (or re-authorizing) the MCP client to access the MCP server.
- It *can* be used to enable the MCP server to access third-party resources or APIs on behalf of the user, without exposing sensitive credentials or tokens to the MCP client.
+ This distinction is critical to understand. Out-of-band elicitation is *not*
+ about authorizing (or re-authorizing) the MCP client to access the MCP server.
+ It *can* be used to enable the MCP server to access third-party resources or
+ APIs on behalf of the user, without exposing sensitive credentials or tokens
+ to the MCP client.
#### Understanding the Distinction
@@ -589,7 +598,10 @@ The critical security requirements are:
The tokens from these flows are never mixed or passed through. The MCP client's token is for the MCP server only, and the third-party tokens never leave the MCP server.
- For more background, read 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.
+ For more background, read 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
diff --git a/schema/draft/schema.json b/schema/draft/schema.json
index fae1ee512..b2776a249 100644
--- a/schema/draft/schema.json
+++ b/schema/draft/schema.json
@@ -632,7 +632,6 @@
"type": "object"
},
"ElicitRequestParams": {
- "additionalProperties": {},
"description": "The parameters for a request to elicit additional information from the user via the client.",
"properties": {
"_meta": {
@@ -1167,15 +1166,7 @@
"type": "string"
},
"params": {
- "allOf": [
- {
- "$ref": "#/definitions/RequestParamsMeta"
- },
- {
- "additionalProperties": {},
- "type": "object"
- }
- ]
+ "$ref": "#/definitions/RequestParams"
}
},
"required": [
@@ -1352,15 +1343,7 @@
"type": "string"
},
"params": {
- "allOf": [
- {
- "$ref": "#/definitions/RequestParamsMeta"
- },
- {
- "additionalProperties": {},
- "type": "object"
- }
- ]
+ "$ref": "#/definitions/RequestParams"
}
},
"required": [
@@ -1654,15 +1637,7 @@
"type": "string"
},
"params": {
- "allOf": [
- {
- "$ref": "#/definitions/RequestParamsMeta"
- },
- {
- "additionalProperties": {},
- "type": "object"
- }
- ]
+ "$ref": "#/definitions/RequestParams"
}
},
"required": [
@@ -1913,15 +1888,7 @@
"type": "string"
},
"params": {
- "allOf": [
- {
- "$ref": "#/definitions/RequestParamsMeta"
- },
- {
- "additionalProperties": {},
- "type": "object"
- }
- ]
+ "$ref": "#/definitions/RequestParams"
}
},
"required": [
@@ -1936,7 +1903,8 @@
"integer"
]
},
- "RequestParamsMeta": {
+ "RequestParams": {
+ "additionalProperties": {},
"properties": {
"_meta": {
"additionalProperties": {},
diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts
index 56011b383..b7458ef22 100644
--- a/schema/draft/schema.ts
+++ b/schema/draft/schema.ts
@@ -22,7 +22,7 @@ export type ProgressToken = string | number;
*/
export type Cursor = string;
-export interface RequestParamsMeta {
+export interface RequestParams {
/**
* See [specification/draft/basic/index#general-fields] for notes on _meta usage.
*/
@@ -33,13 +33,16 @@ export interface RequestParamsMeta {
progressToken?: ProgressToken;
[key: string]: unknown;
};
+
+ /**
+ * Allow any unknown parameters to be passed in.
+ */
+ [key: string]: unknown;
}
export interface Request {
method: string;
- params?: RequestParamsMeta & {
- [key: string]: unknown;
- };
+ params?: RequestParams;
}
export interface Notification {
@@ -1361,7 +1364,7 @@ export interface OutOfBandElicitRequestParams extends ElicitRequestParams {
/**
* The parameters for a request to elicit additional information from the user via the client.
*/
-export interface ElicitRequestParams extends RequestParamsMeta {
+export interface ElicitRequestParams extends RequestParams {
/**
* The mode of elicitation.
* - "form": In-band structured data collection with optional schema validation
@@ -1375,8 +1378,6 @@ export interface ElicitRequestParams extends RequestParamsMeta {
* For out-of-band mode: Explains why the interaction is needed.
*/
message: string;
-
- [key: string]: unknown;
}
/**
From a17686e4edb499abb22b168437aebb8fb02e3cae Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Tue, 1 Jul 2025 17:17:43 -0700
Subject: [PATCH 15/62] Update docs/specification/draft/client/elicitation.mdx
Co-authored-by: Geoff Goodman
---
docs/specification/draft/client/elicitation.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 0c57617bf..be6903626 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -20,7 +20,7 @@ necessary information dynamically.
Elicitation supports two modes:
- **Form mode** (in-band): Servers can request structured data from users with optional JSON schemas to validate responses
-- **Out-of-band mode**: Servers can direct users to external URLs for sensitive nteractions that must _not_ pass through the MCP client
+- **Out-of-band mode**: Servers can direct users to external URLs for sensitive interactions that must _not_ pass through the MCP client
## User Interaction Model
From 1ca1e58a7802a6bf9825adfdbbcaa61dac7eb00a Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Wed, 2 Jul 2025 07:12:42 -0700
Subject: [PATCH 16/62] More concise schema expr
---
schema/draft/schema.json | 95 ++++++++++++++++++++++------------------
schema/draft/schema.ts | 5 +--
2 files changed, 53 insertions(+), 47 deletions(-)
diff --git a/schema/draft/schema.json b/schema/draft/schema.json
index b2776a249..0857b5c83 100644
--- a/schema/draft/schema.json
+++ b/schema/draft/schema.json
@@ -218,59 +218,68 @@
"elicitation": {
"anyOf": [
{
- "properties": {
- "form": {
- "additionalProperties": true,
- "properties": {},
- "type": "object"
- },
- "oob": {
- "additionalProperties": true,
- "properties": {},
- "type": "object"
- }
- },
- "required": [
- "form"
- ],
- "type": "object"
- },
- {
- "properties": {
- "form": {
- "additionalProperties": true,
- "properties": {},
+ "allOf": [
+ {
+ "properties": {
+ "form": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ },
+ "oob": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ }
+ },
"type": "object"
},
- "oob": {
- "additionalProperties": true,
- "properties": {},
+ {
+ "properties": {
+ "form": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ }
+ },
+ "required": [
+ "form"
+ ],
"type": "object"
}
- },
- "required": [
- "oob"
- ],
- "type": "object"
+ ]
},
{
- "properties": {
- "form": {
- "additionalProperties": true,
- "properties": {},
+ "allOf": [
+ {
+ "properties": {
+ "form": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ },
+ "oob": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ }
+ },
"type": "object"
},
- "oob": {
- "additionalProperties": true,
- "properties": {},
+ {
+ "properties": {
+ "oob": {
+ "additionalProperties": true,
+ "properties": {},
+ "type": "object"
+ }
+ },
+ "required": [
+ "oob"
+ ],
"type": "object"
}
- },
- "required": [
- "form",
- "oob"
- ],
- "type": "object"
+ ]
}
],
"description": "Present if the client supports elicitation from the server."
diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts
index b7458ef22..9f706d49d 100644
--- a/schema/draft/schema.ts
+++ b/schema/draft/schema.ts
@@ -236,10 +236,7 @@ export interface ClientCapabilities {
/**
* Present if the client supports elicitation from the server.
*/
- elicitation?:
- | { form: object; oob?: object }
- | { form?: object; oob: object }
- | { form: object; oob: object };
+ elicitation?: { form?: object; oob?: object } & ({ form: object } | { oob: object });
}
/**
From b3a08b7ba723f9815ad4be52ef28502aea8b1c93 Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Wed, 2 Jul 2025 11:00:07 -0700
Subject: [PATCH 17/62] Update docs/specification/draft/client/elicitation.mdx
Co-authored-by: Josh Cunningham
---
docs/specification/draft/client/elicitation.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index be6903626..7b11e559e 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -576,7 +576,7 @@ The "downstream authorization" enabled by out-of-band elicitation is fundamental
#### Understanding the Distinction
- **MCP Authorization**: Required OAuth flow between the MCP client and MCP server (covered in the [authorization specification](../basic/authorization))
-- **Downstream Authorization**: Optional OAuth flow between the MCP server and a third-party resource server, initiated via out-of-band elicitation
+- **Downstream Authorization**: Optional authorization between the MCP server and a third-party resource server, initiated via out-of-band elicitation
In downstream authorization, the server acts as both:
From 44de9071074c61ebfe1fb42552c21dff17e94392 Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Wed, 2 Jul 2025 14:34:36 -0700
Subject: [PATCH 18/62] Change oob to url
---
docs/clients.mdx | 5 +-
docs/specification/draft/basic/lifecycle.mdx | 2 +-
docs/specification/draft/changelog.mdx | 2 +-
.../draft/client/elicitation.mdx | 88 +++++++--------
schema/draft/schema.json | 100 +++++++++---------
schema/draft/schema.ts | 16 +--
6 files changed, 108 insertions(+), 105 deletions(-)
diff --git a/docs/clients.mdx b/docs/clients.mdx
index eb5b5ee38..1d2158176 100644
--- a/docs/clients.mdx
+++ b/docs/clients.mdx
@@ -709,14 +709,17 @@ MooPoint is a web-based AI chat platform built for developers and advanced users
- Integration with history, variables, and collections for reuse and collaboration
### RecurseChat
-[RecurseChat](https://recurse.chat) is a powerful, fast, local-first chat client with MCP support. RecurseChat supports multiple AI providers including LLaMA.cpp, Ollama, and OpenAI, Anthropic.
+
+[RecurseChat](https://recurse.chat) is a powerful, fast, local-first chat client with MCP support. RecurseChat supports multiple AI providers including LLaMA.cpp, Ollama, and OpenAI, Anthropic.
**Key features:**
+
- Local AI: Support MCP with Ollama models.
- MCP Tools: Individual MCP server management. Easily visualize the connection states of MCP servers.
- MCP Import: Import configuration from Claude Desktop app or JSON
**Learn more:**
+
- [RecurseChat docs](https://recurse.chat/docs/features/mcp/)
### Slack MCP Client
diff --git a/docs/specification/draft/basic/lifecycle.mdx b/docs/specification/draft/basic/lifecycle.mdx
index 0dc25f084..0e5ac7508 100644
--- a/docs/specification/draft/basic/lifecycle.mdx
+++ b/docs/specification/draft/basic/lifecycle.mdx
@@ -66,7 +66,7 @@ The client **MUST** initiate this phase by sending an `initialize` request conta
"sampling": {},
"elicitation": {
"form": {},
- "oob": {}
+ "url": {}
}
},
"clientInfo": {
diff --git a/docs/specification/draft/changelog.mdx b/docs/specification/draft/changelog.mdx
index 912393520..9b62b0bbc 100644
--- a/docs/specification/draft/changelog.mdx
+++ b/docs/specification/draft/changelog.mdx
@@ -9,7 +9,7 @@ the previous revision, [2025-06-18](/specification/2025-06-18).
## Major changes
-1. Added support for [out-of-band elicitation](/specification/draft/client/elicitation#out-of-band-elicitation-requests) requests
+1. Added support for [url elicitation](/specification/draft/client/elicitation#url-elicitation-requests)
(PR [#887](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/887))
## Other schema changes
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 7b11e559e..1fd72455f 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -20,7 +20,7 @@ necessary information dynamically.
Elicitation supports two modes:
- **Form mode** (in-band): Servers can request structured data from users with optional JSON schemas to validate responses
-- **Out-of-band mode**: Servers can direct users to external URLs for sensitive interactions that must _not_ pass through the MCP client
+- **URL mode** (out-of-band): Servers can direct users to external URLs for sensitive interactions that must _not_ pass through the MCP client
## User Interaction Model
@@ -36,13 +36,13 @@ model.
For trust & safety and security:
- Servers **MUST NOT** use form mode elicitation to request sensitive information
-- Servers **MUST** use out-of-band 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 out-of-band mode request
+- 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**:
- Provide UI that makes it clear which server is requesting information
-- For out-of-band mode, clearly display the target domain/host before navigation
+- For url mode, clearly display the target domain/host before navigation
- Allow users to review and modify their responses before sending
- Respect user privacy and provide clear reject and cancel options
@@ -58,13 +58,13 @@ Clients that support elicitation **MUST** declare the `elicitation` capability d
"capabilities": {
"elicitation": {
"form": {},
- "oob": {}
+ "url": {}
}
}
}
```
-Clients declaring the `elicitation` capability **MUST** support at least one mode (`form` or `oob`).
+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.
@@ -78,13 +78,13 @@ All elicitation requests **MUST** include the following parameters:
| Name | Type | Options | Description |
| --------- | ------ | ------------- | ------------------------------------------------------------------ |
-| `mode` | string | `form`, `oob` | The mode of the elicitation. |
+| `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.
-- `"oob"`: Out-of-band interaction via URL navigation. Data is **not** exposed to the client.
+- `"url"`: Out-of-band interaction via URL navigation. Data is **not** exposed to the client.
### Form Elicitation Requests
@@ -257,20 +257,20 @@ Note that complex nested structures, arrays of objects, and other advanced JSON
}
```
-### Out-of-Band Elicitation Requests
+### URL Elicitation Requests
-Out-of-band elicitation enables servers to direct users to external URLs for interactions that must not pass through the MCP client. This is essential for auth flows, payment processing, and other sensitive or secure operations.
+URL 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**: Out-of-band elicitation is *not* for re-authorizing the MCP
- client's access to the MCP server (that is covered by [MCP
+ **Important**: URL elicitation is *not* for re-authorizing the MCP client's
+ access to the MCP server (that is covered by [MCP
authorization](../basic/authorization)). It's specifically for scenarios where
the MCP server needs to obtain sensitive information, or authorization for
third-party services on behalf of the user. The MCP client's authorization
(bearer) token remains unchanged throughout this process.
-Out-of-band elicitation requests **MUST** specify `mode: "oob"` and include these parameters:
+URL elicitation requests **MUST** specify `mode: "url"` and include these parameters:
| Name | Type | Description |
| --------------- | ------ | ----------------------------------------- |
@@ -281,7 +281,7 @@ The `url` parameter **MUST** contain a valid URL. The `message` parameter **MUST
#### Example: Request Sensitive Data
-This example shows an out-of-band elicitation request directing the user to a secure URL where they can provide sensitive information (an API key, for example).
+This example shows a url 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:**
@@ -292,7 +292,7 @@ The same request could direct the user into an OAuth authorization flow, or a pa
"id": 3,
"method": "elicitation/create",
"params": {
- "mode": "oob",
+ "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."
@@ -318,7 +318,7 @@ of band and the client is not aware of the outcome, unless the client requests p
### Progress Tracking
-The client **MAY** request progress updates from the server by sending an `elicitation/track` request with a [progress token](/specification/draft/basic/utilities/progress#progress-token). This is particularly useful in out-of-band mode, because the client is not involved in the interaction.
+The client **MAY** request progress updates from the server by sending an `elicitation/track` request with a [progress token](/specification/draft/basic/utilities/progress#progress-token). This is particularly useful in url mode, because the client is not involved in the interaction.
The client **MUST** include an `elicitationId` in the request to identify which elicitation to send progress updates for. The client **SHOULD** include a `progressToken` in the request's `_meta` field.
@@ -378,7 +378,7 @@ When another request cannot be processed until an elicitation is completed, the
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 out-of-band mode elicitations and have an `elicitationId` property.
+Any elicitations returned in the error **MUST** be url mode elicitations and have an `elicitationId` property.
Servers that want elicit data from the user via form mode **SHOULD** make a separate elicitation request for each form mode elicitation.
**Error Response:**
@@ -393,7 +393,7 @@ Servers that want elicit data from the user via form mode **SHOULD** make a sepa
"data": {
"elicitations": [
{
- "mode": "oob",
+ "mode": "url",
"elicitionId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
"message": "Authorization is required to access your Example Co files."
@@ -426,7 +426,7 @@ sequenceDiagram
Note over Server: Continue processing with new information
```
-### Out-of-Band Mode Flow
+### URL Mode Flow
```mermaid
sequenceDiagram
@@ -436,7 +436,7 @@ sequenceDiagram
participant Server
Note over Server: Server initiates elicitation
- Server->>Client: elicitation/create (mode: oob)
+ Server->>Client: elicitation/create (mode: url)
Client->>User: Present consent to open URL
User-->>Client: Provide consent
@@ -453,7 +453,7 @@ sequenceDiagram
Note over Server: Continue processing with new information
```
-### Out-of-Band Mode With Elicitation Required Error Flow
+### URL Mode With Elicitation Required Error Flow
```mermaid
sequenceDiagram
@@ -486,7 +486,7 @@ sequenceDiagram
## Response Actions
-Elicitation responses use a three-action model to clearly distinguish between different user actions. These actions apply to both form and out-of-band elicitation modes.
+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
{
@@ -507,7 +507,7 @@ The three response actions are:
1. **Accept** (`action: "accept"`): User explicitly approved and submitted with data
- For form mode: The `content` field contains the submitted data matching the requested schema
- - For out-of-band mode: The `content` field is omitted
+ - For url mode: The `content` field is omitted
- Example: User clicked "Submit", "OK", "Confirm", etc.
2. **Reject** (`action: "reject"`): User explicitly rejected the request
@@ -532,7 +532,7 @@ Servers should handle each state appropriately:
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 elicitation)
-- Status of resource access (e.g., API keys or a payment flow via out-of-band elicitation)
+- Status of resource access (e.g., API keys or a payment flow via url 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:
@@ -546,9 +546,9 @@ Servers implementing elicitation **MUST** securely associate this state with ind
requirements while maintaining security best practices.
-### Out-of-Band Elicitation for Sensitive Data
+### URL Elicitation for Sensitive Data
-For servers that interact with APIs requiring sensitive credentials (e.g. LLM APIs), out-of-band elicitation provides a secure mechanism for collecting API keys without exposing them to the MCP client or host application.
+For servers that interact with APIs requiring sensitive credentials (e.g. LLM APIs), url elicitation provides a secure mechanism for collecting API keys without exposing them to the MCP client or host application.
In this pattern:
@@ -560,23 +560,23 @@ In this pattern:
This approach ensures that sensitive credentials never pass through the MCP client or any intermediate MCP servers, reducing the risk of exposure through client-side logging or other attack vectors.
-### Out-of-Band Elicitation for OAuth Flows
+### URL Elicitation for OAuth Flows
-Out-of-band elicitation enables a pattern where MCP servers act as OAuth clients to third-party resource servers.
-The "downstream authorization" enabled by out-of-band elicitation is fundamentally separate from [MCP authorization](../basic/authorization).
+URL elicitation enables a pattern where MCP servers act as OAuth clients to third-party resource servers.
+The "downstream authorization" enabled by url elicitation is fundamentally separate from [MCP authorization](../basic/authorization).
- This distinction is critical to understand. Out-of-band elicitation is *not*
- about authorizing (or re-authorizing) the MCP client to access the MCP server.
- It *can* be used to enable the MCP server to access third-party resources or
- APIs on behalf of the user, without exposing sensitive credentials or tokens
- to the MCP client.
+ This distinction is critical to understand. URL elicitation is *not* about
+ authorizing (or re-authorizing) the MCP client to access the MCP server. It
+ *can* be used to enable the MCP server to access third-party resources or APIs
+ on behalf of the user, without exposing sensitive credentials or tokens to the
+ MCP client.
#### Understanding the Distinction
- **MCP Authorization**: Required OAuth flow between the MCP client and MCP server (covered in the [authorization specification](../basic/authorization))
-- **Downstream Authorization**: Optional authorization between the MCP server and a third-party resource server, initiated via out-of-band elicitation
+- **Downstream Authorization**: Optional authorization between the MCP server and a third-party resource server, initiated via url elicitation
In downstream authorization, the server acts as both:
@@ -606,10 +606,10 @@ The tokens from these flows are never mixed or passed through. The MCP client's
#### Implementation Pattern
-When implementing downstream authorization via out-of-band elicitation:
+When implementing downstream authorization via url elicitation:
1. The MCP server generates an authorization URL, acting as an OAuth client to the third-party service
-2. The server creates an out-of-band elicitation request with this URL
+2. The server creates a url 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
@@ -627,7 +627,7 @@ sequenceDiagram
Client->>Server: tools/call
Note over Server: Needs 3rd-party authorization for user
Note over Server: Store state (which user this auth flow is for)
- Server->>Client: ElicitationRequired error (mode: "oob", url: "example.com/authorize?...")
+ Server->>Client: ElicitationRequired error (mode: "url", url: "example.com/authorize?...")
Note over Client: Client notes the tools/call request can be retried later
Client->>User: Present consent to open URL
User->>Client: Provide consent
@@ -662,10 +662,10 @@ This pattern maintains clear security boundaries while enabling rich integration
### Safe URL Handling
-Clients implementing out-of-band elicitation **MUST** handle URLs carefully to prevent users from unknowingly clicking malicious links.
+Clients implementing url elicitation **MUST** handle URLs carefully to prevent users from unknowingly clicking malicious links.
1. Servers **MUST NOT** include URLs in any message or schema fields as part of a form elicitation request.
-2. Servers **MUST NOT** include URLs in any message or schema fields as part of an out-of-band elicitation request, except for the `url` field.
+2. Servers **MUST NOT** include URLs in any message or schema fields as part of an url elicitation request, except for the `url` field.
These requirements ensure that client implementations have clear rules about when to present a URL to the user, so that other rules about user consent and SSRF protection (below) can be consistently applied.
@@ -685,7 +685,7 @@ Non-normative examples:
2. Clients **SHOULD** validate all responses against the provided schema
3. Servers **SHOULD** validate received data matches the requested schema
-### Out-of-Band Mode Security
+### URL Mode Security
Clients **MUST NOT** open a user agent (e.g. browser) without explicit consent from the user
@@ -693,7 +693,7 @@ Clients **MUST NOT** open a user agent (e.g. browser) without explicit consent f
Since clients facilitate the opening of URLs provided by servers, they **MUST** implement SSRF protections, including:
-- Requiring the `https://` scheme for all out-of-band URLs (no HTTP, `file://`, etc.)
+- Requiring the `https://` scheme for all url mode URLs (no HTTP, `file://`, etc.)
- Blocking requests to internal IP ranges (e.g., `127.0.0.1`, `10.0.0.0/8`, etc.)
- Clearly rendering or distinguishing Unicode characters (e.g. punycode URLs) to avoid "look-alike" misdirections
- Clearly communicating the destination server and target URL to the user when asking for consent
@@ -702,11 +702,11 @@ Further recommendations can be found in the OWASP [SSRF Prevention Cheat Sheet](
#### Phishing
-Out-of-band 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.
+URL 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](/specification/draft/basic/authorization) to identify the user, through a session cookie or equivalent in the browser.
-For example, out-of-band 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:
+For example, url 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
diff --git a/schema/draft/schema.json b/schema/draft/schema.json
index 0857b5c83..d8218c287 100644
--- a/schema/draft/schema.json
+++ b/schema/draft/schema.json
@@ -226,7 +226,7 @@
"properties": {},
"type": "object"
},
- "oob": {
+ "url": {
"additionalProperties": true,
"properties": {},
"type": "object"
@@ -258,7 +258,7 @@
"properties": {},
"type": "object"
},
- "oob": {
+ "url": {
"additionalProperties": true,
"properties": {},
"type": "object"
@@ -268,14 +268,14 @@
},
{
"properties": {
- "oob": {
+ "url": {
"additionalProperties": true,
"properties": {},
"type": "object"
}
},
"required": [
- "oob"
+ "url"
],
"type": "object"
}
@@ -626,7 +626,7 @@
"params": {
"anyOf": [
{
- "$ref": "#/definitions/OutOfBandElicitRequestParams"
+ "$ref": "#/definitions/URLElicitRequestParams"
},
{
"$ref": "#/definitions/FormElicitRequestParams"
@@ -655,14 +655,14 @@
"type": "object"
},
"message": {
- "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor out-of-band mode: Explains why the interaction is needed.",
+ "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor url mode: Explains why the interaction is needed.",
"type": "string"
},
"mode": {
- "description": "The mode of elicitation.\n- \"form\": In-band structured data collection with optional schema validation\n- \"oob\": Out-of-band interaction via URL navigation",
+ "description": "The mode of elicitation.\n- \"form\": In-band structured data collection with optional schema validation\n- \"url\": Out-of-band interaction via URL navigation",
"enum": [
"form",
- "oob"
+ "url"
],
"type": "string"
}
@@ -721,7 +721,7 @@
"properties": {
"elicitations": {
"items": {
- "$ref": "#/definitions/OutOfBandElicitRequestParams"
+ "$ref": "#/definitions/URLElicitRequestParams"
},
"type": "array"
}
@@ -838,7 +838,7 @@
"type": "object"
},
"message": {
- "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor out-of-band mode: Explains why the interaction is needed.",
+ "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor url mode: Explains why the interaction is needed.",
"type": "string"
},
"mode": {
@@ -1564,46 +1564,6 @@
],
"type": "object"
},
- "OutOfBandElicitRequestParams": {
- "properties": {
- "_meta": {
- "additionalProperties": {},
- "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
- "properties": {
- "progressToken": {
- "$ref": "#/definitions/ProgressToken",
- "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
- }
- },
- "type": "object"
- },
- "elicitationId": {
- "description": "The ID of the elicitation, which must be unique within the context of the server.\nThe client MUST treat this ID as an opaque value.",
- "type": "string"
- },
- "message": {
- "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor out-of-band mode: Explains why the interaction is needed.",
- "type": "string"
- },
- "mode": {
- "const": "oob",
- "description": "The elicitation mode.",
- "type": "string"
- },
- "url": {
- "description": "The URL that the user should navigate to.",
- "format": "uri",
- "type": "string"
- }
- },
- "required": [
- "elicitationId",
- "message",
- "mode",
- "url"
- ],
- "type": "object"
- },
"PaginatedRequest": {
"properties": {
"method": {
@@ -2658,6 +2618,46 @@
],
"type": "object"
},
+ "URLElicitRequestParams": {
+ "properties": {
+ "_meta": {
+ "additionalProperties": {},
+ "description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
+ "properties": {
+ "progressToken": {
+ "$ref": "#/definitions/ProgressToken",
+ "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications."
+ }
+ },
+ "type": "object"
+ },
+ "elicitationId": {
+ "description": "The ID of the elicitation, which must be unique within the context of the server.\nThe client MUST treat this ID as an opaque value.",
+ "type": "string"
+ },
+ "message": {
+ "description": "The message to present to the user.\nFor form mode: Describes what information is being requested.\nFor url mode: Explains why the interaction is needed.",
+ "type": "string"
+ },
+ "mode": {
+ "const": "url",
+ "description": "The elicitation mode.",
+ "type": "string"
+ },
+ "url": {
+ "description": "The URL that the user should navigate to.",
+ "format": "uri",
+ "type": "string"
+ }
+ },
+ "required": [
+ "elicitationId",
+ "message",
+ "mode",
+ "url"
+ ],
+ "type": "object"
+ },
"UnsubscribeRequest": {
"description": "Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request.",
"properties": {
diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts
index 9f706d49d..6e37443e3 100644
--- a/schema/draft/schema.ts
+++ b/schema/draft/schema.ts
@@ -131,7 +131,7 @@ export interface ElicitationRequiredError extends JSONRPCError {
code: typeof ELICITATION_REQUIRED;
message: string;
data: {
- elicitations: OutOfBandElicitRequestParams[];
+ elicitations: URLElicitRequestParams[];
[key: string]: unknown;
};
};
@@ -236,7 +236,7 @@ export interface ClientCapabilities {
/**
* Present if the client supports elicitation from the server.
*/
- elicitation?: { form?: object; oob?: object } & ({ form: object } | { oob: object });
+ elicitation?: { form?: object; url?: object } & ({ form: object } | { url: object });
}
/**
@@ -1338,11 +1338,11 @@ export interface FormElicitRequestParams extends ElicitRequestParams {
};
}
-export interface OutOfBandElicitRequestParams extends ElicitRequestParams {
+export interface URLElicitRequestParams extends ElicitRequestParams {
/**
* The elicitation mode.
*/
- mode: "oob";
+ mode: "url";
/**
* The ID of the elicitation, which must be unique within the context of the server.
@@ -1365,14 +1365,14 @@ export interface ElicitRequestParams extends RequestParams {
/**
* The mode of elicitation.
* - "form": In-band structured data collection with optional schema validation
- * - "oob": Out-of-band interaction via URL navigation
+ * - "url": Out-of-band interaction via URL navigation
*/
- mode: "form" | "oob";
+ mode: "form" | "url";
/**
* The message to present to the user.
* For form mode: Describes what information is being requested.
- * For out-of-band mode: Explains why the interaction is needed.
+ * For url mode: Explains why the interaction is needed.
*/
message: string;
}
@@ -1382,7 +1382,7 @@ export interface ElicitRequestParams extends RequestParams {
*/
export interface ElicitRequest extends Request {
method: "elicitation/create";
- params: FormElicitRequestParams | OutOfBandElicitRequestParams;
+ params: FormElicitRequestParams | URLElicitRequestParams;
}
/**
From 7fab051ff0ccb512ab9f2fdbc67f1ce720633983 Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Wed, 2 Jul 2025 14:54:37 -0700
Subject: [PATCH 19/62] Clarify URL elicitation note language
---
docs/specification/draft/client/elicitation.mdx | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 1fd72455f..58ff4cac7 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -262,12 +262,13 @@ Note that complex nested structures, arrays of objects, and other advanced JSON
URL 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 elicitation is *not* for re-authorizing the MCP client's
- access to the MCP server (that is covered by [MCP
- authorization](../basic/authorization)). It's specifically for scenarios where
- the MCP server needs to obtain sensitive information, or authorization for
- third-party services on behalf of the user. The MCP client's authorization
- (bearer) token remains unchanged throughout this process.
+ **Important**: URL 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 elicitation requests **MUST** specify `mode: "url"` and include these parameters:
From f179987c56014952f1336ef1940649c1fff69fc3 Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Wed, 2 Jul 2025 15:05:39 -0700
Subject: [PATCH 20/62] Change requirements to recommendations for ssrf
---
docs/specification/draft/client/elicitation.mdx | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 58ff4cac7..711b5b4df 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -692,12 +692,14 @@ Clients **MUST NOT** open a user agent (e.g. browser) without explicit consent f
#### Server-Side Request Forgery (SSRF)
-Since clients facilitate the opening of URLs provided by servers, they **MUST** implement SSRF protections, including:
+Since clients facilitate the opening of URLs provided by servers, they **MUST** implement SSRF protections.
-- Requiring the `https://` scheme for all url mode URLs (no HTTP, `file://`, etc.)
-- Blocking requests to internal IP ranges (e.g., `127.0.0.1`, `10.0.0.0/8`, etc.)
-- Clearly rendering or distinguishing Unicode characters (e.g. punycode URLs) to avoid "look-alike" misdirections
-- Clearly communicating the destination server and target URL to the user when asking for consent
+The following are recommendations for implementing SSRF protections. Servers that choose to relax these contraints should be aware of the risks.
+
+- Require the `https://` scheme for all url mode URLs (no HTTP, `file://`, etc.)
+- Block requests to internal IP ranges (e.g., `127.0.0.1`, `10.0.0.0/8`, etc.)
+- Clearly render or distinguish Unicode characters (e.g. punycode URLs) to avoid "look-alike" misdirections
+- Clearly communicate the destination server and target URL to the user when asking for consent before opening the URL
Further recommendations can be found in the OWASP [SSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html).
From c2517837390a2d97bc4b69358c914cc5b1682744 Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Wed, 2 Jul 2025 15:09:44 -0700
Subject: [PATCH 21/62] Change bad elicitation/track from ignore to error
---
docs/specification/draft/client/elicitation.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 711b5b4df..8bdeec797 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -323,7 +323,7 @@ The client **MAY** request progress updates from the server by sending an `elici
The client **MUST** include an `elicitationId` in the request to identify which elicitation to send progress updates for. The client **SHOULD** include a `progressToken` in the request's `_meta` field.
-The server **MUST** ignore any `elicitation/track` requests containing an `elicitationId` that is not known or does not belong to the client.
+The server **MUST** not accept any `elicitation/track` requests containing an `elicitationId` that is not known or does not belong to the client (i.e. respond with an [error](/docs/concepts/architecture#error-handling)).
The server **MAY** send a `notifications/progress` notification to the client with the progress token and the progress status.
From fc2a37dfa691682d6c84d0b63bf4c7d8b4ea1c64 Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Wed, 2 Jul 2025 15:28:53 -0700
Subject: [PATCH 22/62] Clarify user identification for stdio vs remote
---
docs/specification/draft/client/elicitation.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index 8bdeec797..fa665d2df 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -538,8 +538,8 @@ Most practical uses of elicitation require that the server maintain state about
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
-- User identification **MUST** be derived from authenticated tokens
- State storage **MUST** be protected against unauthorized access
+- When using remote communication, user identification **MUST** be derived from authenticated tokens acquired via [MCP authorization](../basic/authorization)
The examples in this section are non-normative and illustrate potential uses
From 373c569de323050dee32c7bfb8c9dbc4bf2201ec Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Wed, 2 Jul 2025 15:34:10 -0700
Subject: [PATCH 23/62] make links relative for easier versioning switches
---
docs/specification/draft/client/elicitation.mdx | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index fa665d2df..b51442f63 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -51,7 +51,7 @@ Applications **SHOULD**:
## Capabilities
Clients that support elicitation **MUST** declare the `elicitation` capability during
-[initialization](/specification/draft/basic/lifecycle#initialization):
+[initialization](../basic/lifecycle#initialization):
```json
{
@@ -319,7 +319,7 @@ of band and the client is not aware of the outcome, unless the client requests p
### Progress Tracking
-The client **MAY** request progress updates from the server by sending an `elicitation/track` request with a [progress token](/specification/draft/basic/utilities/progress#progress-token). This is particularly useful in url mode, because the client is not involved in the interaction.
+The client **MAY** request progress updates from the server by sending an `elicitation/track` request with a [progress token](../basic/utilities/progress#progress-token). This is particularly useful in url mode, because the client is not involved in the interaction.
The client **MUST** include an `elicitationId` in the request to identify which elicitation to send progress updates for. The client **SHOULD** include a `progressToken` in the request's `_meta` field.
@@ -673,12 +673,12 @@ These requirements ensure that client implementations have clear rules about whe
### Identifying the User
Servers **MUST NOT** rely on client-provided user identification, as this can be forged.
-Instead, servers **SHOULD** follow [security best practices](/specification/draft/basic/security_best_practices).
+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 the [MCP authorization server](/specification/draft/basic/authorization) to identify the user
+- Correct: Rely on the [MCP authorization server](../basic/authorization) to identify the user
### Form Mode Security
@@ -707,7 +707,7 @@ Further recommendations can be found in the OWASP [SSRF Prevention Cheat Sheet](
URL 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](/specification/draft/basic/authorization) to identify the user, through a session cookie or equivalent in the browser.
+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 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:
From 0c8886ba25645c336b06f8f13d3f8a0d4e0b162f Mon Sep 17 00:00:00 2001
From: Nate Barbettini
Date: Sat, 5 Jul 2025 10:06:38 -0700
Subject: [PATCH 24/62] Fixes from review
---
docs/specification/draft/client/elicitation.mdx | 4 ++--
schema/draft/schema.json | 3 ++-
schema/draft/schema.ts | 2 +-
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index b51442f63..4780bc6d0 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -323,7 +323,7 @@ The client **MAY** request progress updates from the server by sending an `elici
The client **MUST** include an `elicitationId` in the request to identify which elicitation to send progress updates for. The client **SHOULD** include a `progressToken` in the request's `_meta` field.
-The server **MUST** not accept any `elicitation/track` requests containing an `elicitationId` that is not known or does not belong to the client (i.e. respond with an [error](/docs/concepts/architecture#error-handling)).
+The server **MUST** respond with an [error](/docs/concepts/architecture#error-handling) if the client sends an `elicitation/track` request containing an `elicitationId` that is not known or does not belong to the client.
The server **MAY** send a `notifications/progress` notification to the client with the progress token and the progress status.
@@ -694,7 +694,7 @@ Clients **MUST NOT** open a user agent (e.g. browser) without explicit consent f
Since clients facilitate the opening of URLs provided by servers, they **MUST** implement SSRF protections.
-The following are recommendations for implementing SSRF protections. Servers that choose to relax these contraints should be aware of the risks.
+The following are recommendations for implementing SSRF protections. Servers that choose to relax these constraints should be aware of the risks.
- Require the `https://` scheme for all url mode URLs (no HTTP, `file://`, etc.)
- Block requests to internal IP ranges (e.g., `127.0.0.1`, `10.0.0.0/8`, etc.)
diff --git a/schema/draft/schema.json b/schema/draft/schema.json
index d8218c287..680afe872 100644
--- a/schema/draft/schema.json
+++ b/schema/draft/schema.json
@@ -875,7 +875,8 @@
},
"required": [
"message",
- "mode"
+ "mode",
+ "requestedSchema"
],
"type": "object"
},
diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts
index 6e37443e3..95246613f 100644
--- a/schema/draft/schema.ts
+++ b/schema/draft/schema.ts
@@ -1329,7 +1329,7 @@ export interface FormElicitRequestParams extends ElicitRequestParams {
* A restricted subset of JSON Schema.
* Only top-level properties are allowed, without nesting.
*/
- requestedSchema?: {
+ requestedSchema: {
type: "object";
properties: {
[key: string]: PrimitiveSchemaDefinition;
From f36130e6add5a868a691c305e6c48cf2f7de721a Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Wed, 16 Jul 2025 13:12:47 -0700
Subject: [PATCH 25/62] add browser guidance
---
docs/specification/draft/client/elicitation.mdx | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/docs/specification/draft/client/elicitation.mdx b/docs/specification/draft/client/elicitation.mdx
index fcb6f2c52..83dad5c9c 100644
--- a/docs/specification/draft/client/elicitation.mdx
+++ b/docs/specification/draft/client/elicitation.mdx
@@ -688,7 +688,10 @@ Non-normative examples:
### URL Mode Security
-Clients **MUST NOT** open a user agent (e.g. browser) without explicit consent from the user
+Clients **MUST NOT** open a user agent (e.g. browser) without explicit consent from the user.
+
+Clients **MUST** render the URL provided by the server in a browser which 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.
#### Server-Side Request Forgery (SSRF)
From 05ba57c99982fb72b4493277d4f460b366e946d6 Mon Sep 17 00:00:00 2001
From: Wils Dawson
Date: Wed, 16 Jul 2025 14:04:49 -0700
Subject: [PATCH 26/62] update schema with new references
---
docs/specification/draft/schema.mdx | 32 +++--
schema/draft/schema.json | 198 ++++++++++++++--------------
schema/draft/schema.ts | 19 ++-
3 files changed, 137 insertions(+), 112 deletions(-)
diff --git a/docs/specification/draft/schema.mdx b/docs/specification/draft/schema.mdx
index 458a2d482..09795f799 100644
--- a/docs/specification/draft/schema.mdx
+++ b/docs/specification/draft/schema.mdx
@@ -27,7 +27,7 @@ the data is entirely optional.
Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.
Optionalelicitation
elicitation?:object
Present if the client supports elicitation from the server.
Optionalexperimental
experimental?:{[key:string]:object}
Experimental, non-standard capabilities that the client supports.
Optionalroots
roots?:{listChanged?:boolean}
Present if the client supports listing roots.
Type declaration
OptionallistChanged?: boolean
Whether the client supports notifications for changes to the roots list.
Optionalsampling
sampling?:object
Present if the client supports sampling from an LLM.
Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.
elicitation?: object;
experimental?: { [key: string]: object };
roots?: { listChanged?: boolean };
sampling?: object;
}