Skip to content

Conversation

@kentcdodds
Copy link
Contributor

Motivation and Context

TL;DR: This updates the spec to this:

### Example: Full Capabilities Declaration

Client `initialize` request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-03-26",
    "capabilities": {
      "roots": { "listChanged": true },
      "sampling": {},
      "elicitation": {},
      "logging": {},
      "completions": {},
      "prompts": { "listChanged": true },
      "resources": { "subscribe": true, "listChanged": true },
      "tools": { "listChanged": true },
      "experimental": { "customFeature": {} }
    },
    "clientInfo": {
      "name": "ExampleClient",
      "version": "1.0.0"
    }
  }
}
```

Server `initialize` response:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-03-26",
    "capabilities": {
      "logging": {},
      "prompts": { "listChanged": true },
      "resources": { "subscribe": true, "listChanged": true },
      "tools": { "listChanged": true },
      "roots": { "listChanged": true },
      "sampling": {},
      "elicitation": {},
      "completions": {},
      "experimental": { "customServerFeature": {} }
    },
    "serverInfo": {
      "name": "ExampleServer",
      "version": "1.0.0"
    },
    "instructions": "Optional instructions for the client"
  }
}
```

This is for "progressive enhancement". For example, if a client doesn't support resources, then a tool should not respond with an embedded resource, but rather the value itself. But there's no way for a server to know whether a client supports resources without this change.

As the spec evolves and clients add support for more of the spec, there will always be features which the server/client may not support and for which a fallback may be appropriate.

How Has This Been Tested?

I have not tested this, but I would expect SDKs update their mechanism to list client capabilities to include those within this spec.

Breaking Changes

This adds some SHOULDs in places I think are appropriate.

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

#604

…f features in client and server capabilities
@hesreallyhim
Copy link
Contributor

One question I would like to pose is - why don't we include "list" on the capabilities? "list" is an implicit capability - if we are going in this direction, why not just have the capabilities object declare every capability explicitly, which then enumerates every possible message that the server/client will handle? The convention of this object, which is that foo: {} is the way we indicate "server supports foo" is to me counter-intuitive and concretely confusing in some cases. For some capabilities, it's taken for granted that, e.g., if you "support tools" then you will respond to "tools/list" - but I don't see that made explicit in the spec. Maybe the language of the spec can be adjusted, but the way it's phrased seems to me slightly open to interpretation:

However, implementations are free to expose tools through any interface pattern that suits their needs—the protocol itself does not mandate any specific user interaction model.

Regardless of the merits of that example, the point is we're basically relying on "common sense" (or on something written somewhere else in the protocol) that "supports tools" entails "handles tools/list requests" whereas "supports sampling" doesn't. IMO it would make for a more "logical" and readable system if you (or a really dumb machine) could derive the full set of messages that the server/client can handle from the capabilities object alone, and not rely on any implicit contextual knowledge. I don't want to delay this from getting merged, and probably nobody agrees with me, but that's my opinion, FWIW. 🫡

@kentcdodds
Copy link
Contributor Author

I agree. I think capabilities simply being an array of supported messages would be much simpler.

@kentcdodds
Copy link
Contributor Author

TL;DR: Make capabilities look something like this:

### Example: Full Capabilities Declaration

Client `initialize` request:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-03-26",
    "consumes": [
      "ping",
      "sampling/createMessage",
      "roots/list",
      "notifications/cancelled",
      "notifications/progress",
      "notifications/message",
      "notifications/resources/updated",
      "notifications/resources/list_changed",
      "notifications/tools/list_changed",
      "notifications/prompts/list_changed"
    ],
    "emits": [
      "ping",
      "initialize",
      "completion/complete",
      "logging/setLevel",
      "prompts/get",
      "prompts/list",
      "resources/list",
      "resources/templates/list",
      "resources/read",
      "resources/subscribe",
      "resources/unsubscribe",
      "tools/call",
      "tools/list",
      "notifications/cancelled",
      "notifications/progress",
      "notifications/initialized",
      "notifications/roots/list_changed"
    ],
    "clientInfo": {
      "name": "ExampleClient",
      "version": "1.0.0"
    }
  }
}
```

Server `initialize` response:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-03-26",
    "emits": [
      "ping",
      "sampling/createMessage",
      "roots/list",
      "notifications/cancelled",
      "notifications/progress",
      "notifications/message",
      "notifications/resources/updated",
      "notifications/resources/list_changed",
      "notifications/tools/list_changed",
      "notifications/prompts/list_changed"
    ],
    "consumes": [
      "ping",
      "initialize",
      "completion/complete",
      "logging/setLevel",
      "prompts/get",
      "prompts/list",
      "resources/list",
      "resources/templates/list",
      "resources/read",
      "resources/subscribe",
      "resources/unsubscribe",
      "tools/call",
      "tools/list",
      "notifications/cancelled",
      "notifications/progress",
      "notifications/initialized",
      "notifications/roots/list_changed"
    ],
    "serverInfo": {
      "name": "ExampleServer",
      "version": "1.0.0"
    },
    "instructions": "Optional instructions for the client"
  }
}
```

I don't particularly care about the names "emits" and "consumes", but this I think communicates the capaibilities well and it also helps ensure that as features continue to get added to the spec, this list will grow as well (hopefully the spec doesn't get so large that the size of this list is ever a problem, maybe the list itself could be a good deterrent to that happening).

@connor4312
Copy link
Contributor

connor4312 commented Jun 15, 2025

I'm less of a fan of the list idea. For the Debug Adapter Protocol, I just have one big bag of properties. While MCP currently is open to making breaking changes, DAP never makes a breaking change. Having an object of descriptive properties allows us to create specific behaviors of methods and control flows that are not simply tied to whether or not something is implemented.

For example, if a client doesn't support resources, then a tool should not respond with an embedded resource, but rather the value itself. But there's no way for a server to know whether a client supports resources without this change.

Specifically this kind of thing!

(MCP could always start adding more properties in addition to the lists, but their presence discourages granular capabilities and would lead to questions about intersecting behaviors if both are present.)


I like the idea of starting to build granular capabilities so that spec revisions and servers can work more gracefully in the future. Though I'm biased since that what I've done in the past ;) As of this PR I'm a little unsure the specific behaviors each capability should enable or disable. E.g. Is it implied that if a client doesn't support resources, the server should not return embedded resources? But is this always the case? Resources is a big area and a client might support them in some areas but not others.

In DAP, for any behavior that should vary by capability, we very explicitly state as such on each property/object type, and I think doing the same for MCP's capability set would be good if we start getting more detailed.

@kentcdodds
Copy link
Contributor Author

I'm not certain I understand what you're suggesting. Are you saying we just need to have more properties in the capabilities like embeddedResources to be more explicit?

@hesreallyhim
Copy link
Contributor

@connor4312 are you making a point about a list-structure vs a dict-structure? I prefer an object/dict more for direct lookups and such, but if so I see your point. Still would be good to know what you think about the broader idea of full enumeration vs partially implicit.

<Info>
As of the 2025-03-26 draft, both client and server SHOULD enumerate all
features they support in their `capabilities` object, not just a minimal
subset. This enables each side to tailor requests and responses to the other's
Copy link
Contributor

@hesreallyhim hesreallyhim Jun 15, 2025

Choose a reason for hiding this comment

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

Regarding "SHOULD", unfortunately it's a little more subtle than that... e.g.:

Servers that support tools MUST declare the tools capability

Whereas I think for other capabilities it's a SHOULD, e.g.:

When the list of available tools changes, servers that declared the listChanged capability SHOULD send a notification

I think this is unfortunate. Also, I think from a formal POV, automatic evaluation of compliance with a SHOULD is almost impossible, because it's a highly contextual definition, at least on my reading.

"SHOULD" means, to my understanding, "MUST do so unless there's a really good reason not to in a specific case and the reason pertains to interoperation or security" - well, that's pretty hard to describe in a type-system, e.g.

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 things could be made clearer if we reduced the number of SHOULDs overall. It's hard to think of a reason that has to do with interoperation and/or security whereby a server that supports X would not list it in their capabilities, or we could clarify and say something like "MUST declare the capability to all authorized parties" or "MUST declare the capability unless doing so compromises the security of the system"

| Client | `elicitation` | Support for server [elicitation](/specification/draft/client/elicitation) requests |
| Client | `logging` | Support for receiving [log messages](/specification/draft/server/utilities/logging) from the server |
| Client | `completions` | Support for [argument autocompletion](/specification/draft/server/utilities/completion) |
| Client | `prompts` | Support for [prompt templates](/specification/draft/server/prompts) |
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe instead of the "Supports..." wording, which I find somewhat non-specific, an alternative along the lines of: "Exposes resources to the client", "Exposes tools to the client." Or something even more concrete like "Responds to prompts requests", etc. I just think "Supports" is slightly lacking in precision.

| Client | `logging` | Support for receiving [log messages](/specification/draft/server/utilities/logging) from the server |
| Client | `completions` | Support for [argument autocompletion](/specification/draft/server/utilities/completion) |
| Client | `prompts` | Support for [prompt templates](/specification/draft/server/prompts) |
| Client | `resources` | Support for [resources](/specification/draft/server/resources) |
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: I don't see prompts, resources, or tools defined as client capabilities, even in the draft spec - is this an oversight or an innovation? I think it's a separate discussion, but whether a client "supports" resources (meaning, do they have any handlers related to resources, does the client's UI have anything to do with resources?) could actually be something that a server might be interested to know about

Copy link

Choose a reason for hiding this comment

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

I second this. I am currently struggling with this. Cursor client does not support resources, but there's no way for the server to know that. I am working around this right now by exposing the data as a resource and a tool. It would be better if the server knew how to structure itself to best serve the client.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is my problem precisely.

@MQ37
Copy link

MQ37 commented Aug 5, 2025

This would be a great feature for us at Apify. We are building the Apify Actor MCP server that allows discovering Actors in Apify Store , but we're struggling with client support for notifications/tools/list_changed.

The workflow is as follows: First, the user searches for an Actor. If they want to use an Actor from the store, they need to add it to the session using the add Actor tool. This then requires the client to support notifications/tools/list_changed, since it modifies the tools list and the client needs to re-fetch in order to use the new Actor tool.

Sadly, some clients, even the Claude desktop, still do not support this feature, and it would be great if we knew what to expect from the client. We could then, for example, instead of the add Actor tool, expose just a generic call Actor tool that allows a client to call any Actor without adding or modifying session tools.

FYI @jirispilka @jancurn

@mbleigh
Copy link
Contributor

mbleigh commented Aug 22, 2025

+1 that this is something I actively need for the Firebase MCP Server and another MCP project I'm working on. Otherwise it's impossible for servers to gracefully degrade support when a client doesn't utilize the major primitives. I support the original proposal at the top for its simplicity, although I might suggest perhaps something like:

// initialize request
{
  /** Capabilities the client is declaring it has. */
  capabilities: ClientCapabilities;
  /** Server capabilities the client is declaring it makes use of. */
  serverCapabilities?: ServerCapabilities;
}

// initialize response
{
  /** Capabilities the server is declaring it has. */
  capabilities: ServerCapabilities;
  /** Client capabilities the server is declaring it makes use of. */
  clientCapabilities?: ClientCapabilities;
}

I don't think MCP is going to get wide adoption of Prompts and Resources without some mechanism for graceful degradation. Tools are the only common denominator right now and so that's all people are building even though there are major drawbacks to stuffing everything full of tools.

Would really like to address this ASAP.

@kentcdodds
Copy link
Contributor Author

Now there's a formal SEP process. If you'd like to put together a SEP, I can put my support behind that and then we can get to putting something together.

@mbleigh
Copy link
Contributor

mbleigh commented Aug 22, 2025

Wrote up an SEP in #1381 -- would love to move this forward!

@kentcdodds
Copy link
Contributor Author

Closing in favor of discussion in #1381.

@kentcdodds kentcdodds closed this Aug 22, 2025
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.

6 participants