-
Notifications
You must be signed in to change notification settings - Fork 1.2k
SEP-1036: URL Mode Elicitation for secure out-of-band interactions #887
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SEP-1036: URL Mode Elicitation for secure out-of-band interactions #887
Conversation
|
(Comment reserved for future use) |
| - `"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 Elicitation Requests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to reviewers: This section is not new, but re-organized so that we can clearly describe form mode elicitation here, and URL mode elicitation in the next sub-section.
| | ----------------- | ------ | -------------------------------------------------------------- | | ||
| | `requestedSchema` | object | A JSON Schema defining the structure of the expected response. | | ||
|
|
||
| #### Requested Schema |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to reviewers: No changes here! (just moved)
| } | ||
| ``` | ||
|
|
||
| Clients declaring the `elicitation` capability **MUST** support at least one mode (`form` or `oob`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We considered allowing elicitation: {} to imply elicitation: { form: {} } for backwards compatibility with the 2025-06-18 spec version, at the cost of more logic when parsing capabilities. For now, we've proposed this small breaking change since we're already targeting a new spec version. Open to feedback from the community here.
|
Updated the title to be less jargony, thanks for the suggestion @localden! |
schema/draft/schema.ts
Outdated
| /** | ||
| * @category `elicitation/create` | ||
| */ | ||
| export interface ElicitRequestURLParams extends ElicitRequestParams { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, how the interfaces are structured, the ElicitRequestURLParams would also have the requestedSchema in it, because it extends ElicitRequestParams defined above - understand from this SEP that requestedSchema should only be present for form types and not for url elicitation mode.
pcarleton
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overall looks good. I'm approving, but let's get the suggested typescript schema changes in.
I'd also like to discuss in a follow-up adjusting the language around not providing URLs in other fields since the default implementation of that I think will be overly restrictive.
This is with my conformance hat on, where we'd want some way to enforce the MUST, and I think the enforcement would be too restrictive.
| - Servers **MUST NOT** use elicitation to request sensitive information. | ||
| - Servers **MUST NOT** use form mode elicitation to request sensitive information | ||
| - Servers **MUST** use URL mode for interactions involving sensitive information, such as credentials | ||
| - URLs **MUST NOT** appear in any field of an elicitation request, other than the `url` field in an URL mode request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'll want to change this to something like "Clients SHOULD NOT render URLs as clickable in any other field of an elicitation request". (can be in a follow-up, I'd like to get the bulk of this in).
A strict interpretation of this would have clients rejecting elicitation requests that have URLs in other parts of the elicitation request as invalid, but there are valid reasons to have it in other fields. For example, an email drafting server may send the email body as a "default" value for the use to edit before sending. The email body might contain links. Or a research mode might list the URL's it searched over in a message in order to "show its work" before getting accept/reject from a client.
That is very much in the spirit of what my initial language meant to achieve. I totally agree, I can do a fast-follow to add this! |
|
Thanks for the quick resolution of the typescript schemas! All good now! |
reivisiting the URL should/must language mentioned in review in a follow up
…actions
This commit adds support for URL mode elicitation as specified in SEP-1036,
enabling servers to direct users to external URLs for sensitive interactions
that must not pass through the MCP client.
Key changes:
Types (src/mcp/types.py):
- Add ELICITATION_REQUIRED error code (-32000)
- Update ElicitationCapability to support form and url modes
- Add ElicitTrackRequest and ElicitTrackResult for progress tracking
- Add UrlElicitationInfo and ElicitationRequiredErrorData types
- Update ElicitRequestParams with mode field and URL mode parameters
Server (src/mcp/server/):
- Add elicit_url() helper function in elicitation.py
- Add elicit_form() and elicit_url() methods to ServerSession
- Maintain backward compatibility with existing elicit() method
Client (src/mcp/client/session.py):
- Update capability negotiation for form and URL modes
- Add track_elicitation() method for progress monitoring
Tests:
- Comprehensive test coverage for URL mode elicitation
- Verify backward compatibility with form mode
- All 311 existing tests pass
Use cases enabled:
- OAuth authorization flows with third-party services
- Secure credential collection (API keys, passwords)
- Payment and subscription flows
- Any sensitive interaction requiring out-of-band handling
Breaking changes:
- ElicitRequestParams now requires mode field ("form" or "url")
- Clients must declare which elicitation modes they support
Closes: modelcontextprotocol/modelcontextprotocol#887
* mcp: support sep-1036 for URL mode elicitation Refs modelcontextprotocol/modelcontextprotocol#887 * up
This PR is the specification proposal for SEP #1036.
This PR introduces an elicitation mode for secure out-of-band interactions that bypass the MCP client.
There are some important use cases that require the MCP server to interact with the end-user in a secure way:
These interactions are highly sensitive in nature. Web applications have long avoided directly requesting third-party passwords or credentials by using flows like OAuth, and we can take inspiration from this solution.
The new elicitation mode proposed here requires that the MCP client obtain consent from the user, and then facilitate navigation to a URL in a user-agent (aka browser) where these interactions can occur securely and avoid transmitting sensitive data through the client.
Motivation and Context
One of the hot topics discussed but not addressed in #284 was the idea of fine-grained authorization for specific tools or resources in a third-party "downstream" API. This is not in scope for MCP authorization, which establishes authorization between the MCP client and MCP server only. Furthermore, the Security Best Practices document explains why MCP servers cannot be "simple" token passthrough servers.
In conversations with the community, it became clear that a mechanism for "downstream" authorization challenges and other sensitive flows was needed. @wdawson and I discussed a narrow version of this idea in #234, and proposed a broader user interaction mechanism in #475.
In the meantime, elicitation was added to the spec as a mechanism to request non-sensitive information from the user via in-band requests. In discussions with @bhosmer-ant and @pcarleton, we decided to reformat our ideas into a new mode of elicitation, instead of introducing a similar-but-different mechanism for out-of-band interactions.
This PR rolls up all of the feedback we received on #475. Thank you to everyone who helped review the first draft!
How Has This Been Tested?
TODO: Sample app showing both the client and server side of out-of-band elicitation.
Breaking Changes
{ "capabilities": { "elicitation": { // One or both of: "form": {}, "oob": {} } } }elicitation/createrequests must now specify themodefield (eitherformoroob)Reference Implementation
Client/server implementation in TypeScript: feat/url-elicitation
Explainer video: https://drive.google.com/file/d/1llCFS9wmkK_RUgi5B-zHfUUgy-CNb0n0/view?usp=sharing
Acknowledgements
Huge thanks to @localden, @siwachabhi, @connor4312, @pwwpche, @aaronpk, @btiernay, @ggoodman, @chhamilton, @patwhite, @adranwit, @LucaButBoring, @max-stytch, @mcguinness, and many others who have helped publicly and privately to refine this proposal.