Skip to content
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

RFC Stateless #153

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

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

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.

@@ -103,8 +103,8 @@ The server **MUST** respond with its own capabilities and information:
}
```

After successful initialization, the client **MUST** send an `initialized` notification
to indicate it is ready to begin normal operations:
When using _statfull_ transports, after successful initialization, the client **MUST**
Copy link
Contributor

Choose a reason for hiding this comment

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

*stateful

Copy link
Author

Choose a reason for hiding this comment

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

Fixed typo, thank you.

If the server supports the requested protocol version, it **MUST** respond with the same
version. Otherwise, the server **MUST** respond with another protocol version it
supports. This **SHOULD** be the _latest_ version supported by the server.
For _statfull_ transports, if the server supports the requested protocol version, it
Copy link
Contributor

Choose a reason for hiding this comment

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

*stateful

Copy link
Author

Choose a reason for hiding this comment

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

Fixed typo, thank you.


Transports **stdio** and **SSE** are _statefull_ transports, while **HTTP** is _stateless_.
Copy link
Contributor

Choose a reason for hiding this comment

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

*stateful

Copy link
Author

Choose a reason for hiding this comment

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

Fixed typo, thank you.

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.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think from the discussion here, we want to have the http transport to allow progressive enhancement, meaning we should allow for the transport to (at it's lowest level of implementation) be stateless, with a progressive improvement pathway to start supporting additional parts of the protocol purely additively

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I fully agree.

@@ -209,8 +209,8 @@ capability **SHOULD** send a notification:

### Subscriptions

The protocol supports optional subscriptions to resource changes. Clients can subscribe
to specific resources and receive notifications when they change:
When _statfull_ transports are used, the protocol supports optional subscriptions to resource
Copy link
Contributor

Choose a reason for hiding this comment

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

*stateful

Copy link
Author

Choose a reason for hiding this comment

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

Typo fixed. Thank you

@jerome3o-anthropic
Copy link
Contributor

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?

@@ -103,8 +103,8 @@ The server **MUST** respond with its own capabilities and information:
}
```

After successful initialization, the client **MUST** send an `initialized` notification
to indicate it is ready to begin normal operations:
When using _statful_ transports, after successful initialization, the client **MUST**
Copy link

@PederHP PederHP Feb 8, 2025

Choose a reason for hiding this comment

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

statful should be stateful

If the server supports the requested protocol version, it **MUST** respond with the same
version. Otherwise, the server **MUST** respond with another protocol version it
supports. This **SHOULD** be the _latest_ version supported by the server.
For _statful_ transports, if the server supports the requested protocol version, it
Copy link

@PederHP PederHP Feb 8, 2025

Choose a reason for hiding this comment

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

statful should be stateful

@@ -209,8 +209,8 @@ capability **SHOULD** send a notification:

### Subscriptions

The protocol supports optional subscriptions to resource changes. Clients can subscribe
to specific resources and receive notifications when they change:
When _statful_ transports are used, the protocol supports optional subscriptions to resource
Copy link

Choose a reason for hiding this comment

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

statful should be stateful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants