diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..e7f32e65e --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +**/schema.json \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index f3658ac8f..cbaa84d89 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1,316 +1,306 @@ { - "$schema": "https://mintlify.com/docs.json", - "theme": "willow", - "name": "Model Context Protocol", - "colors": { - "primary": "#09090b", - "light": "#FAFAFA", - "dark": "#09090b" - }, - "favicon": "/favicon.svg", - "navigation": { - "tabs": [ - { - "tab": "User Guide", - "groups": [ - { - "group": "Get Started", - "pages": [ - "introduction", - { - "group": "Quickstart", - "pages": [ - "quickstart/server", - "quickstart/client", - "quickstart/user" + "$schema": "https://mintlify.com/docs.json", + "theme": "willow", + "name": "Model Context Protocol", + "colors": { "primary": "#09090b", "light": "#FAFAFA", "dark": "#09090b" }, + "favicon": "/favicon.svg", + "navigation": { + "tabs": [ + { + "tab": "User Guide", + "groups": [ + { + "group": "Get Started", + "pages": [ + "introduction", + { + "group": "Quickstart", + "pages": [ + "quickstart/server", + "quickstart/client", + "quickstart/user" + ] + }, + "examples", + "clients", + "faqs" + ] + }, + { + "group": "Tutorials", + "pages": [ + "tutorials/building-mcp-with-llms", + "docs/tools/debugging", + "docs/tools/inspector" + ] + }, + { + "group": "Concepts", + "pages": [ + "docs/concepts/architecture", + "docs/concepts/resources", + "docs/concepts/prompts", + "docs/concepts/tools", + "docs/concepts/sampling", + "docs/concepts/roots", + "docs/concepts/transports" + ] + }, + { + "group": "Development", + "pages": [ + "development/roadmap", + "development/contributing" + ] + } ] - }, - "examples", - "clients", - "faqs" - ] - }, - { - "group": "Tutorials", - "pages": [ - "tutorials/building-mcp-with-llms", - "docs/tools/debugging", - "docs/tools/inspector" - ] - }, - { - "group": "Concepts", - "pages": [ - "docs/concepts/architecture", - "docs/concepts/resources", - "docs/concepts/prompts", - "docs/concepts/tools", - "docs/concepts/sampling", - "docs/concepts/roots", - "docs/concepts/transports" - ] - }, - { - "group": "Development", - "pages": [ - "development/roadmap", - "development/contributing" - ] - } - ] - }, - { - "tab": "SDKs", - "icon": "book-open", - "groups": [ - { - "group": "Java", - "pages": [ - "sdk/java/mcp-overview", - "sdk/java/mcp-client", - "sdk/java/mcp-server" - ] - } - ] - }, - { - "tab": "Specification", - "icon": "book", - "groups": [ - { - "group": "2025-03-26 (Latest)", - "pages": [ - "specification/2025-03-26/index", - "specification/2025-03-26/changelog", - "specification/2025-03-26/architecture/index", - { - "group": "Base Protocol", - "pages": [ - "specification/2025-03-26/basic/index", - "specification/2025-03-26/basic/lifecycle", - "specification/2025-03-26/basic/transports", - "specification/2025-03-26/basic/authorization", - { - "group": "Utilities", - "pages": [ - "specification/2025-03-26/basic/utilities/cancellation", - "specification/2025-03-26/basic/utilities/ping", - "specification/2025-03-26/basic/utilities/progress" - ] - } + }, + { + "tab": "SDKs", + "icon": "book-open", + "groups": [ + { + "group": "Java", + "pages": [ + "sdk/java/mcp-overview", + "sdk/java/mcp-client", + "sdk/java/mcp-server" + ] + } ] - }, - { - "group": "Client Features", - "pages": [ - "specification/2025-03-26/client/roots", - "specification/2025-03-26/client/sampling" + }, + { + "tab": "Specification", + "icon": "book", + "groups": [ + { + "group": "2025-03-26 (Latest)", + "pages": [ + "specification/2025-03-26/index", + "specification/2025-03-26/changelog", + "specification/2025-03-26/architecture/index", + { + "group": "Base Protocol", + "pages": [ + "specification/2025-03-26/basic/index", + "specification/2025-03-26/basic/lifecycle", + "specification/2025-03-26/basic/transports", + "specification/2025-03-26/basic/authorization", + { + "group": "Utilities", + "pages": [ + "specification/2025-03-26/basic/utilities/cancellation", + "specification/2025-03-26/basic/utilities/ping", + "specification/2025-03-26/basic/utilities/progress" + ] + } + ] + }, + { + "group": "Client Features", + "pages": [ + "specification/2025-03-26/client/roots", + "specification/2025-03-26/client/sampling" + ] + }, + { + "group": "Server Features", + "pages": [ + "specification/2025-03-26/server/index", + "specification/2025-03-26/server/prompts", + "specification/2025-03-26/server/resources", + "specification/2025-03-26/server/tools", + { + "group": "Utilities", + "pages": [ + "specification/2025-03-26/server/utilities/completion", + "specification/2025-03-26/server/utilities/logging", + "specification/2025-03-26/server/utilities/pagination" + ] + } + ] + } + ] + }, + { + "group": "2024-11-05", + "pages": [ + "specification/2024-11-05/index", + "specification/2024-11-05/architecture/index", + { + "group": "Base Protocol", + "pages": [ + "specification/2024-11-05/basic/index", + "specification/2024-11-05/basic/lifecycle", + "specification/2024-11-05/basic/messages", + "specification/2024-11-05/basic/transports", + { + "group": "Utilities", + "pages": [ + "specification/2024-11-05/basic/utilities/cancellation", + "specification/2024-11-05/basic/utilities/ping", + "specification/2024-11-05/basic/utilities/progress" + ] + } + ] + }, + { + "group": "Client Features", + "pages": [ + "specification/2024-11-05/client/roots", + "specification/2024-11-05/client/sampling" + ] + }, + { + "group": "Server Features", + "pages": [ + "specification/2024-11-05/server/index", + "specification/2024-11-05/server/prompts", + "specification/2024-11-05/server/resources", + "specification/2024-11-05/server/tools", + { + "group": "Utilities", + "pages": [ + "specification/2024-11-05/server/utilities/completion", + "specification/2024-11-05/server/utilities/logging", + "specification/2024-11-05/server/utilities/pagination" + ] + } + ] + } + ] + }, + { + "group": "draft", + "pages": [ + "specification/draft/index", + "specification/draft/changelog", + "specification/draft/architecture/index", + { + "group": "Base Protocol", + "pages": [ + "specification/draft/basic/index", + "specification/draft/basic/lifecycle", + "specification/draft/basic/transports", + "specification/draft/basic/authorization", + "specification/draft/basic/security_best_practices", + { + "group": "Utilities", + "pages": [ + "specification/draft/basic/utilities/cancellation", + "specification/draft/basic/utilities/ping", + "specification/draft/basic/utilities/progress" + ] + } + ] + }, + { + "group": "Client Features", + "pages": [ + "specification/draft/client/roots", + "specification/draft/client/sampling", + "specification/draft/client/elicitation", + "specification/draft/client/user_interaction" + ] + }, + { + "group": "Server Features", + "pages": [ + "specification/draft/server/index", + "specification/draft/server/prompts", + "specification/draft/server/resources", + "specification/draft/server/tools", + { + "group": "Utilities", + "pages": [ + "specification/draft/server/utilities/completion", + "specification/draft/server/utilities/logging", + "specification/draft/server/utilities/pagination" + ] + } + ] + } + ] + }, + { + "group": "Resources", + "pages": [ + "specification/versioning", + "specification/contributing" + ] + } ] - }, - { - "group": "Server Features", - "pages": [ - "specification/2025-03-26/server/index", - "specification/2025-03-26/server/prompts", - "specification/2025-03-26/server/resources", - "specification/2025-03-26/server/tools", - { - "group": "Utilities", - "pages": [ - "specification/2025-03-26/server/utilities/completion", - "specification/2025-03-26/server/utilities/logging", - "specification/2025-03-26/server/utilities/pagination" - ] - } - ] - } + } + ], + "global": { + "anchors": [ + { + "anchor": "C# SDK", + "href": "https://github.com/modelcontextprotocol/csharp-sdk", + "icon": "square-c" + }, + { + "anchor": "Java SDK", + "href": "https://github.com/modelcontextprotocol/java-sdk", + "icon": "java" + }, + { + "anchor": "Kotlin SDK", + "href": "https://github.com/modelcontextprotocol/kotlin-sdk", + "icon": "square-k" + }, + { + "anchor": "Python SDK", + "href": "https://github.com/modelcontextprotocol/python-sdk", + "icon": "python" + }, + { + "anchor": "Ruby SDK", + "href": "https://github.com/modelcontextprotocol/ruby-sdk", + "icon": "gem" + }, + { + "anchor": "Swift SDK", + "href": "https://github.com/modelcontextprotocol/swift-sdk", + "icon": "swift" + }, + { + "anchor": "TypeScript SDK", + "href": "https://github.com/modelcontextprotocol/typescript-sdk", + "icon": "square-js" + } ] - }, - { - "group": "2024-11-05", - "pages": [ - "specification/2024-11-05/index", - "specification/2024-11-05/architecture/index", - { - "group": "Base Protocol", - "pages": [ - "specification/2024-11-05/basic/index", - "specification/2024-11-05/basic/lifecycle", - "specification/2024-11-05/basic/messages", - "specification/2024-11-05/basic/transports", - { - "group": "Utilities", - "pages": [ - "specification/2024-11-05/basic/utilities/cancellation", - "specification/2024-11-05/basic/utilities/ping", - "specification/2024-11-05/basic/utilities/progress" - ] - } - ] - }, - { - "group": "Client Features", - "pages": [ - "specification/2024-11-05/client/roots", - "specification/2024-11-05/client/sampling" - ] - }, - { - "group": "Server Features", - "pages": [ - "specification/2024-11-05/server/index", - "specification/2024-11-05/server/prompts", - "specification/2024-11-05/server/resources", - "specification/2024-11-05/server/tools", - { - "group": "Utilities", - "pages": [ - "specification/2024-11-05/server/utilities/completion", - "specification/2024-11-05/server/utilities/logging", - "specification/2024-11-05/server/utilities/pagination" - ] - } - ] - } - ] - }, - { - "group": "draft", - "pages": [ - "specification/draft/index", - "specification/draft/changelog", - "specification/draft/architecture/index", - { - "group": "Base Protocol", - "pages": [ - "specification/draft/basic/index", - "specification/draft/basic/lifecycle", - "specification/draft/basic/transports", - "specification/draft/basic/authorization", - "specification/draft/basic/security_best_practices", - { - "group": "Utilities", - "pages": [ - "specification/draft/basic/utilities/cancellation", - "specification/draft/basic/utilities/ping", - "specification/draft/basic/utilities/progress" - ] - } - ] - }, - { - "group": "Client Features", - "pages": [ - "specification/draft/client/roots", - "specification/draft/client/sampling", - "specification/draft/client/elicitation" - ] - }, - { - "group": "Server Features", - "pages": [ - "specification/draft/server/index", - "specification/draft/server/prompts", - "specification/draft/server/resources", - "specification/draft/server/tools", - { - "group": "Utilities", - "pages": [ - "specification/draft/server/utilities/completion", - "specification/draft/server/utilities/logging", - "specification/draft/server/utilities/pagination" - ] - } - ] - } - ] - }, - { - "group": "Resources", - "pages": ["specification/versioning", "specification/contributing"] - } - ] - } - ], - "global": { - "anchors": [ - { - "anchor": "C# SDK", - "href": "https://github.com/modelcontextprotocol/csharp-sdk", - "icon": "square-c" - }, - { - "anchor": "Java SDK", - "href": "https://github.com/modelcontextprotocol/java-sdk", - "icon": "java" - }, - { - "anchor": "Kotlin SDK", - "href": "https://github.com/modelcontextprotocol/kotlin-sdk", - "icon": "square-k" - }, - { - "anchor": "Python SDK", - "href": "https://github.com/modelcontextprotocol/python-sdk", - "icon": "python" - }, - { - "anchor": "Ruby SDK", - "href": "https://github.com/modelcontextprotocol/ruby-sdk", - "icon": "gem" + } + }, + "logo": { "light": "/logo/light.svg", "dark": "/logo/dark.svg" }, + "navbar": { + "links": [], + "primary": { + "type": "button", + "label": "GitHub", + "href": "https://github.com/modelcontextprotocol" + } + }, + "seo": { + "metatags": { + "og:image": "https://raw.githubusercontent.com/modelcontextprotocol/docs/2eb6171ddbfeefde349dc3b8d5e2b87414c26250/images/og-image.png" }, + "indexing": "navigable" + }, + "footer": { + "socials": { "github": "https://github.com/modelcontextprotocol" } + }, + "redirects": [ { - "anchor": "Swift SDK", - "href": "https://github.com/modelcontextprotocol/swift-sdk", - "icon": "swift" + "source": "/tutorials/building-a-client", + "destination": "/quickstart/client" }, + { "source": "/quickstart", "destination": "/quickstart/server" }, { - "anchor": "TypeScript SDK", - "href": "https://github.com/modelcontextprotocol/typescript-sdk", - "icon": "square-js" + "source": "/specification/latest", + "destination": "/specification/2025-03-26", + "permanent": false } - ] - } - }, - "logo": { - "light": "/logo/light.svg", - "dark": "/logo/dark.svg" - }, - "navbar": { - "links": [], - "primary": { - "type": "button", - "label": "GitHub", - "href": "https://github.com/modelcontextprotocol" - } - }, - "seo": { - "metatags": { - "og:image": "https://raw.githubusercontent.com/modelcontextprotocol/docs/2eb6171ddbfeefde349dc3b8d5e2b87414c26250/images/og-image.png" - }, - "indexing": "navigable" - }, - "footer": { - "socials": { - "github": "https://github.com/modelcontextprotocol" - } - }, - "redirects": [ - { - "source": "/tutorials/building-a-client", - "destination": "/quickstart/client" - }, - { - "source": "/quickstart", - "destination": "/quickstart/server" - }, - { - "source": "/specification/latest", - "destination": "/specification/2025-03-26", - "permanent": false - } - ], - "contextual": { - "options": ["copy", "view"] - } + ], + "contextual": { "options": ["copy", "view"] } } diff --git a/docs/specification/draft/basic/lifecycle.mdx b/docs/specification/draft/basic/lifecycle.mdx index 58aa184fa..4f0c6315b 100644 --- a/docs/specification/draft/basic/lifecycle.mdx +++ b/docs/specification/draft/basic/lifecycle.mdx @@ -62,7 +62,10 @@ The client **MUST** initiate this phase by sending an `initialize` request conta "listChanged": true }, "sampling": {}, - "elicitation": {} + "elicitation": {}, + "userInteraction": { + "types": ["ua"] + } }, "clientInfo": { "name": "ExampleClient", @@ -150,6 +153,7 @@ Key capabilities include: | Client | `roots` | Ability to provide filesystem [roots](/specification/draft/client/roots) | | Client | `sampling` | Support for LLM [sampling](/specification/draft/client/sampling) requests | | Client | `elicitation` | Support for server [elicitation](/specification/draft/client/elicitation) requests | +| Client | `userInteraction` | Support for [user interactions](/specification/draft/client/user_interaction) | | Client | `experimental` | Describes support for non-standard experimental features | | Server | `prompts` | Offers [prompt templates](/specification/draft/server/prompts) | | Server | `resources` | Provides readable [resources](/specification/draft/server/resources) | diff --git a/docs/specification/draft/changelog.mdx b/docs/specification/draft/changelog.mdx index d09e798b8..512fddcf6 100644 --- a/docs/specification/draft/changelog.mdx +++ b/docs/specification/draft/changelog.mdx @@ -15,6 +15,8 @@ the previous revision, [2025-03-26](/specification/2025-03-26). 4. Clarified [security considerations](https://modelcontextprotocol.io/specification/draft/basic/authorization#3-security-considerations) and best practices in the authorization spec and in a new [security best practices page](https://modelcontextprotocol.io/specification/draft/basic/security_best_practices). 5. Added support for **[elicitation](/specification/draft/client/elicitation)**, enabling servers to request additional information from users during interactions. (PR [#382](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/382)) +6. Added support for **[user interaction](/specification/draft/client/user_interaction)** (PR + [#475](https://github.com/modelcontextprotocol/specification/pull/475)) ## Other schema changes diff --git a/docs/specification/draft/client/user_interaction.mdx b/docs/specification/draft/client/user_interaction.mdx new file mode 100644 index 000000000..79c69b106 --- /dev/null +++ b/docs/specification/draft/client/user_interaction.mdx @@ -0,0 +1,410 @@ +--- +title: User Interaction +--- + +**Protocol Revision**: draft + +The Model Context Protocol (MCP) provides a standardized way for servers to interact +directly with end-users without data passing through the client or the LLM. This allows +servers to maintain control over user interactions and data sharing while dynamically +gathering necessary information. + +The interaction itself is fully under the control of the MCP server and the MCP client is +only responsible for providing an affordance to start it (typically by presenting a URL to +the end-user, and opening it in a user agent such as a web browser). Within this model, +the client's responsibilities remain minimal and the server has the flexibility to +implement a wide range of interactions involving the end-user. For example: + +- A productivity MCP server might request a user to authorize a third-party service to + access their documents. +- A news MCP server might request a user to upgrade their subscription to access more features. +- A banking MCP server might request a user to verify their account to access a new feature. + +## Terminology + +- **End-user**: The human who is interacting with with the MCP server through their MCP client. +- **User agent**: a client, such as a web browser, that is capable of + interacting with the end-user. Broadly, it is used as defined in + [RFC 9110 Section 3.5](https://datatracker.ietf.org/doc/html/rfc9110#section-3.5). + +## Capabilities + +MCP clients that support user interaction **MUST** declare the `userInteraction` capability during +[initialization](/specification/draft/basic/lifecycle#initialization): + +```json +{ + "capabilities": { + "userInteraction": { + "types": ["ua"] + } + } +} +``` + +Clients supporting the `userInteraction` capability **MUST** support at least one +interaction type, and **MUST** list all the interaction types they support in the `types` +array. The acceptable values are defined in the [Interaction Types](#interaction-types) +section below. + +The MCP server **MUST NOT** send an interaction request to the client of a type that is not +explicitly declared by the client. + + + +For trust and safety, there **SHOULD** always +be a human in the loop with the ability to deny interaction requests. + +MCP clients **MUST**: + +- Provide a way for the end-user to consent to the interaction. +- Clearly communicate which server is requesting an interaction. + +MCP clients **SHOULD**: + +- Allow the end-user to cancel the interaction. + + + +Using the `userInteraction` capability means that the MCP server **MUST** be stateful, if +it is not already. At a minimum, the MCP server **MUST** keep track of the interactions it +has created for each MCP client. + + + +## Protocol Messages + +### Server-Initiated Interaction Requests + +When the MCP client indicates support for user interactions, the MCP server **MAY** request a user +interaction from the client at any time. To request a user interaction, the server sends an +`interaction/create` message to the client. + +The request includes the following fields as part of the `params` object: + +- `id`: The ID of the interaction that **MUST** be unique across the server's concurrent + interactions. +- `type`: The type of interaction, which **MUST** be one of the types negotiated during + [initialization](/specification/draft/basic/lifecycle#initialization). +- `interaction`: The interaction object, the schema of which depends on the type of + interaction. Each schema is defined in the [Interaction Types](#interaction-types) + section below. + +The following is an example of a `interaction/create` message for a `ua` interaction: + +```json +{ + "jsonrpc": "2.0", + "id": 123, + "method": "interaction/create", + "params": { + "id": "c8ec9a71-c475-4a88-a774-e9cd154bc7f8", + "type": "ua", + "interaction": { + "url": "https://oauth.example.com/authorize?client_id=abc123&...", + "message": { + "type": "text", + "text": "Authorization is required to access your Example Co files." + } + } + } +} +``` + +The following flow diagram illustrates the `ua` interaction type across the server, the client, and the end-user: + +```mermaid +sequenceDiagram + participant U as End-User + participant B as User Agent (Browser) + participant C as MCP Client + participant S as MCP Server + + Note over S,C: Server initiates prompt interaction + S->>C: interaction/create type=ua + + C->>U: Present consent to open URL + U-->>C: Provide consent + + C->>B: Open URL + C->>S: Send response + Note over U,B: Human interaction + B-->>S: Perform interaction + + Note over S: Continue operations +``` + + + +### Requiring Interaction as an Error Response + +The MCP server **MAY** require a user interaction as an error response to a client +request. This is useful when interaction is required as a pre-condition for a request. For +example, a [tool call](/specification/draft/server/tools#calling-tools) or [resource read](/specification/draft/server/resources#reading-resources) +request that requires the end-user to authorize a third-party service before the request +can be completed. + +The MCP server **MUST** send an +[error response](/specification/draft/basic/lifecycle#error-handling) with the `code` equal to +`-32003` and the `message` equal to `interaction_required`. + +The error response **MUST** include an `data` object consistent with one of the defined +[interaction types](#interaction-types). + +The following is an example of an error response containing a `ua` interaction: + +```json +{ + "jsonrpc": "2.0", + "id": 123, + "error": { + "code": -32003, + "message": "interaction_required", + "data": { + "id": "c8ec9a71-c475-4a88-a774-e9cd154bc7f8", + "type": "ua", + "url": "https://oauth.example.com/authorize?client_id=abc123&...", + "message": { + "type": "text", + "text": "Authorization is required to access your Example Co files." + } + } + } +} +``` + +The following flow diagram illustrates a client request (tool call) that requires interaction with a third-party service: + +```mermaid +sequenceDiagram + participant U as End-User + participant B as User Agent (Browser) + participant C as MCP Client + participant S as MCP Server + participant T as Third-Party Service + + C->>S: tools/call name=send_email + + Note over S: Server determines interaction is required + S->>C: error code=-32003 + + C->>U: Present consent to open URL + U-->>C: Provide consent + + C->>B: Open URL + B->>T: Navigate to URL + Note over T: Human interaction + T-->>S: Redirect to MCP server + + Note over S: Completed interaction + + Note over C: At a later time, retry request + C->>S: tools/call name=send_email + Note over S: Continue operations +``` + +## Interaction Types + +When a user interaction is requested by the server and supported by the client, the MCP client **MUST** present +the user with an interaction flow. The type of flow is defined by the MCP server, and the client's behavior +is specific to the interaction type. + +This specification defines one type of user interaction: + +- **`ua`**: A user agent interaction that involves making a request via a + client application that acts on behalf of the user, such as a web browser. + +The client and server **MAY** negotiate additional interaction types. + + +### User Agent Interactions + +A user agent interaction is a user interaction that involves the MCP client facilitating +navigation to a URL in a client application such as a web browser. This allows the MCP server to +obtain data without involving the MCP client. The MCP server can, as a result, control the +entire interaction from start to finish, including the user experience, and guarantee the +security of sensitive data, such as API keys or access tokens. + +This flow requires the client to support the `ua` user interaction type: +```json +{ + "capabilities": { + "userInteraction": { + "types": ["ua"] + } + } +} +``` + +The MCP client **MUST** facilitate the opening of the URL in a user agent, such as the default web browser. + +#### Server Request + +For `ua` interactions, the `interaction` object has the following properties: + +- `url`: The URL that the user should interact with. +- `message`: An optional `TextContent` object used to provide an explanation to the user about the interaction. + +```json +{ + "jsonrpc": "2.0", + "id": 123, + "method": "interaction/create", + "params": { + "id": "c8ec9a71-c475-4a88-a774-e9cd154bc7f8", + "type": "ua", + "interaction": { + "url": "https://example.com/mcp?state=1234567890&...", + "message": { + "type": "text", + "text": "Please sign in to your account." + } + } + } +} +``` + +#### Client Response + +When the client facilitates the opening of the URL, it **MUST** send a response to the server: + +```json +{ + "jsonrpc": "2.0", + "id": 123, + "result": {} +} +``` + +Alternatively, if the end-user cancels or declines the interaction, the client **MUST** +send an error response to the server: + +```json +{ + "jsonrpc": "2.0", + "id": 123, + "error": { + "code": -32099, + "message": "User did not consent to the interaction." + } +} +``` + +## Tracking Progress +The [Progress capability](/specification/draft/basic/utilities/progress) provides a way +for MCP clients to track progress for user interactions. By tracking the progress of an +interaction, the MCP client can provide a better user experience. For example, the MCP +client could: + +- Update the UI when the interaction is complete. +- Automatically retry a tool call that required interaction. + +Tracking progress for user interactions is optional. MCP clients **MAY** send an +`interaction/track` message to the MCP server along with a [progress token](/specification/draft/basic/utilities/progress#progress-flow) +to track the progress of an interaction. The MCP client **MUST** include the interaction +ID in the `id` field for which it wants to track. This `id` **MUST** refer to an +interaction the server sent to the client. + +```json +{ + "jsonrpc": "2.0", + "id": 123, + "method": "interaction/track", + "params": { + "_meta": { + "progressToken": "progress-token-123" + }, + "id": "c8ec9a71-c475-4a88-a774-e9cd154bc7f8" + } +} +``` + +MCP servers **MUST NOT** send progress notifications related to the interaction if: + +- The `id` is not an interaction the server created. +- The `id` is not an interaction associated with the client. +- The `id` is not an interaction associated with the current MCP session, if session management is in use. + +MCP servers that receive a valid `interaction/track` request **SHOULD** send at least 1 +`notifications/progress` message, even if the interaction is already complete. + +The following is an example of a progress notification sent by the MCP server: + +```json +{ + "jsonrpc": "2.0", + "method": "notifications/progress", + "params": { + "progressToken": "progress-token-123", + "progress": 100, + "total": 100, + "message": "Consent granted." + } +} +``` + +## Cancelling an Interaction + +The MCP server **MAY** cancel an interaction at any time by sending a +`notifications/cancelled` message to the client, as described in [Cancellation](/specification/draft/basic/utilities/cancellation). +The MCP client **SHOULD NOT** send a response. + + +## Security Considerations + +### Handling Sensitive Information + +MCP servers **MUST** use the `ua` interaction type for sensitive information, such as +auth credentials or authorization grants. The MCP client **MUST NOT** send sensitive +information to the MCP server in any other way. + +### User Consent + +The MCP client **SHOULD** clearly communicate the purpose of the interaction to the end-user, +and provide a way for the end-user to consent to the interaction before continuing. + +### Identifying the User + +The MCP server **MUST NOT** rely on input from the client or end-user to identify the +end-user, as this untrusted input can be forged and lead to impersonation attacks. + +Instead, the MCP server **SHOULD** follow [security best practices](/specification/draft/basic/security_best_practices). + +### Server-side Request Forgery + +With the `ua` interaction type, the MCP client is expected to make a request via a user agent +based on the value of the `url` parameter in the interaction object. Since MCP enables clients +to interoperate with MCP servers it has no prior knowledge of, this opens a risk for Server-Side +Request Forgery (SSRF) attacks by malicious MCP servers. MCP clients **SHOULD** take appropriate +precautions against SSRF attacks, such as blocking requests to internal IP address ranges and +requiring TLS. + +Additionally, the MCP client **SHOULD** validate the `url` parameter in the interaction object and +provide sufficient context to the user about the request that will be made, before it is opened in +a User Agent. + +Further recommendations can be found in the Open Worldwide Application Security +Project (OWASP) [SSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html). + +### Phishing + +The `ua` interaction type may be used in a way where the `url` parameter in the +interaction object points to a URL on a domain that is not the MCP server's domain. For +example, the URL may be an authorization URL of a third-party service that the MCP server +needs the user to authorize access to. If that third-party service is malicious or +compromised, it could trick the user into revealing their account credentials or other +sensitive information. + +To mitigate this risk, MCP clients **SHOULD** take appropriate precautions, such as verifying the +authenticity of the URL and clearly presenting the destination of the request to the user. + +### Impersonation attacks + +Since MCP enables clients to interoperate with MCP servers it has no prior knowledge of, +this opens a risk for impersonation attacks by malicious MCP clients. MCP servers +**SHOULD** take appropriate precautions against impersonation attacks, such as: + +- Implementing [Authorization](/specification/draft/basic/authorization) +- Identifying the end-user in trusted (server) code +- Ensuring that user interaction requests are bound to the MCP session to prevent Insecure + Direct Object Reference (IDOR) attacks diff --git a/docs/specification/draft/index.mdx b/docs/specification/draft/index.mdx index ebba5d4f5..ec254bcc6 100644 --- a/docs/specification/draft/index.mdx +++ b/docs/specification/draft/index.mdx @@ -63,6 +63,7 @@ Clients may offer the following features to servers: - **Sampling**: Server-initiated agentic behaviors and recursive LLM interactions - **Elicitation**: Server-initiated requests for additional information from users +- **User Interaction**: Server-initiated out-of-band interactions with end-users ### Additional Utilities diff --git a/package.json b/package.json index a3dfd568c..fab3aee69 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,12 @@ "printWidth": 89, "proseWrap": "always" } + }, + { + "files": "*.json", + "options": { + "tabWidth": 4 + } } ] }, diff --git a/schema/draft/schema.json b/schema/draft/schema.json index 05552b38d..93fd5902c 100644 --- a/schema/draft/schema.json +++ b/schema/draft/schema.json @@ -227,6 +227,22 @@ "description": "Present if the client supports sampling from an LLM.", "properties": {}, "type": "object" + }, + "userInteraction": { + "description": "Present if the client supports user interaction.", + "properties": { + "types": { + "description": "An array of supported user interaction types. Clients must support at least one type.\n\nThis specification defines one interaction type:\n- \"ua\": A user agent interaction involving making a request via a User Agent (e.g. a Web browser)\n\nAdditional interaction types may be negotiated between client and server.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "types" + ], + "type": "object" } }, "type": "object" @@ -287,6 +303,9 @@ }, { "$ref": "#/definitions/CompleteRequest" + }, + { + "$ref": "#/definitions/TrackUserInteractionRequest" } ] }, @@ -303,6 +322,9 @@ }, { "$ref": "#/definitions/ElicitResult" + }, + { + "$ref": "#/definitions/CreateUserInteractionResult" } ] }, @@ -499,6 +521,62 @@ ], "type": "object" }, + "CreateUserInteractionRequest": { + "description": "A request from the server to the client to create a user interaction.", + "properties": { + "method": { + "const": "interaction/create", + "type": "string" + }, + "params": { + "properties": { + "id": { + "description": "The ID of the interaction.", + "type": "string" + }, + "interaction": { + "anyOf": [ + { + "additionalProperties": true, + "properties": {}, + "type": "object" + }, + { + "$ref": "#/definitions/UAInteraction" + } + ], + "description": "The interaction object. The schema of the interaction object is dependent on the type of\ninteraction." + }, + "type": { + "description": "The type of interaction.", + "type": "string" + } + }, + "required": [ + "id", + "interaction", + "type" + ], + "type": "object" + } + }, + "required": [ + "method", + "params" + ], + "type": "object" + }, + "CreateUserInteractionResult": { + "description": "The client's response to a user interaction/create request from the server.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.", + "type": "object" + } + }, + "type": "object" + }, "Cursor": { "description": "An opaque token used to represent a cursor for pagination.", "type": "string" @@ -2069,6 +2147,9 @@ }, { "$ref": "#/definitions/ElicitRequest" + }, + { + "$ref": "#/definitions/CreateUserInteractionRequest" } ] }, @@ -2103,6 +2184,9 @@ }, { "$ref": "#/definitions/CompleteResult" + }, + { + "$ref": "#/definitions/TrackUserInteractionResult" } ] }, @@ -2362,6 +2446,74 @@ ], "type": "object" }, + "TrackUserInteractionRequest": { + "description": "A request from the client to the server to track the progress of a user interaction.", + "properties": { + "_meta": { + "properties": { + "progressToken": { + "$ref": "#/definitions/ProgressToken", + "description": "The progress token which was given in the initial request, used to associate this notification with the request that is proceeding." + } + }, + "required": [ + "progressToken" + ], + "type": "object" + }, + "method": { + "const": "interaction/track", + "type": "string" + }, + "params": { + "properties": { + "id": { + "description": "The ID of the interaction.", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + }, + "required": [ + "_meta", + "method", + "params" + ], + "type": "object" + }, + "TrackUserInteractionResult": { + "description": "The server's response to a user interaction/track request from the client.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.", + "type": "object" + } + }, + "type": "object" + }, + "UAInteraction": { + "description": "Defines the interaction object for \"ua\" (user agent) type interactions.", + "properties": { + "message": { + "$ref": "#/definitions/TextContent", + "description": "An optional message to provide an explanation to the user about the interaction." + }, + "url": { + "description": "The URL that the user should interact with.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "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 0852bad4b..b5ea9eaab 100644 --- a/schema/draft/schema.ts +++ b/schema/draft/schema.ts @@ -220,10 +220,26 @@ export interface ClientCapabilities { * Present if the client supports sampling from an LLM. */ sampling?: object; + /** * Present if the client supports elicitation from the server. */ elicitation?: object; + + /** + * Present if the client supports user interaction. + */ + userInteraction?: { + /** + * An array of supported user interaction types. Clients must support at least one type. + * + * This specification defines one interaction type: + * - "ua": A user agent interaction involving making a request via a User Agent (e.g. a Web browser) + * + * Additional interaction types may be negotiated between client and server. + */ + types: string[]; + }; } /** @@ -1258,7 +1274,7 @@ export interface ElicitRequest extends Request { * Restricted schema definitions that only allow primitive types * without nested objects or arrays. */ -export type PrimitiveSchemaDefinition = +export type PrimitiveSchemaDefinition = | StringSchema | NumberSchema | BooleanSchema @@ -1307,7 +1323,7 @@ export interface ElicitResult extends Result { * - "cancel": User dismissed without making an explicit choice */ action: "accept" | "decline" | "cancel"; - + /** * The submitted form data, only present when action is "accept". * Contains values matching the requested schema. @@ -1315,6 +1331,76 @@ export interface ElicitResult extends Result { content?: { [key: string]: unknown }; } +/* User Interaction */ +/** + * A request from the server to the client to create a user interaction. + */ +export interface CreateUserInteractionRequest extends Request { + method: "interaction/create"; + params: { + /** + * The ID of the interaction. + */ + id: string; + /** + * The type of interaction. + */ + type: string; + /** + * The interaction object. The schema of the interaction object is dependent on the type of + * interaction. + */ + interaction: UAInteraction | object; + }; +} + +/** + * Defines the interaction object for "ua" (user agent) type interactions. + */ +export interface UAInteraction { + /** + * The URL that the user should interact with. + * + * @format uri + */ + url: string; + + /** + * An optional message to provide an explanation to the user about the interaction. + */ + message?: TextContent; +} + +/** + * The client's response to a user interaction/create request from the server. + */ +export interface CreateUserInteractionResult extends Result { } + +/** + * A request from the client to the server to track the progress of a user interaction. + */ +export interface TrackUserInteractionRequest extends Request { + method: "interaction/track"; + params: { + /** + * The ID of the interaction. + */ + id: string; + }; + _meta: { + /** + * The progress token which was given in the initial request, used to associate this notification with the request that is proceeding. + */ + progressToken: ProgressToken; + }; +} + + +/** + * The server's response to a user interaction/track request from the client. + */ +export interface TrackUserInteractionResult extends Result { } + /* Client messages */ export type ClientRequest = | PingRequest @@ -1329,7 +1415,8 @@ export type ClientRequest = | SubscribeRequest | UnsubscribeRequest | CallToolRequest - | ListToolsRequest; + | ListToolsRequest + | TrackUserInteractionRequest; export type ClientNotification = | CancelledNotification @@ -1337,14 +1424,15 @@ export type ClientNotification = | InitializedNotification | RootsListChangedNotification; -export type ClientResult = EmptyResult | CreateMessageResult | ListRootsResult | ElicitResult; +export type ClientResult = EmptyResult | CreateMessageResult | ListRootsResult | ElicitResult | CreateUserInteractionResult; /* Server messages */ export type ServerRequest = | PingRequest | CreateMessageRequest | ListRootsRequest - | ElicitRequest; + | ElicitRequest + | CreateUserInteractionRequest; export type ServerNotification = | CancelledNotification @@ -1365,4 +1453,5 @@ export type ServerResult = | ListResourcesResult | ReadResourceResult | CallToolResult - | ListToolsResult; + | ListToolsResult + | TrackUserInteractionResult;