Repository navigation
Reflect the latest registry changes in openapi.yaml - #345
Conversation
| $ref: '#/components/schemas/KeyValueInput' | ||
| transport_type: | ||
| type: string | ||
| enum: [ streamable-http, sse, stdio ] |
There was a problem hiding this comment.
This isn't enough for a client to know how to consume the package -- http/sse packages will need to expose their URL too, perhaps through templated input that can reference their args/environment variables?
There was a problem hiding this comment.
I think that matches my assumption too. So far I've seen SSE/streamable-http servers typically allow you to set the port as an arg/env var (usually defaults to 8080) while the host usually comes from the runtime. And of course the rest of the path portion should follow the spec (e.g. /mcp, /sse, etc.).
I found this to be enough for clients to construct the URL, but I don't mind if you think we should have something more explicit, i.e. an additional templated property 👍
edit: The page refreshed right after I posted this and now I saw your next comment
There was a problem hiding this comment.
Assuming the default port and path might work for a toy client but it's not something that works for complex scenarios where a client manages multiple MCP servers concurrently for example.
Maybe for the template we do something like this:
# in the package -- allow including extra data within the transport type
transport_type:
anyOf:
- $ref: '#/components/schemas/StdioTransport'
- $ref: '#/components/schemas/HttpTransport'
# stdio definition is pretty easy/static
StdioTransport:
type: object
properties:
type:
type: string
enum: [stdio]
required:
- type
# http transport type is more involved. While this is similar to http packages,
# I don't think there's a reason to do input with headers for example, so there's no reuse
HttpTransport:
type: object
properties:
type:
type: string
enum: [http]
url:
type: string
example: http://{host}:{port}/my-server/mcp
description: |
Fully qualified URL for the streamable HTTP when the server is started. Clients should retry connecting to this URL as it may take some time for the server to be ready.
Identifiers wrapped in `{curly_braces}` should be looked up and replaced with the corresponding value of the input, based on the `value_hint` in PositionalArguments or the `name` in NamedArguments or KeyValueInput. The input's `default` value should be used if the input was not explicitly configured.
headers:
type: array
items:
- type: object
required:
- name
- value
properties:
name:
type: string
description: Name of the header.
example: SOME_VARIABLE
value:
type: string
description: Value of the header. Identifiers may be wrapped in `{curly_braces}` to reference existing variables, following the same rules at HttpTransport.url.
required:
- type
- urlThis would let it work to specify a URL or defaults based on the server's spawn arguments. The curly_braces format is reused from templated arguments, although the reference mechanic is new. This also works to do nonces (as I suggest below) if we add some tag like is_randomized on an argument.
SSE would basically be the same, but as SSE was removed from the spec back in June I'm not convinced we need to support it in new work going forward :)
There was a problem hiding this comment.
Yeah, I see your point now, I agree it's better to make this deterministic for clients 👍 I'll proceed with incorporating your feedback into this PR so we can keep the discussion here 👍 I'll probably address the URL part now and file an issue for the nonce part so we can do it in a follow up.
Thanks for your detailed replies, it is much appreciated! 🙏
There was a problem hiding this comment.
@connor4312 - hey, whenever you get a chance could you take another look? I've updated the PR description too to better match the changes.
|
Continuing from #340 (comment)
It is definitely necessary. Ports are not standardized and of course only one process can listen on a port. Nor are particular subpaths, such as We should also think about how we can ensure HTTP MCP servers running locally can be connected to securely. A common attack vector is escalation of privledge from services or users running on the same machine or network. Best practice for this kind of thing is to include a randomized nonce (be it a header, query string, or URL fragment -- a header is easiest for MCP) that the client and server share. So I suggest a means to include that as well when thinking about how the URL gets specified. |
214216a to
d652b59
Compare
| example: "streamable-http" | ||
| url: | ||
| type: string | ||
| format: uri |
There was a problem hiding this comment.
This technically might not be a uri format itself. After interpolation it should produce a URI, but the template string might not be a URI before that. E.g. it could just be {uri} if I have a server that takes a named argument --listen-on {uri}
There was a problem hiding this comment.
Thanks! I'll update that on both schemas since the server.json has it too 👍
|
API shape overall lgtm, will let others weigh in too :) |
596c876 to
13139f6
Compare
|
Did I miss a discussion somewhere about removing SSE? I'm not super strongly opposed, but I would guess something like 20-40% of remote servers in use in the wild today are still SSE. So it's a pretty significant move to not allow them in the registry. I totally agree with removing them for local (not a common use case, has security issues), but would have thought to keep them in remotes |
tadasant
left a comment
There was a problem hiding this comment.
Thanks for updating! Added some questions / suggestions.
Thanks for catching the bit about needing a URL for local streamable @connor4312 and @domdomegg, it's a good point. I would also not be opposed to just nixing HTTP-based local servers for now to cull down on our complexity here; I haven't seen a practical use case for that mode. Easy to just make the enum only allow stdio for now and add it later if folks present use cases.
| @@ -118,14 +118,15 @@ | |||
| ] | |||
| }, | |||
| "transport_type": { | |||
There was a problem hiding this comment.
This key feels out of place IMO -- can we just flatten it? i.e. instead of creating remote.transport_type.type and remote.transport_type.url, etc, we just have remote.transport_type, remote.url, etc.
There was a problem hiding this comment.
i.e. positioning as "remotes is an array of Transport, which is one of StreamableHttpTransport (or SSETransport, if we choose to re-add that; and perhaps soon WebSocketTransport pending that ongoing SEP)"
There was a problem hiding this comment.
This key feels out of place IMO -- can we just flatten it? i.e. instead of creating remote.transport_type.type and remote.transport_type.url, etc, we just have remote.transport_type, remote.url, etc.
I tried this initially, but it turned out to be messier in practice. Having a dedicated transport object for each option ended up being clearer as schema validation got tricky, i.e. there wasn’t really an easy way to enforce which fields should be present for a given transport type.
There was a problem hiding this comment.
I guess if we rename transport_type to just transport, this feels a lot better. Still a little odd that the only key in remote is transport, but maybe we'll come up with something in the future that needs to live on a Remote alongside transport that will make us happy we added the layer :)
There was a problem hiding this comment.
I tried this initially, but it turned out to be messier in practice. Having a dedicated transport object for each option ended up being clearer as schema validation got tricky, i.e. there wasn’t really an easy way to enforce which fields should be present for a given transport type.
I'm not sure I follow this - are you able to expand more on this difficulty? I think I agree with Tadas that remotes should just be an array of transports I think.
There was a problem hiding this comment.
I'm sorry, I see what you mean now 🤦
For some reason I read that as "let's keep up the old approach of having these properties under the remote object" instead of "replace the remote object with a list of transports".
Yes, your suggestion makes total sense! I'll implement it 🙏
| "registry_base_url": "https://docker.io", | ||
| "identifier": "mcp/filesystem", | ||
| "version": "1.0.2", | ||
| "transport_type": { |
There was a problem hiding this comment.
Seems like this would be better named:
| "transport_type": { | |
| "transport": { |
There was a problem hiding this comment.
Yeah, I prefer transport too, I'll be happy to rename it 👍
There was a problem hiding this comment.
Actually would it be okay if I address that in a follow-up? I think it’ll be easier to review separately and I don’t want to make this PR too heavy. I can jump on it right after this one’s merged so it shouldn’t cause any extra friction
| "format": "uri", | ||
| "description": "Remote server URL", | ||
| "example": "https://mcp-fs.example.com/sse" | ||
| "description": "URL template for the streamable-http transport. Variables in {curly_braces} reference argument value_hints, argument names, or environment variable names. After variable substitution, this should produce a valid URI.", |
There was a problem hiding this comment.
It seems a little odd to me to reach across other fields (value_hints, argument names, env vars) to fill out this url template. Should we consider keeping this consistent and just allowing for variable definitions adjacent to and/or inside url via KeyValueInput?
I think this is something that will be wanted eventually. HTTP servers can do extra things like OAuth (and form-based elicitations if that arrives in MCP) and we have an open feature request on VS Code to easily support spawnable MCP servers that use the HTTP transport. |
You're right, we didn't 👍 I did it based on @connor4312's feedback as I agree it feels right to start the registry by being compliant with the spec regarding this. That said I can easily revert it if we agree this might affect adoption and we want to support the deprecated SSE (at least for now).
Personally I think we should have this. Especially if we want to allow for enterprise adoption besides the desktop experience of running MCP servers, i.e. it would be better to run a streamable server instead of stdio. |
Got it, fair enough, I'll retract my thought of potentially culling them then; let's keep it.
We haven't yet been wielding the registry as a tool for pushing adoption of better practices (for example, we had a very brief idea like "maybe we should require all servers to have a docker image to standardize around that" way back that we shuttered), so I'm inclined to stick to that for now and optimize for registry adoption rather than try to thread a needle with this go live of easy-enough-to-adopt-but-still-pushing-better-practices. Probably should have added "meet the industry where it's currently at" as a design principle. Otherwise it's a slippery slope with making harder decisions like not allowing API Key headers and forcing all auth to be OAuth based. So I think we should keep SSE, at least in Remote, unless folks have strong objections. |
|
A few thoughts:
|
Yea, this is kind of nasty. In VS Code we have a ' |
|
Thank you all for reviewing and commenting this change, really appreciate it! 💯 In the interest of wrapping this up soon I'll summarise the remaining action items we agreed on that I have to address:
Let me know if I missed something 👍 In the meantime I'll make sure to address these (bring back SSE here + the rename on top of it) |
|
I think it's those two (bring back Happy to do it all in one PR - as long as you keep the commits separate think it's easier to reason about as one unit. |
Perfect 🙏 On it then 👍 |
Signed-off-by: Radoslav Dimitrov <[email protected]>
Signed-off-by: Radoslav Dimitrov <[email protected]>
Signed-off-by: Radoslav Dimitrov <[email protected]>
Signed-off-by: Radoslav Dimitrov <[email protected]>
Signed-off-by: Radoslav Dimitrov <[email protected]>
Signed-off-by: Radoslav Dimitrov <[email protected]>
8a33960 to
3b26f59
Compare
Signed-off-by: Radoslav Dimitrov <[email protected]>
35f8ec0 to
e1d368f
Compare
|
Alright, I've rebased the changes along with implementing the feedback items from above so it should be ready to review 👍 |
| // Validate transport type is supported | ||
| switch transport.Type { | ||
| case model.TransportTypeStdio: | ||
| // No additional validation needed for stdio - URL should be empty |
There was a problem hiding this comment.
do we want to validate the the url is empty?
| } | ||
|
|
||
| // validateTransport validates a remote transport (no templating allowed) | ||
| func validateTransport(obj *model.Transport) error { |
There was a problem hiding this comment.
maybe rename validateRemoteTransport or something?
domdomegg
left a comment
There was a problem hiding this comment.
lgtm - happy to merge now and then sort out the other two things as minor follow-ups?
|
@claude can you raise two separate PRs for the review comments above? if you get stuck instead raise an issue assigned to |
This comment was marked as off-topic.
This comment was marked as off-topic.
- Add StdioTransport, StreamableHttpTransport, SseTransport schema definitions - Add transport field to Package schema with support for all transport types - Update remotes to use transport objects instead of old Remote schema - Remove deprecated Remote schema - Add 'docker' to runtime_hint examples to match server.json schema This aligns the OpenAPI spec with the server.json schema structure that was updated in PR #345. Co-authored-by: adam jones <[email protected]>
- Add validation that URL must be empty for stdio transport types - Rename validateTransport to validateRemoteTransport for clarity - Update test case to expect error when stdio transport has URL This addresses feedback from PR #345 requesting stricter validation for stdio transports and better function naming. :house: Remote-Dev: homespace
|
➡️ followups in #365 |
## Summary - Add validation that URL must be empty for stdio transport types - Rename `validateTransport` to `validateRemoteTransport` for better clarity - Update corresponding test case to expect error when stdio transport has URL ## Context This addresses two specific feedback comments from @domdomegg on PR #345: 1. "do we want to validate the the url _is_ empty?" - Now validates URL is empty for stdio 2. "maybe rename validateRemoteTransport or something?" - Renamed function for clarity The changes enforce stricter validation while improving code readability through better naming.
|
@domdomegg - thanks for addressing the comments 🙏 Funny enough I must have lost the most important commit about applying the changes on the openapi schema while I was rebasing the changes at the end 😄 |
|
Should these changes (particularly changing the Remote schema type to Transport and adding transport to the Package) have been made to the "generic" OpenAPI spec also? https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/api/openapi.yaml I tend to use that one for generating my TypeScript client types, but noticed it doesn't have the package transport attribute. Happy to submit a PR if so (or defer to someone with more context). |
|
Yep @BobDickinson! As a side note maybe we should add tests to keep these all in sync? Seems like it should be possible to check that the Official MCP Registry API is some superset of the generic MCP registry API spec? ➡️ #567 |
Motivation and Context
The following PR:
transporttype used in Package and Remotesdockerto theruntime_hintexamplesThanks to @kkkarthik for spotting it! 🙏
How Has This Been Tested?
Ran the tests locally
Breaking Changes
Yes
Types of changes
Checklist
Additional context