Skip to content

Conversation

@pcingola
Copy link

Related discussion

The scope of these RFC is to a stateless transport layer (HTTP), as an alternative to SSE.
Implementing stateless servers is simple, and easier to scale than SSE.
Servers may choose to implemet one (or more) of the transports (stdio, SSE, and HTTP).

Motivation and Context

Currently the protocol offers two main transports: either stdio transport (i.e. local running "servers"), or remote SSE (for remote servers).

As the MCP protocol is inspired by Language Server Protocol, the client is currently assumed to have dedicated connection/s to the server/s during a long running session. This means that MCP's SSE transport is supposed to have very long lived connections, which can be challenging to scale.

Problem

MCP is currently a stateful protocol, with a long-lived connection between client and server. The protocol is definitely not designed around repeatedly opening a connection, issuing one semantic request, then closing.

This is fairly limiting for serverless deployments, which frequently autoscale up and down, and generally aren't designed around long-lived requests (for example, typically there's a max request lifetime measured in minutes).

Deploying to a Platform-as-a-Service is really nice and convenient as a developer, so not being very compatible with this model creates an impediment to broader MCP adoption.

Proposed solution

On top of the statefull protocol, also offer stateless variant of the protocol. This is done by using simple HTTP / POST with the same JSON-RBC structures already defined.

Approach

The changes to the specification introduced in this RFC are minimal, so we can leverage all the current specification.

We recognize that the stateless server would not be able to implement the same features as a statful server. Specifically, server notifications and sampling are not possible in this simple statless server proposal. Nevertheless a client that need these features can use SSE (if made available by the server).

Use case example

A typical use case for the stateless MCP protocol is to offer tools, prompts, and resources that can be easily scaled and deployed in scaling systems, such as Kubernetes clusters.

NOT Covered

This RFC is intentionally NOT covering other items discussed, specifically it does not intend to cover other ways to mitigate the "long connections" issues, such as:

  • Session tokens to keep state
  • Alternatives to notifications in a stateless server
  • Negotiation capabilities for websockets and polling
  • Authentication, Authorizations and Accounting (AAA)

How Has This Been Tested?

This change on the specification does not alter the main protocol, only adds another transport.

Breaking Changes

None

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

This is based on an excelent [discussion](#102 and input from the forum.
The idea is to create a minimal change that enables easier scaling, thus speeds up MCP adoption.

@PederHP
Copy link
Member

PederHP commented Jan 29, 2025

Not sure when I would use this transport, but I think I support the inclusion of a pure HTTP based transport. Question:

In the **HTTP** transport, the server operates as an independent process that
can handle multiple client connections. The server **MAY** answer to each request
independently. The server **MAY NOT** have memory of any client capabilites, client
supported versions, or previous client interations.

Server requests and server notifications **MAY NOT** be implemented in **HTTP** _stateless_ transport.

When you say MAY NOT is that "must not" or "does not have to"? I think if server requests and server notifications were to be supported, and I think one could make an argument for it, it should be via polling a GET endpoint. Similar to how some streaming libraries emulate web sockets through polling.

If there is no defined mechanism for supporting polling for notifications and server requests, then I think it should be clearly defined as unsupported. That might be your intention here, but I think it reads somewhat confusingly at the moment. MAY NOT is strange if there is no way to do it.

@pcingola
Copy link
Author

pcingola commented Jan 29, 2025

Thank you for your comments @PederHP . I'll try to answer each of them below...

Not sure when I would use this transport, but I think I support the inclusion of a pure HTTP based transport.

Great, thank you for supporting it.
The use-case I was tihinnking about, was to easily scale servers that provide stateless tools.

Question:

 ...
Server requests and server notifications **MAY NOT** be implemented in **HTTP** _stateless_ transport.

When you say MAY NOT is that "must not" or "does not have to"? I think if server requests and server notifications were to be supported, and I think one could make an argument for it, it should be via polling a GET endpoint. Similar to how some streaming libraries emulate web sockets through polling.

Yes, the intention was "does not have to", because I was thinking in that line. I wanted to leave the door open to add "GET polling" endpoint (which is mentioned in the referred discussion), but I didn't want to overcomplicate this RFC by adding all those capabilities, and protocol negotiations.

If there is no defined mechanism for supporting polling for notifications and server requests, then I think it should be clearly defined as unsupported. That might be your intention here, but I think it reads somewhat confusingly at the moment. MAY NOT is strange if there is no way to do it.

I agree it can be confusing, but at the same time I didn't want to rule it completely out for the future changes.
As far as I understand, the protocol allows the server to mark the capability as "unsupported" during the initialization lifecycle (https://github.com/modelcontextprotocol/specification/blob/main/docs/specification/2024-11-05/basic/lifecycle.md), so this requires no change in the protocol specification. But, as you said, maybe it's better to add a clarification.

@jerome3o-anthropic
Copy link
Member

jerome3o-anthropic commented Feb 5, 2025

Thank you for the RFC @pcingola - I think this is mostly correct, however I think we should find a way to allow for the http transport to progressively add the other features (discussion here), so there is an onboarding ramp to adding the stateful features if the server creator decides to support it. From my initial read it looks like you don't prevent this from being added in the future, what are your thoughts on the progressive enhancement piece?

@pcingola
Copy link
Author

pcingola commented Feb 8, 2025

Thank @jerome3o-anthropic and @PederHP , and my apologies for the typos.

@pcingola
Copy link
Author

pcingola commented Feb 8, 2025

@jerome3o-anthropic: I've adedd a bit of language to make it more clear that we want to "allow for the http transport to progressively add the other features"

Reference: #102 (comment)

As also discussed in that thread (comments by @jspahrsummers) I've also added a sentence about making it easier for serv er disconnections on SSE transport.

Do you think this is ready to merge? Sorry to ask, I'm don't know how the review process works.

Copy link
Member

@jerome3o-anthropic jerome3o-anthropic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @pcingola, I really appreciate your time here. We've had lots of discussions about statelessness in the MCP team, and in various forums (mainly the gh discussion that you've contributed to) and our current disposition is toward something that:

  • Still has state (i.e. session id's, initialization handshakes)
  • Still has bidirectional communication via SSE, but
    • Doesn't require it for tool calls/resource reading (by using a base HTTP communication pattern like you've suggested).
    • Doesn't require long lived connections - the SSE connection is best effort (and servers could also buffer server messages when disconnected if they wanted)

We are converging on this view because we believe that MCP's stateful features are going to be what sets it apart in the longer term, and that bidirectionality and state will be necessary in a world full of AI agents.

We are also focusing most of our engineering effort at the moment on authentication related work (so that's why things have been slow here, apologies), but once we free up a bit after that I suspect we will focus on statelessness (hopefully soon). But that's why movement here is slow and that we haven't merged something like this yet.

Also note that having stateless and stateful variations of the protocol is a meaningful bifurcation and has big implications for the future of MCP, which is why we are hesitant to merge/commit to a pathway yet.

@pcingola
Copy link
Author

pcingola commented Feb 19, 2025

Hi @jerome3o-anthropic and @jspahrsummers,
Thank you fr your clarifications on this PR.

Similar to what you've said, my views on these topics are also evolving as I think more about them. As mentioned earlier, the problem is not about state but more on the burden of "long lived connections". So the approach of minimizing the requirements on connection times (e.g. making them best effort) and only requiring SSE when really needed is a sensible approach.

Given this, it's probably better to delete this PR altogether and start with a fresh one that emphasizes these suggestions. If this PR was useful to think about these concepts, I think it was time well invested.

I can try to help by starting a new PR more focused on these approaches (in a couple of weeks when you have a bit more time).

All the best and thank you for your feedback!

@jspahrsummers
Copy link
Member

jspahrsummers commented Feb 19, 2025

Thank you for taking the time to write this up and have the discussion! This has been a thorny, swirly discussion, and we're ultimately landing in quite a different place than where we started—but this is how it goes for complex things sometimes. 😄

I'll go ahead and close this, per your comment. We plan to put up an RFC soon that captures @jerome3o-anthropic's proposal, and we'd welcome your feedback there. ❤️

@jspahrsummers jspahrsummers moved this to Approved in Standards Track Mar 11, 2025
@jspahrsummers jspahrsummers moved this from Approved to Rejected in Standards Track Mar 11, 2025
jspahrsummers pushed a commit that referenced this pull request Mar 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: Rejected

Development

Successfully merging this pull request may close these issues.

4 participants