Skip to content

OpenAPI spec for official registry API #3

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

Merged
merged 10 commits into from
May 9, 2025
Merged

Conversation

tadasant
Copy link
Contributor

@tadasant tadasant commented Mar 28, 2025

This is a rough first pass at what the API shape should look like. Not meant to be final, we may not even merge this particular PR; just meant to give readers a sense of what we're going for to spark feedback conversations.

@tadasant
Copy link
Contributor Author

tadasant commented May 5, 2025

@sridharavinash I made a few changes I think are improvements:

df3ef54 - add a default_value field for EnvironmentVariable

1669e45 - rename CommandArguments to Command and allow for a name field (like npx, uvx, etc; so it's explicit what the command arguments are tied to)

52cf2c1 - simplify the notion of Repository. Original PR was from back when we were planning to tightly couple source code to our MCP server concept, but the DNS-based naming approach as superseded that.

50d22a9 - renamed registries and registry_canonical to packages and package_canonical; realized that naming makes a lot more sense

e9ad735 - removed license field; unnecessary denormalized data.

@tadasant tadasant changed the title [WIP] OpenAPI spec for official registry API OpenAPI spec for official registry API May 5, 2025
Copy link
Contributor

@sridharavinash sridharavinash left a comment

Choose a reason for hiding this comment

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

Minor nits/ clarifications, nothing blocking .

schema:
type: string
format: uuid
- name: version
Copy link
Contributor

Choose a reason for hiding this comment

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

I reviewed the current Go implementation and noticed that a UUID is generated every time an MCP server is published, ensuring that each version of an MCP server has a unique ID.

However, it seems that the id here is associated only with the MCP server itself, rather than with the server + version, which is causing some confusion for me.

And I think the current specification is more reasonable for a clear semantic understanding.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The implementation is very much a work in progress, so it's probably just a bug, but cc @sridharavinash to confirm

@sandy081
Copy link
Collaborator

sandy081 commented May 8, 2025

@tadasant / @sridharavinash

May I know if the server definition supports a required publisher property? I remember @sridharavinash mentioning that this can be derived from the repository owner or org. If so then it makes sense that the server registry populates the publisher information in the server list and server response.

@tadasant
Copy link
Contributor Author

tadasant commented May 8, 2025

@tadasant / @sridharavinash

May I know if the server definition supports a required publisher property? I remember @sridharavinash mentioning that this can be derived from the repository owner or org. If so then it makes sense that the server registry populates the publisher information in the server list and server response.

There was no current plan to include a publisher property -- it is just implied through the reverse-DNS name field. If you think it would be helpful to include, I would suggest opening a Discussion as that would be some net new requirements work that I think it'd be helpful to get more input on.

@sandy081
Copy link
Collaborator

sandy081 commented May 8, 2025

There was no current plan to include a publisher property -- it is just implied through the reverse-DNS name field.

Is the name field meant for the name of the MCP server, eg: @modelcontextprotocol/server-filesystem in which case the owner/publisher would be modelcontextprotocol right? If so, it would be helpful if the server registry resolves this information into a separate property with necessary details like publisher and publisherDisplayName, for eg

"publisher": {
    "name": "modelcontextprotocol",
    "displayName": "Model Context Protocol",
    "verified": true
}

I think the registry is the right one to resolve this information and leaving this to clients could cause falsy information. It is important for a user to know the publisher/owner of an MCP server. Hence it would be great if this can be included in the initial version.

@tadasant
Copy link
Contributor Author

tadasant commented May 9, 2025

Thanks for all the feedback so far @alexhancock @connor4312 @sandy081 @luoxiner @annaji-msft

I am thinking we have covered a good amount of breadth to start, and at this point there need to be some more detailed discussions about specific points, and it's feeling unwieldy to try to handle in a single monster PR here.

How would you all feel if we merged this OpenAPI spec and then spun up separate PR's/Issues to drill down on the open questions we've identified?

Specifically:

  • Incorporating OAuth details into the remote servers shape (@annaji-msft). This is probably noncontroversial, just needs to be worked through.
  • Incorporating headers for remotes (@connor4312). This is probably noncontroversial, just needs to be worked through.
  • Consider including "marketing" data, like displayName and icon. I had initially thought displayName might make sense, but I am now leaning towards thinking we should exclude both. Can share my thoughts in an Issue, would like to get more opinions on this one (@sandy081)
  • Consider including publisher data. Can discuss more in an issue, but I think there a major issues here with the notion of "trust". We actually have no guarantees that the publisher is who they say they are. We've got the reverse DNS system planned, but all that is is the namespace. (@sandy081)
  • Figuring out the proper way to model commands. I'm starting to think we should simplify into a templating approach. (@connor4312 @alexhancock @sandy081)

Besides these above open points, I've addressed feedback on the other comments.

If you all think it's a good idea to merge this and start to separate out the discussions, I'll start an Issue for each of these, and if someone is eager to finalize they can open a PR without being blocked on me. Does that work?

cc @toby @digitarald

@evalstate
Copy link

Thanks @tadasant -- this is brilliant work btw. I was going to ask how to contribute, so I definitely +1 on getting this merged.

@connor4312
Copy link
Collaborator

connor4312 commented May 9, 2025

Figuring out the #3 (comment). I'm starting to think we should simplify into a templating approach.

I considered this in my initial draft of how a registry manifest would work. I thought of templating args, environment variables, and headers ('inputs') with Mustache-like syntax:

"docker": {
  "configuration": {
    "required": ["github-token"],
    "github-token": {
      "type": "string",
      "description": "GitHub Personal Access Token",
      "secret": true
    }
  },
  "name": "ghcr.io/github/github-mcp-server",
  "args": ["-e", "GITHUB_TOKEN"],
  "env": { "GITHUB_TOKEN": "{{github-token}}" }
}

In my initial draft I stated that inputs that reference an optional configuration that's missing would be omitted. (Is this is enough? I'm not sure.) Then there are the usual niggles with templating, like how we handle escaping and so on. Configuration being a JSON schema object gives some more power but opens up to nested objects and arrays and I'm not sure how/if those should be handled (or if we'd spec it such that only primitives are allowed.) It also doesn't map cleanly onto repeated arguments unless we get deep into the weeds of templating.

Overall I liked the explicit version more. It kept the world better-bounded and gave clear answers to the above unknowns. Sandeep linked roughly where we ended up on our version of the spec.

I think docker mounts overall may need formal specification. Many clients, like VS Code, will have the notion of the "workspace folder" which is probably what the user wants to mount by default into their container. And additionally thinking of a world where we specify the arguments for the server and not the runtime (i.e. not npx/uvx/docker), perhaps the config for the filesystem server just looks like

  "packages": [
    {
      "registry_name": "docker",
      "name": "mcp/filesystem",
      "version": "1.0.2",
      "command": {
        "name": "docker",
        "mounts": [
          {
            "description": "Folder to serve as the root of the filesystem",
            "default_flags": "ro",
            "default_mount_point": "/projects",
            "repeated": true,
          }
        ],
        "positional_arguments": [
          {
            "name": "root_path",
            "description": "Root path for filesystem access",
            "default_value": "/projects"
          }
        ]
      }
    }
  ]
}

... where the default_mount_point corresponds to the default of the positional argument which should be good enough hint for users to know what to do (or even for clients to correlate them automatically.)

This also can let us guarentee as a client that we won't have unintended side-effects for the host and can basically run Docker containers without requiring super explicit "are you sure you want to run this untrusted command from the internet on your computer" confirmations. Versus a template, we control the docker command that's executed and the mounts that it's given, so we can ensure it doesn't just try and mounnt ~/.ssh/id_rsa and do bad stuff.

Copy link
Collaborator

@digitarald digitarald left a comment

Choose a reason for hiding this comment

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

LGTM based on #3 (comment)

@tadasant tadasant merged commit b005e9c into main May 9, 2025
1 check failed
@tadasant tadasant deleted the tadasant/openapi-spec branch May 9, 2025 19:22
@tadasant
Copy link
Contributor Author

tadasant commented May 9, 2025

Follow-ups:

If anyone wants to self-assign and drive any of this forward, please feel free. Unless I assign myself to an issue, I'm not actively working on it yet.

],
"positional_arguments": [
{
"position": 0,

Choose a reason for hiding this comment

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

Explicitly specifying the position as a key in the JSON seems like an anti-pattern given that the parent object (an array) is inherently ordered by nature.

What are your thoughts about this? Any chance I could open this up as a follow-up issue if you think it is pertinent?

Copy link
Collaborator

Choose a reason for hiding this comment

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

You may be interested in looking at this PR: #33

Choose a reason for hiding this comment

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

I did take a look and I think #33 may be simplifying the commands a little too much. However, I can move that discussion there instead.

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.