Introduce serverId, rename id to versionId (#465)
Wielded Claude Code to do this; across many iterations and have reviewed all the code + largely rewritten the PR commentary here. This PR implements the server ID consistency changes from [#396](https://github.com/modelcontextprotocol/registry/issues/396). Our goal is to: - Rename `id` to `versionId` to make it clear that it is the ID for a specific version, not a server - Introduce `serverId` as a net new concept. This will be 1:1 with `name`. While not strictly necessary (we could just use name as a PK), the convention of having a UUID as an ID on our objects is just a helpful subjective architecture decision. Plus also leaves open the door to reconsidering the "should we allow renames" question. ## Key Changes ### 🗄️ Database Schema Changes - **Renamed**: `id` column → `version_id` (unique identifier for each server version) ### 📋 Metadata Structure Updates - **JSON Schema**: Updated `_meta.io.modelcontextprotocol.registry/official` to include: - `serverId`: Consistent ID across all versions of a server - `versionId`: Unique ID for this specific version (renamed from `id`) ### 🔧 API Endpoint Updates - **New endpoint structure**: Changed from version-ID-based to server-ID-based URLs: - `GET /v0/servers/{server_id}` - Get latest version of server - `GET /v0/servers/{server_id}?version=X.X.X` - Get specific version - `GET /v0/servers/{server_id}/versions` - List all versions of a server - `PUT /v0/servers/{server_id}?version=X.X.X` - Edit specific version - **Consistent URL patterns**: All server endpoints now use `server_id` as the primary identifier ### Database Migration Strategy The migration (`005_add_server_id_rename_version_id.sql`): 1. Adds new `version_id` column 2. Generates deterministic UUIDs for servers with the same name 3. Updates JSON metadata to add `serverId` and rename `id` to `versionId` 4. Copies existing `id` values to `version_id` column 5. Drops old `id` column and makes `version_id` the new primary key ## Testing Besides of course automated tests passing, I: 1. Set up my local db with the pre-005-migration state, imported all the production data 2. Ran the migration 3. Spot checked some diffs of the data that resulted -- ```json // before { "name": "io.github.ruvnet/ruv-swarm", "_meta": { "io.modelcontextprotocol.registry/official": { "id": "0a9cda7f-2b73-4839-844b-6582f335de42", "is_latest": false, "updated_at": "2025-09-10T17:21:34.92137012Z", "published_at": "2025-09-10T17:15:32.69690433Z" } }, "version": "1.0.18", "repository": { "url": "", "source": "" }, "description": "Neural network swarm orchestration with WebAssembly acceleration and MCP integration" } // after { "name": "io.github.ruvnet/ruv-swarm", "_meta": { "io.modelcontextprotocol.registry/official": { "serverId": "e8538952-96af-4a33-9e31-7fbed012521e", "is_latest": false, "versionId": "0a9cda7f-2b73-4839-844b-6582f335de42", "updated_at": "2025-09-10T17:21:34.92137012Z", "published_at": "2025-09-10T17:15:32.69690433Z" } }, "version": "1.0.18", "repository": { "url": "", "source": "" }, "description": "Neural network swarm orchestration with WebAssembly acceleration and MCP integration" } ``` Servers that have multiple versions stayed consistent in their `serverId`: ```json // First version { "name": "app.getdialer/dialer", "_meta": { "io.modelcontextprotocol.registry/official": { "serverId": "80f08bdb-f3e4-4f19-b072-1676ae49b663", "is_latest": false, "versionId": "04f25b17-331d-48d7-b08b-37baece208a7", "updated_at": "2025-09-09T00:16:49.162620072Z", "published_at": "2025-09-08T23:47:09.452137971Z" } }, "status": "active", "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json", "remotes": [ { "url": "https://getdialer.app/mcp", "type": "streamable-http" }, { "url": "https://getdialer.app/sse", "type": "sse" } ], "version": "1.0.0", "repository": { "url": "", "source": "" }, "description": "An MCP server that provides your you make outbound phone calls using your own phone number" } // Second version { "name": "app.getdialer/dialer", "_meta": { "io.modelcontextprotocol.registry/official": { "serverId": "80f08bdb-f3e4-4f19-b072-1676ae49b663", "is_latest": true, "versionId": "faa26cb9-3aad-415e-aece-f715fff5fe5e", "updated_at": "2025-09-09T00:16:49.107842808Z", "published_at": "2025-09-09T00:16:49.107842808Z" } }, "status": "active", "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json", "remotes": [ { "url": "https://getdialer.app/mcp", "type": "streamable-http" }, { "url": "https://getdialer.app/sse", "type": "sse" } ], "version": "1.0.1", "repository": { "url": "", "source": "" }, "description": "An MCP server that provides lets you make outbound phone calls using your own phone number" } ``` And I also tried publishing a test server anew; looked good: ```bash ⏺ Bash(curl -s "http://localhost:8080/v0/servers/102dc4e4-6ca8-40e6-aa11-cd45763d3352" | jq '.') ⎿ { "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json", "name": "io.modelcontextprotocol.anonymous/test-claude-migration-server", "description": "A test server to verify the new migration and API endpoints work correctly", "status": "active", "repository": { "url": "https://github.com/example/test-claude-migration-server", "source": "github", "id": "example/test-claude-migration-server" }, "version": "1.0.0", "_meta": { "io.modelcontextprotocol.registry/official": { "serverId": "102dc4e4-6ca8-40e6-aa11-cd45763d3352", "versionId": "48c9cd55-7bc4-4ac2-896e-59e81eb653e4", "published_at": "2025-09-12T18:33:23.264203-07:00", "updated_at": "2025-09-12T18:33:23.264203-07:00", "is_latest": true } } } ⏺ Bash(curl -s "http://localhost:8080/v0/servers/102dc4e4-6ca8-40e6-aa11-cd45763d3352/versions" | jq '.') ⎿ { "servers": [ { "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json", "name": "io.modelcontextprotocol.anonymous/test-claude-migration-server", "description": "A test server to verify the new migration and API endpoints work correctly", "status": "active", "repository": { "url": "https://github.com/example/test-claude-migration-server", "source": "github", "id": "example/test-claude-migration-server" }, "version": "1.0.0", "_meta": { "io.modelcontextprotocol.registry/official": { "serverId": "102dc4e4-6ca8-40e6-aa11-cd45763d3352", "versionId": "48c9cd55-7bc4-4ac2-896e-59e81eb653e4", "published_at": "2025-09-12T18:33:23.264203-07:00", "updated_at": "2025-09-12T18:33:23.264203-07:00", "is_latest": true } } } ], "metadata": { "count": 1 } } ``` Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Preeti Dewani <preetidewani1990@gmail.com> Co-authored-by: adam jones <adamj+git@anthropic.com> Co-authored-by: Adam Jones <adamj@anthropic.com>
This commit is contained in:
parent
52b1dc71b6
commit
56e8b4879b
4 changed files with 5185 additions and 3466 deletions
|
|
@ -16,31 +16,111 @@ This is a brief guide for admins and moderators managing content on the registry
|
|||
./tools/admin/auth.sh
|
||||
```
|
||||
|
||||
## Edit a Server
|
||||
## Edit a Specific Server Version
|
||||
|
||||
Step 1: Download Server
|
||||
Use this when you need to modify details of a specific version (e.g., fix description, update status, modify packages).
|
||||
|
||||
### Step 1: Download Specific Version
|
||||
|
||||
```bash
|
||||
export SERVER_ID="<server-uuid>"
|
||||
export SERVER_ID="<server-uuid>" # This is the server ID (consistent across versions)
|
||||
export VERSION="<version-string>" # e.g., "1.0.0" (optional, defaults to latest)
|
||||
|
||||
# Get specific version
|
||||
curl -s "https://registry.modelcontextprotocol.io/v0/servers/${SERVER_ID}?version=${VERSION}" > server.json
|
||||
|
||||
# Or get latest version (omit version parameter)
|
||||
curl -s "https://registry.modelcontextprotocol.io/v0/servers/${SERVER_ID}" > server.json
|
||||
```
|
||||
|
||||
Step 2: Open `server.json` and make changes. You cannot change the server name.
|
||||
### Step 2: Make Changes
|
||||
|
||||
Step 3: Push Changes
|
||||
Open `server.json` and edit the specific version details. You cannot change the server name or version number.
|
||||
|
||||
### Step 3: Update Version
|
||||
|
||||
```bash
|
||||
curl -X PUT "https://registry.modelcontextprotocol.io/v0/servers/${SERVER_ID}" \
|
||||
# Update specific version
|
||||
curl -X PUT "https://registry.modelcontextprotocol.io/v0/servers/${SERVER_ID}?version=${VERSION}" \
|
||||
-H "Authorization: Bearer ${REGISTRY_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"server\": $(cat server.json)}"
|
||||
-d "$(cat server.json)"
|
||||
|
||||
```
|
||||
|
||||
## Takedown a Server
|
||||
## Edit an Entire Server (All Versions)
|
||||
|
||||
Use this when you need to apply changes across all versions of a server (e.g., mark entire server as deleted, apply content scrubbing).
|
||||
|
||||
### Step 1: List All Versions
|
||||
|
||||
```bash
|
||||
export SERVER_ID="<server-uuid>" # This is the server ID (consistent across versions)
|
||||
curl -s "https://registry.modelcontextprotocol.io/v0/servers/${SERVER_ID}/versions" > all_versions.json
|
||||
```
|
||||
|
||||
### Step 2: Extract Version IDs
|
||||
|
||||
```bash
|
||||
# Extract all version IDs from the server
|
||||
jq -r '.servers[]._meta."io.modelcontextprotocol.registry/official".version_id' all_versions.json > version_ids.txt
|
||||
```
|
||||
|
||||
### Step 3: Apply Changes to All Versions
|
||||
|
||||
```bash
|
||||
# For each version, download, modify, and update
|
||||
while read VERSION_ID; do
|
||||
echo "Processing version: $VERSION_ID"
|
||||
curl -s "https://registry.modelcontextprotocol.io/v0/servers/${VERSION_ID}" > temp_version.json
|
||||
|
||||
# Apply your changes here (e.g., set status to "deleted")
|
||||
jq '.status = "deleted"' temp_version.json > modified_version.json
|
||||
|
||||
curl -X PUT "https://registry.modelcontextprotocol.io/v0/servers/${VERSION_ID}" \
|
||||
-H "Authorization: Bearer ${REGISTRY_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"server\": $(cat modified_version.json)}"
|
||||
done < version_ids.txt
|
||||
|
||||
# Clean up temporary files
|
||||
rm temp_version.json modified_version.json version_ids.txt all_versions.json
|
||||
```
|
||||
|
||||
## Quick Operations
|
||||
|
||||
### Get Latest Version of a Server
|
||||
|
||||
```bash
|
||||
export SERVER_ID="<server-uuid>"
|
||||
curl -s "https://registry.modelcontextprotocol.io/v0/servers/${SERVER_ID}" > latest_version.json
|
||||
export VERSION_ID=$(jq -r '._meta."io.modelcontextprotocol.registry/official".version_id' latest_version.json)
|
||||
echo "Latest version ID: $VERSION_ID"
|
||||
```
|
||||
|
||||
### Takedown a Specific Version
|
||||
|
||||
```bash
|
||||
export VERSION_ID="<version-uuid>"
|
||||
./tools/admin/takedown.sh
|
||||
```
|
||||
|
||||
This soft deletes the server. If you need to delete the content of a server (usually only where legally necessary), use the edit workflow above to scrub it all.
|
||||
### Takedown an Entire Server (All Versions)
|
||||
|
||||
```bash
|
||||
export SERVER_ID="<server-uuid>"
|
||||
# Get all version IDs and takedown each one
|
||||
curl -s "https://registry.modelcontextprotocol.io/v0/servers/${SERVER_ID}/versions" | \
|
||||
jq -r '.servers[]._meta."io.modelcontextprotocol.registry/official".version_id' | \
|
||||
while read VERSION_ID; do
|
||||
echo "Taking down version: $VERSION_ID"
|
||||
./tools/admin/takedown.sh "$VERSION_ID"
|
||||
done
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Version-specific changes**: Only affect that particular version
|
||||
- **Server-wide changes**: Must be applied to each version individually
|
||||
- **Content scrubbing**: Use the version-specific edit workflow to scrub sensitive content
|
||||
- **Server name**: Cannot be changed in any version (it's the immutable identifier)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ Integration patterns and best practices for building applications that consume M
|
|||
**Authentication**: Not required for read-only access
|
||||
|
||||
- **`GET /v0/servers`** - List all servers with pagination
|
||||
- **`GET /v0/servers/{id}`** - Get server details by UUID
|
||||
- **`GET /v0/servers/{server_id}`** - Get latest version of server by server ID
|
||||
- **`GET /v0/servers/{server_id}?version=X.X.X`** - Get specific version of server
|
||||
- **`GET /v0/servers/{server_id}/versions`** - List all versions of a server
|
||||
|
||||
See the [interactive API documentation](https://registry.modelcontextprotocol.io/docs) for complete request/response schemas.
|
||||
|
||||
|
|
@ -18,7 +20,7 @@ See the [interactive API documentation](https://registry.modelcontextprotocol.io
|
|||
## Building a subregistry
|
||||
**Create enhanced registries** - ETL official registry data and add your own metadata like ratings, security scans, or compatibility info.
|
||||
|
||||
For now we recommend scraping the `GET /v0/servers` endpoint on some regular basis. In the future we might provide a filter for updated_at ([#291](https://github.com/modelcontextprotocol/registry/issues/291)) to get only recently changed servers.
|
||||
For now we recommend scraping the `GET /v0/servers` endpoint on some regular basis. In the future we might provide a filter for updatedAt ([#291](https://github.com/modelcontextprotocol/registry/issues/291)) to get only recently changed servers.
|
||||
|
||||
Servers are generally immutable, except for the `status` field which can be updated to `deleted` (among other states). For these packages, we recommend you also update the status field to `deleted` or remove the package from your registry quickly. This is because this status generally indicates it has violated our permissive [moderation guidelines](../administration/moderation-guidelines.md), suggesting it is illegal, malware or spam.
|
||||
|
||||
|
|
@ -30,14 +32,14 @@ You can also add custom metadata to servers using the `_meta` field. For example
|
|||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json",
|
||||
"name": "io.github.yourname/weather-server",
|
||||
"description": "MCP server for weather data access",
|
||||
"status": "active",
|
||||
"version": "1.0.0",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registryType": "npm",
|
||||
"identifier": "weather-mcp-server",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ The MCP Registry project is a **metaregistry**, meaning that it hosts metadata f
|
|||
|
||||
For local MCP servers, the MCP Registry has pointers in the `packages` node of the [`server.json`](../../reference/server-json/generic-server-json.md) schema that refer to packages in supported package managers.
|
||||
|
||||
The list of supported package managers for hosting MCP servers is defined by the `properties.packages[N].properties.registry_type` string enum in the [`server.json` schema](../../reference/server-json/server.schema.json). For example, this could be "npm" (for npmjs.com packages) or "pypi" (for PyPI packages).
|
||||
The list of supported package managers for hosting MCP servers is defined by the `properties.packages[N].properties.registryType` string enum in the [`server.json` schema](../../reference/server-json/server.schema.json). For example, this could be "npm" (for npmjs.com packages) or "pypi" (for PyPI packages).
|
||||
|
||||
For remote MCP servers, the package registry is not relevant. The MCP client consumes the server via a URL instead of by downloading and running a package. In other words, this document only applies to local MCP servers.
|
||||
|
||||
|
|
@ -34,13 +34,13 @@ These steps may evolve as additional validations or details are discovered and m
|
|||
- Example for NuGet: https://github.com/modelcontextprotocol/registry/issues/126
|
||||
1. Open a PR with the following changes:
|
||||
- Update the [`server.json` schema](../../reference/server-json/server.schema.json)
|
||||
- Add your package registry name to the `registry_type` example array.
|
||||
- Add your package registry base url to the `registry_base_url` example array.
|
||||
- Add the single-shot CLI command name to the `runtime_hint` example value array.
|
||||
- Add your package registry name to the `registryType` example array.
|
||||
- Add your package registry base url to the `registryBaseUrl` example array.
|
||||
- Add the single-shot CLI command name to the `runtimeHint` example value array.
|
||||
- Update the [`openapi.yaml`](../../reference/api/openapi.yaml)
|
||||
- Add your package registry name to the `registry_type` enum value array.
|
||||
- Add your package registry base url to the `registry_base_url` enum value array.
|
||||
- Add the single-shot CLI command name to the `runtime_hint` example value array.
|
||||
- Add your package registry name to the `registryType` enum value array.
|
||||
- Add your package registry base url to the `registryBaseUrl` enum value array.
|
||||
- Add the single-shot CLI command name to the `runtimeHint` example value array.
|
||||
- Add a sample, minimal `server.json` to the [`server.json` examples](../../reference/server-json/generic-server-json.md).
|
||||
- Implement a registry validator:
|
||||
- Create a new validator file: `internal/validators/registries/yourregistry.go`, following the pattern of existing validators. Examples:
|
||||
|
|
|
|||
|
|
@ -92,13 +92,13 @@ This creates a `server.json` with auto-detected values. You'll see something lik
|
|||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json",
|
||||
"name": "io.github.yourname/your-server",
|
||||
"description": "A description of your MCP server",
|
||||
"version": "1.0.0",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registryType": "npm",
|
||||
"identifier": "your-package-name",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
|
@ -151,7 +151,7 @@ Add an `mcpName` field to your `package.json`:
|
|||
"name": "io.github.username/server-name",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registryType": "npm",
|
||||
"identifier": "your-npm-package",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
|
@ -183,7 +183,7 @@ Add it to your README.md file (which becomes the package description on PyPI). T
|
|||
"name": "io.github.username/server-name",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "pypi",
|
||||
"registryType": "pypi",
|
||||
"identifier": "your-pypi-package",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
|
@ -215,7 +215,7 @@ Add a README file to your NuGet package that includes the server name. This can
|
|||
"name": "io.github.username/server-name",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "nuget",
|
||||
"registryType": "nuget",
|
||||
"identifier": "Your.NuGet.Package",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
|
@ -251,8 +251,8 @@ LABEL io.modelcontextprotocol.server.name="io.github.username/server-name"
|
|||
"name": "io.github.username/server-name",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "oci",
|
||||
"registry_base_url": "https://docker.io",
|
||||
"registryType": "oci",
|
||||
"registryBaseUrl": "https://docker.io",
|
||||
"identifier": "yourusername/your-mcp-server",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
|
@ -266,8 +266,8 @@ LABEL io.modelcontextprotocol.server.name="io.github.username/server-name"
|
|||
"name": "io.github.username/server-name",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "oci",
|
||||
"registry_base_url": "https://ghcr.io",
|
||||
"registryType": "oci",
|
||||
"registryBaseUrl": "https://ghcr.io",
|
||||
"identifier": "yourusername/your-mcp-server",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
|
@ -302,9 +302,9 @@ openssl dgst -sha256 server.mcpb
|
|||
"name": "io.github.username/server-name",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "mcpb",
|
||||
"registryType": "mcpb",
|
||||
"identifier": "https://github.com/you/your-repo/releases/download/v1.0.0/server.mcpb",
|
||||
"file_sha256": "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce"
|
||||
"fileSha256": "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -337,7 +337,7 @@ Add the `remotes` field to your `server.json` (can coexist with `packages`):
|
|||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json",
|
||||
"name": "com.yourcompany/api-server",
|
||||
"description": "Cloud-hosted MCP server for API operations",
|
||||
"version": "2.0.0",
|
||||
|
|
@ -388,8 +388,8 @@ Configure headers that clients should send when connecting:
|
|||
{
|
||||
"name": "X-API-Key",
|
||||
"description": "API key for authentication",
|
||||
"is_required": true,
|
||||
"is_secret": true
|
||||
"isRequired": true,
|
||||
"isSecret": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue