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
43 changed files with 5185 additions and 3466 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
|||
build/
|
||||
bin/
|
||||
tmp/
|
||||
|
||||
.db
|
||||
.env
|
||||
|
|
@ -11,4 +12,4 @@ validate-schemas
|
|||
coverage.out
|
||||
coverage.html
|
||||
deploy/infra/infra
|
||||
registry
|
||||
registry
|
||||
|
|
@ -301,7 +301,7 @@ func createServerJSON(
|
|||
|
||||
// Create server structure
|
||||
return apiv0.ServerJSON{
|
||||
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: name,
|
||||
Description: description,
|
||||
Status: model.StatusActive,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,17 @@ func PublishCommand(args []string) error {
|
|||
return fmt.Errorf("invalid server.json: %w", err)
|
||||
}
|
||||
|
||||
// Check for deprecated schema and recommend migration
|
||||
// Allow empty schema (will use default) but reject old schemas
|
||||
if serverJSON.Schema != "" && !strings.Contains(serverJSON.Schema, "2025-09-16") {
|
||||
return fmt.Errorf(`deprecated schema detected :%s.
|
||||
|
||||
Migrate to the current schema format for new servers.
|
||||
|
||||
📋 Migration checklist: https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/CHANGELOG.md#migration-checklist-for-publishers
|
||||
📖 Full changelog with examples: https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/CHANGELOG.md`, serverJSON.Schema)
|
||||
}
|
||||
|
||||
// Load saved token
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
|
|
@ -71,8 +82,8 @@ func PublishCommand(args []string) error {
|
|||
}
|
||||
|
||||
_, _ = fmt.Fprintln(os.Stdout, "✓ Successfully published")
|
||||
if serverID := response.GetID(); serverID != "" {
|
||||
_, _ = fmt.Fprintf(os.Stdout, "✓ Server Id %s", serverID)
|
||||
if serverID := response.GetServerID(); serverID != "" {
|
||||
_, _ = fmt.Fprintf(os.Stdout, "✓ Server Id %s version %s\n", serverID, response.Version)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
134
cmd/publisher/commands/publish_test.go
Normal file
134
cmd/publisher/commands/publish_test.go
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
package commands_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/modelcontextprotocol/registry/cmd/publisher/commands"
|
||||
apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0"
|
||||
"github.com/modelcontextprotocol/registry/pkg/model"
|
||||
)
|
||||
|
||||
func TestPublishCommand_DeprecatedSchema(t *testing.T) {
|
||||
// Create a temporary directory for test files
|
||||
tempDir, err := os.MkdirTemp("", "mcp-publisher-test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Change to temp directory
|
||||
originalDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get current dir: %v", err)
|
||||
}
|
||||
defer func() { _ = os.Chdir(originalDir) }()
|
||||
|
||||
if err := os.Chdir(tempDir); err != nil {
|
||||
t.Fatalf("Failed to change to temp dir: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
schema string
|
||||
expectError bool
|
||||
errorSubstr string
|
||||
}{
|
||||
{
|
||||
name: "deprecated 2025-07-09 schema should show warning",
|
||||
schema: "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
|
||||
expectError: true,
|
||||
errorSubstr: "deprecated schema detected",
|
||||
},
|
||||
{
|
||||
name: "current 2025-09-16 schema should pass validation",
|
||||
schema: "https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "empty schema should pass validation",
|
||||
schema: "",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "custom schema without 2025-07-09 should pass validation",
|
||||
schema: "https://example.com/custom.schema.json",
|
||||
expectError: true,
|
||||
errorSubstr: "deprecated schema detected",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Create test server.json with specific schema
|
||||
serverJSON := apiv0.ServerJSON{
|
||||
Schema: tt.schema,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
Status: model.StatusActive,
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/example/test",
|
||||
Source: "github",
|
||||
},
|
||||
Packages: []model.Package{
|
||||
{
|
||||
RegistryType: model.RegistryTypeNPM,
|
||||
RegistryBaseURL: model.RegistryURLNPM,
|
||||
Identifier: "@example/test-server",
|
||||
Version: "1.0.0",
|
||||
Transport: model.Transport{
|
||||
Type: model.TransportTypeStdio,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
jsonData, err := json.MarshalIndent(serverJSON, "", " ")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to marshal test JSON: %v", err)
|
||||
}
|
||||
|
||||
// Write server.json to temp directory
|
||||
serverFile := filepath.Join(tempDir, "server.json")
|
||||
if err := os.WriteFile(serverFile, jsonData, 0o600); err != nil {
|
||||
t.Fatalf("Failed to write server.json: %v", err)
|
||||
}
|
||||
|
||||
err = commands.PublishCommand([]string{})
|
||||
|
||||
if tt.expectError {
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for deprecated schema, but got none")
|
||||
return
|
||||
}
|
||||
if !strings.Contains(err.Error(), tt.errorSubstr) {
|
||||
t.Errorf("Expected error containing '%s', got: %v", tt.errorSubstr, err)
|
||||
}
|
||||
// Check that the error contains the migration links
|
||||
if !strings.Contains(err.Error(), "Migration checklist:") {
|
||||
t.Errorf("Expected error to contain migration checklist link")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "Full changelog with examples:") {
|
||||
t.Errorf("Expected error to contain changelog link")
|
||||
}
|
||||
} else {
|
||||
// For non-deprecated schemas, we expect the command to fail at auth step, not schema validation
|
||||
if err != nil && strings.Contains(err.Error(), "deprecated schema detected") {
|
||||
t.Errorf("Unexpected deprecated schema error for schema '%s': %v", tt.schema, err)
|
||||
}
|
||||
|
||||
// We expect auth errors for valid schemas since we don't have a token
|
||||
if err != nil && !strings.Contains(err.Error(), "not authenticated") && !strings.Contains(err.Error(), "failed to read token") {
|
||||
t.Logf("Expected auth error for valid schema, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up for next test
|
||||
os.Remove(serverFile)
|
||||
})
|
||||
}
|
||||
}
|
||||
6572
data/seed.json
6572
data/seed.json
File diff suppressed because it is too large
Load diff
|
|
@ -23,6 +23,7 @@ services:
|
|||
- MCP_REGISTRY_OIDC_EXTRA_CLAIMS=${MCP_REGISTRY_OIDC_EXTRA_CLAIMS:-[{"hd":"modelcontextprotocol.io"}]}
|
||||
- MCP_REGISTRY_OIDC_EDIT_PERMISSIONS=${MCP_REGISTRY_OIDC_EDIT_PERMISSIONS:-*}
|
||||
- MCP_REGISTRY_OIDC_PUBLISH_PERMISSIONS=${MCP_REGISTRY_OIDC_PUBLISH_PERMISSIONS:-*}
|
||||
- MCP_REGISTRY_ENABLE_REGISTRY_VALIDATION=${MCP_REGISTRY_ENABLE_REGISTRY_VALIDATION:-true}
|
||||
ports:
|
||||
- 8080:8080
|
||||
restart: "unless-stopped"
|
||||
|
|
|
|||
|
|
@ -58,14 +58,14 @@ If server authors expect to have multiple registry versions for the same package
|
|||
### For Semantic Versions
|
||||
The registry attempts to parse versions as semantic versions. If successful, it uses semantic version comparison rules to determine:
|
||||
- Version ordering in lists
|
||||
- Which version is marked as `is_latest`
|
||||
- Which version is marked as `isLatest`
|
||||
|
||||
### For Non-Semantic Versions
|
||||
If version parsing as semantic version fails:
|
||||
- The registry will always mark the version as latest (overriding any previous version)
|
||||
- Clients should fall back to using publish timestamp for ordering
|
||||
|
||||
**Important Note**: This behavior means that for servers with mixed semantic and non-semantic versions, the `is_latest` flag may not align with the total ordering. A non-semantic version published after semantic versions will be marked as latest, even if semantic versions are considered "higher" in the ordering.
|
||||
**Important Note**: This behavior means that for servers with mixed semantic and non-semantic versions, the `isLatest` flag may not align with the total ordering. A non-semantic version published after semantic versions will be marked as latest, even if semantic versions are considered "higher" in the ordering.
|
||||
|
||||
## Implementation Details
|
||||
|
||||
|
|
@ -73,13 +73,13 @@ If version parsing as semantic version fails:
|
|||
1. **Validation**: Versions are validated for uniqueness within a server name
|
||||
2. **Parsing**: The registry attempts to parse each version as semantic version
|
||||
3. **Comparison**: Uses semantic version rules when possible, falls back to timestamp
|
||||
4. **Latest Flag**: The `is_latest` field is set based on the comparison results
|
||||
4. **Latest Flag**: The `isLatest` field is set based on the comparison results
|
||||
|
||||
### Client Recommendations
|
||||
Registry clients SHOULD:
|
||||
1. Attempt to interpret versions as semantic versions when possible
|
||||
2. Use the following ordering rules:
|
||||
- If one version is marked as is_latest: it is later
|
||||
- If one version is marked as isLatest: it is later
|
||||
- If both versions are valid semver: use semver comparison
|
||||
- If neither are valid semver: use publish timestamp
|
||||
- If one is semver and one is not: semver version is considered higher
|
||||
|
|
@ -145,7 +145,7 @@ Existing servers with non-semantic versions will continue to work without change
|
|||
"version": "1.2.3",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registryType": "npm",
|
||||
"identifier": "@myorg/server",
|
||||
"version": "1.2.3"
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@ Existing servers with non-semantic versions will continue to work without change
|
|||
"version": "1.2.3-1",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registryType": "npm",
|
||||
"identifier": "@myorg/server",
|
||||
"version": "1.2.3"
|
||||
}
|
||||
|
|
@ -196,12 +196,12 @@ Version strategy options:
|
|||
"version": "1.3.0",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registryType": "npm",
|
||||
"identifier": "@myorg/server",
|
||||
"version": "1.3.0"
|
||||
},
|
||||
{
|
||||
"registry_type": "oci",
|
||||
"registryType": "oci",
|
||||
"identifier": "myorg/server",
|
||||
"version": "1.2.5"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
70
docs/reference/api/CHANGELOG.md
Normal file
70
docs/reference/api/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Registry API Changelog
|
||||
|
||||
Changes to the REST API endpoints and responses.
|
||||
|
||||
## 2025-09-16
|
||||
|
||||
### ⚠️ BREAKING CHANGES
|
||||
|
||||
#### Server ID Endpoints ([#396](https://github.com/modelcontextprotocol/registry/issues/396))
|
||||
|
||||
API endpoints updated for consistent server identification across versions.
|
||||
|
||||
**Problem:** Each server version had a unique ID, preventing version history tracking and server renaming.
|
||||
|
||||
**Solution:** Introduced consistent server identification across versions.
|
||||
|
||||
**Changed endpoints:**
|
||||
- `GET /v0/servers/{id}` → `GET /v0/servers/{server_id}`
|
||||
|
||||
**New endpoints:**
|
||||
- `GET /v0/servers/{server_id}/versions` - List all versions of a server
|
||||
- `GET /v0/servers/{server_id}?version=1.0.0` - Get specific version
|
||||
|
||||
**Changed response metadata:**
|
||||
- `_meta.*.id` → `_meta.*.serverId`
|
||||
- Added: `_meta.*.versionId`
|
||||
|
||||
#### Migration Examples
|
||||
|
||||
**Old Structure:**
|
||||
```json
|
||||
{
|
||||
"_meta": {
|
||||
"io.modelcontextprotocol.registry/official": {
|
||||
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"published_at": "2024-01-01T00:00:00Z",
|
||||
"is_latest": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**New Structure:**
|
||||
```json
|
||||
{
|
||||
"_meta": {
|
||||
"io.modelcontextprotocol.registry/official": {
|
||||
"serverId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"versionId": "773f9b2e-1a47-4c8d-b5e6-2f8d9c4a7b3e",
|
||||
"published_at": "2024-01-01T00:00:00Z",
|
||||
"is_latest": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Migration Checklist for API Consumers
|
||||
|
||||
- [ ] Update API endpoint URLs from `/v0/servers/{id}` to `/v0/servers/{server_id}`
|
||||
- [ ] Update code reading registry metadata from `id` to `serverId`/`versionId`
|
||||
- [ ] Add support for new `/v0/servers/{server_id}/versions` endpoint if needed
|
||||
- [ ] Update JSON parsing to expect camelCase field names
|
||||
- [ ] Test with new API responses
|
||||
|
||||
### Changed
|
||||
- OpenAPI spec version: `2025-07-09` → `2025-09-16`
|
||||
|
||||
## 2025-07-09
|
||||
|
||||
Initial release of the Registry API.
|
||||
|
|
@ -15,7 +15,9 @@ The official registry has some more endpoints and restrictions on top of this. S
|
|||
|
||||
### Core Endpoints
|
||||
- **`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
|
||||
- **`POST /v0/publish`** - Publish new server (optional, registry-specific authentication)
|
||||
|
||||
### Authentication
|
||||
|
|
|
|||
|
|
@ -58,4 +58,4 @@ Example: `GET /v0/servers?search=filesystem&updated_since=2025-08-01T00:00:00Z&v
|
|||
#### Admin endpoints
|
||||
- GET `/metrics` - Prometheus metrics endpoint
|
||||
- GET `/v0/health` - Basic health check endpoint
|
||||
- PUT `/v0/servers/{id}` - Edit existing server
|
||||
- PUT `/v0/servers/{server_id}?version=X.X.X` - Edit specific server version (version parameter required)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
openapi: 3.1.0
|
||||
jsonSchemaDialect: "https://json-schema.org/draft/2020-12/schema"
|
||||
$id: https://modelcontextprotocol.io/schemas/draft/2025-07-09/server-registry-openapi
|
||||
$id: https://modelcontextprotocol.io/schemas/draft/2025-09-16/server-registry-openapi
|
||||
info:
|
||||
title: MCP Server Registry API
|
||||
version: "2025-07-09"
|
||||
version: "2025-09-16"
|
||||
summary: API for discovering and accessing MCP server metadata
|
||||
description: |
|
||||
Specification for a theoretical REST API that serves up metadata about MCP servers.
|
||||
|
|
@ -36,21 +36,21 @@ paths:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ServerList'
|
||||
/v0/servers/{id}:
|
||||
/v0/servers/{server_id}:
|
||||
get:
|
||||
summary: Get MCP server details
|
||||
description: Returns detailed information about a specific MCP server
|
||||
description: Returns detailed information about a specific MCP server. Returns latest version by default, or specific version if version query parameter is provided.
|
||||
parameters:
|
||||
- name: id
|
||||
- name: server_id
|
||||
in: path
|
||||
required: true
|
||||
description: Unique ID of the server
|
||||
description: Unique server ID (consistent across all versions)
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
- name: version
|
||||
in: query
|
||||
description: Desired MCP server version
|
||||
description: Specific version to retrieve (e.g., "1.0.0"). If not provided, returns latest version.
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
|
|
@ -70,6 +70,35 @@ paths:
|
|||
error:
|
||||
type: string
|
||||
example: "Server not found"
|
||||
/v0/servers/{server_id}/versions:
|
||||
get:
|
||||
summary: List all versions of an MCP server
|
||||
description: Returns all available versions for a specific MCP server, ordered by publication date (newest first)
|
||||
parameters:
|
||||
- name: server_id
|
||||
in: path
|
||||
required: true
|
||||
description: Unique server ID (consistent across all versions)
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'200':
|
||||
description: A list of all versions for the server
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ServerList'
|
||||
'404':
|
||||
description: Server not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
example: "Server not found"
|
||||
/v0/publish:
|
||||
post:
|
||||
summary: Publish MCP server (Optional)
|
||||
|
|
@ -99,8 +128,8 @@ paths:
|
|||
source: "github"
|
||||
version: "1.0.2"
|
||||
packages:
|
||||
- registry_type: "npm"
|
||||
registry_base_url: "https://registry.npmjs.org"
|
||||
- registryType: "npm"
|
||||
registryBaseUrl: "https://registry.npmjs.org"
|
||||
identifier: "@modelcontextprotocol/server-filesystem"
|
||||
version: "1.0.2"
|
||||
_meta:
|
||||
|
|
@ -121,8 +150,8 @@ paths:
|
|||
source: "github"
|
||||
version: "1.0.0"
|
||||
packages:
|
||||
- registry_type: "npm"
|
||||
registry_base_url: "https://registry.npmjs.org"
|
||||
- registryType: "npm"
|
||||
registryBaseUrl: "https://registry.npmjs.org"
|
||||
identifier: "@example/mcp-demo-server"
|
||||
version: "1.0.0"
|
||||
_meta:
|
||||
|
|
@ -233,7 +262,7 @@ components:
|
|||
type: string
|
||||
example: "1.0.2"
|
||||
description: "Version string for this server. SHOULD follow semantic versioning (e.g., '1.0.2', '2.1.0-alpha'). Equivalent of Implementation.version in MCP specification."
|
||||
website_url:
|
||||
websiteUrl:
|
||||
type: string
|
||||
format: uri
|
||||
description: "Optional URL to the server's homepage, documentation, or project website. This provides a central link for users to learn more about the server. Particularly useful when the server has custom installation instructions or setup requirements."
|
||||
|
|
@ -269,7 +298,7 @@ components:
|
|||
Package:
|
||||
type: object
|
||||
properties:
|
||||
registry_type:
|
||||
registryType:
|
||||
type: string
|
||||
description: Registry type indicating how to download packages (e.g., 'npm', 'pypi', 'oci', 'nuget', 'mcpb')
|
||||
examples:
|
||||
|
|
@ -278,7 +307,7 @@ components:
|
|||
- "oci"
|
||||
- "nuget"
|
||||
- "mcpb"
|
||||
registry_base_url:
|
||||
registryBaseUrl:
|
||||
type: string
|
||||
format: uri
|
||||
description: Base URL of the package registry
|
||||
|
|
@ -299,25 +328,25 @@ components:
|
|||
type: string
|
||||
description: Package version
|
||||
example: "1.0.2"
|
||||
file_sha256:
|
||||
fileSha256:
|
||||
type: string
|
||||
description: SHA-256 hash of the package file for integrity verification.
|
||||
example: "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce"
|
||||
runtime_hint:
|
||||
runtimeHint:
|
||||
type: string
|
||||
description: A hint to help clients determine the appropriate runtime for the package. This field should be provided when `runtime_arguments` are present.
|
||||
description: A hint to help clients determine the appropriate runtime for the package. This field should be provided when `runtimeArguments` are present.
|
||||
examples: [npx, uvx, dnx]
|
||||
runtime_arguments:
|
||||
runtimeArguments:
|
||||
type: array
|
||||
description: A list of arguments to be passed to the package's runtime command (such as docker or npx). The `runtime_hint` field should be provided when `runtime_arguments` are present.
|
||||
description: A list of arguments to be passed to the package's runtime command (such as docker or npx). The `runtimeHint` field should be provided when `runtimeArguments` are present.
|
||||
items:
|
||||
$ref: '#/components/schemas/Argument'
|
||||
package_arguments:
|
||||
packageArguments:
|
||||
type: array
|
||||
description: A list of arguments to be passed to the package's binary.
|
||||
items:
|
||||
$ref: '#/components/schemas/Argument'
|
||||
environment_variables:
|
||||
environmentVariables:
|
||||
type: array
|
||||
description: A mapping of environment variables to be set when running the package.
|
||||
items:
|
||||
|
|
@ -329,7 +358,7 @@ components:
|
|||
description:
|
||||
description: A description of the input, which clients can use to provide context to the user.
|
||||
type: string
|
||||
is_required:
|
||||
isRequired:
|
||||
type: boolean
|
||||
default: false
|
||||
format:
|
||||
|
|
@ -346,7 +375,7 @@ components:
|
|||
The default value for the input. If this is not set, the user may be prompted to provide a value. If a value is set, it should not be configurable by end users.
|
||||
|
||||
Identifiers wrapped in `{curly_braces}` will be replaced with the corresponding properties from the input `variables` map. If an identifier in braces is not found in `variables`, or if `variables` is not provided, the `{curly_braces}` substring should remain unchanged.
|
||||
is_secret:
|
||||
isSecret:
|
||||
type: boolean
|
||||
description: Indicates whether the input is a secret value (e.g., password, token). If true, clients should handle the value securely.
|
||||
default: false
|
||||
|
|
@ -383,11 +412,11 @@ components:
|
|||
type: string
|
||||
enum: [positional]
|
||||
example: "positional"
|
||||
value_hint:
|
||||
valueHint:
|
||||
type: string
|
||||
description: An identifier-like hint for the value. This is not part of the command line, but can be used by client configuration and to provide hints to users.
|
||||
example: file_path
|
||||
is_repeated:
|
||||
isRepeated:
|
||||
type: boolean
|
||||
description: Whether the argument can be repeated multiple times in the command line.
|
||||
default: false
|
||||
|
|
@ -395,7 +424,7 @@ components:
|
|||
- required:
|
||||
- value
|
||||
- required:
|
||||
- value_hint
|
||||
- valueHint
|
||||
|
||||
NamedArgument:
|
||||
description: A command-line `--flag={value}`.
|
||||
|
|
@ -414,7 +443,7 @@ components:
|
|||
type: string
|
||||
description: The flag name, including any leading dashes.
|
||||
example: "--port"
|
||||
is_repeated:
|
||||
isRepeated:
|
||||
type: boolean
|
||||
description: Whether the argument can be repeated multiple times.
|
||||
default: false
|
||||
|
|
@ -468,7 +497,7 @@ components:
|
|||
type: string
|
||||
format: uri
|
||||
description: JSON Schema URI for this server.json format
|
||||
example: "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json"
|
||||
example: "https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json"
|
||||
packages:
|
||||
type: array
|
||||
items:
|
||||
|
|
@ -496,16 +525,22 @@ components:
|
|||
type: object
|
||||
description: Registry-specific metadata managed by the MCP registry system
|
||||
required:
|
||||
- id
|
||||
- serverId
|
||||
- versionId
|
||||
- published_at
|
||||
- updated_at
|
||||
- is_latest
|
||||
properties:
|
||||
id:
|
||||
serverId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique registry identifier for this server entry
|
||||
description: Consistent ID across all versions of a server
|
||||
example: "550e8400-e29b-41d4-a716-446655440000"
|
||||
versionId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique ID for this specific version
|
||||
example: "773f9b2e-1a47-4c8d-b5e6-2f8d9c4a7b3e"
|
||||
published_at:
|
||||
type: string
|
||||
format: date-time
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ mcp-publisher init [options]
|
|||
"version": "1.0.0",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registryType": "npm",
|
||||
"identifier": "detected-package-name",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
|
|
|||
126
docs/reference/server-json/CHANGELOG.md
Normal file
126
docs/reference/server-json/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
# Server JSON Schema Changelog
|
||||
|
||||
Changes to the server.json schema and format.
|
||||
|
||||
## 2025-09-16
|
||||
|
||||
### ⚠️ BREAKING CHANGES
|
||||
|
||||
#### Field Names: snake_case → camelCase ([#428](https://github.com/modelcontextprotocol/registry/issues/428))
|
||||
|
||||
All JSON field names standardized to camelCase. **All existing `server.json` files must be updated.**
|
||||
|
||||
**Changed fields:**
|
||||
- `registry_type` → `registryType`
|
||||
- `registry_base_url` → `registryBaseUrl`
|
||||
- `file_sha256` → `fileSha256`
|
||||
- `runtime_hint` → `runtimeHint`
|
||||
- `runtime_arguments` → `runtimeArguments`
|
||||
- `package_arguments` → `packageArguments`
|
||||
- `environment_variables` → `environmentVariables`
|
||||
- `is_required` → `isRequired`
|
||||
- `is_secret` → `isSecret`
|
||||
- `value_hint` → `valueHint`
|
||||
- `is_repeated` → `isRepeated`
|
||||
- `website_url` → `websiteUrl`
|
||||
|
||||
#### Migration Examples
|
||||
|
||||
**Package Configuration:**
|
||||
```json
|
||||
// OLD - Will be rejected
|
||||
{
|
||||
"packages": [{
|
||||
"registry_type": "npm",
|
||||
"registry_base_url": "https://registry.npmjs.org",
|
||||
"file_sha256": "abc123...",
|
||||
"runtime_hint": "node",
|
||||
"runtime_arguments": [...],
|
||||
"package_arguments": [...],
|
||||
"environment_variables": [...]
|
||||
}]
|
||||
}
|
||||
|
||||
// NEW - Required format
|
||||
{
|
||||
"packages": [{
|
||||
"registryType": "npm",
|
||||
"registryBaseUrl": "https://registry.npmjs.org",
|
||||
"fileSha256": "abc123...",
|
||||
"runtimeHint": "node",
|
||||
"runtimeArguments": [...],
|
||||
"packageArguments": [...],
|
||||
"environmentVariables": [...]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
**Arguments Configuration:**
|
||||
```json
|
||||
// OLD - Will be rejected
|
||||
{
|
||||
"runtime_arguments": [
|
||||
{
|
||||
"name": "port",
|
||||
"is_required": true,
|
||||
"is_repeated": false,
|
||||
"value_hint": "8080"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// NEW - Required format
|
||||
{
|
||||
"runtimeArguments": [
|
||||
{
|
||||
"name": "port",
|
||||
"isRequired": true,
|
||||
"isRepeated": false,
|
||||
"valueHint": "8080"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Environment Variables:**
|
||||
```json
|
||||
// OLD - Will be rejected
|
||||
{
|
||||
"environment_variables": [
|
||||
{
|
||||
"name": "API_KEY",
|
||||
"is_required": true,
|
||||
"is_secret": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// NEW - Required format
|
||||
{
|
||||
"environmentVariables": [
|
||||
{
|
||||
"name": "API_KEY",
|
||||
"isRequired": true,
|
||||
"isSecret": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Migration Checklist for Publishers
|
||||
|
||||
- [ ] Update your `server.json` files to use camelCase field names
|
||||
- [ ] Test server publishing with new CLI version
|
||||
- [ ] Update any automation scripts that reference old field names
|
||||
- [ ] Update documentation referencing old field names
|
||||
|
||||
#### Updated Schema Reference
|
||||
|
||||
🔗 **Current schema**: https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json
|
||||
|
||||
### Changed
|
||||
- Schema version: `2025-07-09` → `2025-09-16`
|
||||
|
||||
## 2025-07-09
|
||||
|
||||
Initial release of the server.json schema.
|
||||
|
|
@ -8,7 +8,7 @@ Also see:
|
|||
|
||||
## Browse the Complete Schema
|
||||
|
||||
**📋 View the full specification interactively**: Open [server.schema.json](./server.schema.json) in a schema viewer like [json-schema.app](https://json-schema.app/view/%23?url=https%3A%2F%2Fstatic.modelcontextprotocol.io%2Fschemas%2F2025-07-09%2Fserver.schema.json).
|
||||
**📋 View the full specification interactively**: Open [server.schema.json](./server.schema.json) in a schema viewer like [json-schema.app](https://json-schema.app/view/%23?url=https%3A%2F%2Fstatic.modelcontextprotocol.io%2Fschemas%2F2025-09-16%2Fserver.schema.json).
|
||||
|
||||
The schema contains all field definitions, validation rules, examples, and detailed descriptions.
|
||||
|
||||
|
|
@ -22,11 +22,11 @@ The official registry has some more restrictions on top of this. See the [offici
|
|||
|
||||
```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.modelcontextprotocol.anonymous/brave-search",
|
||||
"description": "MCP server for Brave Search API integration",
|
||||
"status": "active",
|
||||
"website_url": "https://anonymous.modelcontextprotocol.io/examples",
|
||||
"websiteUrl": "https://anonymous.modelcontextprotocol.io/examples",
|
||||
"repository": {
|
||||
"url": "https://github.com/modelcontextprotocol/servers",
|
||||
"source": "github"
|
||||
|
|
@ -34,19 +34,19 @@ The official registry has some more restrictions on top of this. See the [offici
|
|||
"version": "1.0.2",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registry_base_url": "https://registry.npmjs.org",
|
||||
"registryType": "npm",
|
||||
"registryBaseUrl": "https://registry.npmjs.org",
|
||||
"identifier": "@modelcontextprotocol/server-brave-search",
|
||||
"version": "1.0.2",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"environment_variables": [
|
||||
"environmentVariables": [
|
||||
{
|
||||
"name": "BRAVE_API_KEY",
|
||||
"description": "Brave Search API Key",
|
||||
"is_required": true,
|
||||
"is_secret": true
|
||||
"isRequired": true,
|
||||
"isSecret": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ For MCP servers located within a subdirectory of a larger repository (monorepo s
|
|||
|
||||
```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.modelcontextprotocol/everything",
|
||||
"description": "MCP server that exercises all the features of the MCP protocol",
|
||||
"status": "active",
|
||||
|
|
@ -81,8 +81,8 @@ For MCP servers located within a subdirectory of a larger repository (monorepo s
|
|||
"version": "0.6.2",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registry_base_url": "https://registry.npmjs.org",
|
||||
"registryType": "npm",
|
||||
"registryBaseUrl": "https://registry.npmjs.org",
|
||||
"identifier": "@modelcontextprotocol/everything",
|
||||
"version": "0.6.2",
|
||||
"transport": {
|
||||
|
|
@ -113,14 +113,14 @@ Suppose your MCP server application requires a `mcp start` CLI arguments to star
|
|||
"version": "0.4.0-beta",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "nuget",
|
||||
"registry_base_url": "https://api.nuget.org",
|
||||
"registryType": "nuget",
|
||||
"registryBaseUrl": "https://api.nuget.org",
|
||||
"identifier": "Knapcode.SampleMcpServer",
|
||||
"version": "0.4.0-beta",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"package_arguments": [
|
||||
"packageArguments": [
|
||||
{
|
||||
"type": "positional",
|
||||
"value": "mcp"
|
||||
|
|
@ -145,13 +145,13 @@ Suppose your MCP server application requires a `mcp start` CLI arguments to star
|
|||
}
|
||||
```
|
||||
|
||||
This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcpServer@0.4.0-beta -- mcp start` instead of the default `dnx Knapcode.SampleMcpServer@0.4.0-beta` (when no `package_arguments` are provided).
|
||||
This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcpServer@0.4.0-beta -- mcp start` instead of the default `dnx Knapcode.SampleMcpServer@0.4.0-beta` (when no `packageArguments` are provided).
|
||||
|
||||
### Filesystem Server with Multiple 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": "io.github.modelcontextprotocol/filesystem",
|
||||
"description": "Node.js server implementing Model Context Protocol (MCP) for filesystem operations.",
|
||||
"status": "active",
|
||||
|
|
@ -163,24 +163,24 @@ This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcp
|
|||
"version": "1.0.2",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registry_base_url": "https://registry.npmjs.org",
|
||||
"registryType": "npm",
|
||||
"registryBaseUrl": "https://registry.npmjs.org",
|
||||
"identifier": "@modelcontextprotocol/server-filesystem",
|
||||
"version": "1.0.2",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"package_arguments": [
|
||||
"packageArguments": [
|
||||
{
|
||||
"type": "positional",
|
||||
"value_hint": "target_dir",
|
||||
"valueHint": "target_dir",
|
||||
"description": "Path to access",
|
||||
"default": "/Users/username/Desktop",
|
||||
"is_required": true,
|
||||
"is_repeated": true
|
||||
"isRequired": true,
|
||||
"isRepeated": true
|
||||
}
|
||||
],
|
||||
"environment_variables": [
|
||||
"environmentVariables": [
|
||||
{
|
||||
"name": "LOG_LEVEL",
|
||||
"description": "Logging level (debug, info, warn, error)",
|
||||
|
|
@ -189,43 +189,43 @@ This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcp
|
|||
]
|
||||
},
|
||||
{
|
||||
"registry_type": "oci",
|
||||
"registry_base_url": "https://docker.io",
|
||||
"registryType": "oci",
|
||||
"registryBaseUrl": "https://docker.io",
|
||||
"identifier": "mcp/filesystem",
|
||||
"version": "1.0.2",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"runtime_arguments": [
|
||||
"runtimeArguments": [
|
||||
{
|
||||
"type": "named",
|
||||
"description": "Mount a volume into the container",
|
||||
"name": "--mount",
|
||||
"value": "type=bind,src={source_path},dst={target_path}",
|
||||
"is_required": true,
|
||||
"is_repeated": true,
|
||||
"isRequired": true,
|
||||
"isRepeated": true,
|
||||
"variables": {
|
||||
"source_path": {
|
||||
"description": "Source path on host",
|
||||
"format": "filepath",
|
||||
"is_required": true
|
||||
"isRequired": true
|
||||
},
|
||||
"target_path": {
|
||||
"description": "Path to mount in the container. It should be rooted in `/project` directory.",
|
||||
"is_required": true,
|
||||
"isRequired": true,
|
||||
"default": "/project"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"package_arguments": [
|
||||
"packageArguments": [
|
||||
{
|
||||
"type": "positional",
|
||||
"value_hint": "target_dir",
|
||||
"valueHint": "target_dir",
|
||||
"value": "/project"
|
||||
}
|
||||
],
|
||||
"environment_variables": [
|
||||
"environmentVariables": [
|
||||
{
|
||||
"name": "LOG_LEVEL",
|
||||
"description": "Logging level (debug, info, warn, error)",
|
||||
|
|
@ -296,20 +296,20 @@ This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcp
|
|||
"version": "0.5.0",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "pypi",
|
||||
"registry_base_url": "https://pypi.org",
|
||||
"registryType": "pypi",
|
||||
"registryBaseUrl": "https://pypi.org",
|
||||
"identifier": "weather-mcp-server",
|
||||
"version": "0.5.0",
|
||||
"runtime_hint": "uvx",
|
||||
"runtimeHint": "uvx",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"environment_variables": [
|
||||
"environmentVariables": [
|
||||
{
|
||||
"name": "WEATHER_API_KEY",
|
||||
"description": "API key for weather service",
|
||||
"is_required": true,
|
||||
"is_secret": true
|
||||
"isRequired": true,
|
||||
"isSecret": true
|
||||
},
|
||||
{
|
||||
"name": "WEATHER_UNITS",
|
||||
|
|
@ -350,20 +350,20 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
"version": "0.5.0",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "nuget",
|
||||
"registry_base_url": "https://api.nuget.org",
|
||||
"registryType": "nuget",
|
||||
"registryBaseUrl": "https://api.nuget.org",
|
||||
"identifier": "Knapcode.SampleMcpServer",
|
||||
"version": "0.5.0",
|
||||
"runtime_hint": "dnx",
|
||||
"runtimeHint": "dnx",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"environment_variables": [
|
||||
"environmentVariables": [
|
||||
{
|
||||
"name": "WEATHER_CHOICES",
|
||||
"description": "Comma separated list of weather descriptions to randomly select.",
|
||||
"is_required": true,
|
||||
"is_secret": false
|
||||
"isRequired": true,
|
||||
"isSecret": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -398,14 +398,14 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
"version": "3.1.0",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "oci",
|
||||
"registry_base_url": "https://docker.io",
|
||||
"registryType": "oci",
|
||||
"registryBaseUrl": "https://docker.io",
|
||||
"identifier": "example/database-manager-mcp",
|
||||
"version": "3.1.0",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"runtime_arguments": [
|
||||
"runtimeArguments": [
|
||||
{
|
||||
"type": "named",
|
||||
"name": "--network",
|
||||
|
|
@ -417,7 +417,7 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
"name": "-e",
|
||||
"value": "DB_TYPE={db_type}",
|
||||
"description": "Database type to connect to",
|
||||
"is_repeated": true,
|
||||
"isRepeated": true,
|
||||
"variables": {
|
||||
"db_type": {
|
||||
"description": "Type of database",
|
||||
|
|
@ -427,18 +427,18 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
"mongodb",
|
||||
"redis"
|
||||
],
|
||||
"is_required": true
|
||||
"isRequired": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"package_arguments": [
|
||||
"packageArguments": [
|
||||
{
|
||||
"type": "named",
|
||||
"name": "--host",
|
||||
"description": "Database host",
|
||||
"default": "localhost",
|
||||
"is_required": true
|
||||
"isRequired": true
|
||||
},
|
||||
{
|
||||
"type": "named",
|
||||
|
|
@ -448,22 +448,22 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
},
|
||||
{
|
||||
"type": "positional",
|
||||
"value_hint": "database_name",
|
||||
"valueHint": "database_name",
|
||||
"description": "Name of the database to connect to",
|
||||
"is_required": true
|
||||
"isRequired": true
|
||||
}
|
||||
],
|
||||
"environment_variables": [
|
||||
"environmentVariables": [
|
||||
{
|
||||
"name": "DB_USERNAME",
|
||||
"description": "Database username",
|
||||
"is_required": true
|
||||
"isRequired": true
|
||||
},
|
||||
{
|
||||
"name": "DB_PASSWORD",
|
||||
"description": "Database password",
|
||||
"is_required": true,
|
||||
"is_secret": true
|
||||
"isRequired": true,
|
||||
"isSecret": true
|
||||
},
|
||||
{
|
||||
"name": "SSL_MODE",
|
||||
|
|
@ -498,7 +498,7 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
|
||||
```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.modelcontextprotocol.anonymous/hybrid-mcp",
|
||||
"description": "MCP server available as both local package and remote service",
|
||||
"repository": {
|
||||
|
|
@ -509,15 +509,15 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
"version": "1.5.0",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registry_base_url": "https://registry.npmjs.org",
|
||||
"registryType": "npm",
|
||||
"registryBaseUrl": "https://registry.npmjs.org",
|
||||
"identifier": "@example/hybrid-mcp-server",
|
||||
"version": "1.5.0",
|
||||
"runtime_hint": "npx",
|
||||
"runtimeHint": "npx",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"package_arguments": [
|
||||
"packageArguments": [
|
||||
{
|
||||
"type": "named",
|
||||
"name": "--mode",
|
||||
|
|
@ -540,8 +540,8 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
{
|
||||
"name": "X-API-Key",
|
||||
"description": "API key for authentication",
|
||||
"is_required": true,
|
||||
"is_secret": true
|
||||
"isRequired": true,
|
||||
"isSecret": true
|
||||
},
|
||||
{
|
||||
"name": "X-Region",
|
||||
|
|
@ -592,11 +592,11 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
"version": "1.0.2",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "mcpb",
|
||||
"registry_base_url": "https://github.com",
|
||||
"registryType": "mcpb",
|
||||
"registryBaseUrl": "https://github.com",
|
||||
"identifier": "https://github.com/modelcontextprotocol/text-editor-mcpb/releases/download/v1.0.2/text-editor.mcpb",
|
||||
"version": "1.0.2",
|
||||
"file_sha256": "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce",
|
||||
"fileSha256": "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
}
|
||||
|
|
@ -622,25 +622,25 @@ This example shows an MCPB (MCP Bundle) package that:
|
|||
|
||||
### Embedded MCP inside a CLI tool
|
||||
|
||||
Some CLI tools bundle an MCP server, without a standalone MCP package or a public repository. In these cases, reuse the existing `packages` shape by pointing at the host CLI package and supplying the `package_arguments` and `runtime_hint` if needed to start the MCP server.
|
||||
Some CLI tools bundle an MCP server, without a standalone MCP package or a public repository. In these cases, reuse the existing `packages` shape by pointing at the host CLI package and supplying the `packageArguments` and `runtimeHint` if needed to start the MCP server.
|
||||
|
||||
```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.snyk/cli-mcp",
|
||||
"description": "MCP server provided by the Snyk CLI",
|
||||
"status": "active",
|
||||
"version": "1.1298.0",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registry_base_url": "https://registry.npmjs.org",
|
||||
"registryType": "npm",
|
||||
"registryBaseUrl": "https://registry.npmjs.org",
|
||||
"identifier": "snyk",
|
||||
"version": "1.1298.0",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"package_arguments": [
|
||||
"packageArguments": [
|
||||
{ "type": "positional", "value": "mcp" },
|
||||
{
|
||||
"type": "named",
|
||||
|
|
@ -657,15 +657,15 @@ Some CLI tools bundle an MCP server, without a standalone MCP package or a publi
|
|||
|
||||
### Server with Custom Installation Path
|
||||
|
||||
For MCP servers that follow a custom installation path or are embedded in applications without standalone packages, use the `website_url` field to direct users to setup documentation:
|
||||
For MCP servers that follow a custom installation path or are embedded in applications without standalone packages, use the `websiteUrl` field to direct users to setup documentation:
|
||||
|
||||
```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.modelcontextprotocol.anonymous/embedded-mcp",
|
||||
"description": "MCP server embedded in a Desktop app",
|
||||
"status": "active",
|
||||
"website_url": "https://anonymous.modelcontextprotocol.io/embedded-mcp-guide",
|
||||
"websiteUrl": "https://anonymous.modelcontextprotocol.io/embedded-mcp-guide",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
```
|
||||
|
|
@ -685,19 +685,19 @@ For MCP servers that follow a custom installation path or are embedded in applic
|
|||
"version": "0.9.5",
|
||||
"packages": [
|
||||
{
|
||||
"registry_type": "npm",
|
||||
"registry_base_url": "https://registry.npmjs.org",
|
||||
"registryType": "npm",
|
||||
"registryBaseUrl": "https://registry.npmjs.org",
|
||||
"identifier": "@legacy/old-weather-server",
|
||||
"version": "0.9.5",
|
||||
"transport": {
|
||||
"type": "stdio"
|
||||
},
|
||||
"environment_variables": [
|
||||
"environmentVariables": [
|
||||
{
|
||||
"name": "WEATHER_API_KEY",
|
||||
"description": "Weather API key",
|
||||
"is_required": true,
|
||||
"is_secret": true
|
||||
"isRequired": true,
|
||||
"isSecret": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
|
||||
"$id": "https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json",
|
||||
"title": "MCP Server Detail",
|
||||
"$ref": "#/definitions/ServerDetail",
|
||||
"definitions": {
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
"example": "1.0.2",
|
||||
"description": "Version string for this server. SHOULD follow semantic versioning (e.g., '1.0.2', '2.1.0-alpha'). Equivalent of Implementation.version in MCP specification. Non-semantic versions are allowed but may not sort predictably. Version ranges are rejected (e.g., '^1.2.3', '~1.2.3', '>=1.2.3', '1.x', '1.*')."
|
||||
},
|
||||
"website_url": {
|
||||
"websiteUrl": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Optional URL to the server's homepage, documentation, or project website. This provides a central link for users to learn more about the server. Particularly useful when the server has custom installation instructions or setup requirements.",
|
||||
|
|
@ -86,18 +86,18 @@
|
|||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"registry_type",
|
||||
"registryType",
|
||||
"identifier",
|
||||
"version",
|
||||
"transport"
|
||||
],
|
||||
"properties": {
|
||||
"registry_type": {
|
||||
"registryType": {
|
||||
"type": "string",
|
||||
"description": "Registry type indicating how to download packages (e.g., 'npm', 'pypi', 'oci', 'nuget', 'mcpb')",
|
||||
"examples": ["npm", "pypi", "oci", "nuget", "mcpb"]
|
||||
},
|
||||
"registry_base_url": {
|
||||
"registryBaseUrl": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Base URL of the package registry",
|
||||
|
|
@ -117,15 +117,15 @@
|
|||
"example": "1.0.2",
|
||||
"minLength": 1
|
||||
},
|
||||
"file_sha256": {
|
||||
"fileSha256": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-f0-9]{64}$",
|
||||
"description": "SHA-256 hash of the package file for integrity verification. Required for MCPB packages and optional for other package types. Authors are responsible for generating correct SHA-256 hashes when creating server.json. If present, MCP clients must validate the downloaded file matches the hash before running packages to ensure file integrity.",
|
||||
"example": "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce"
|
||||
},
|
||||
"runtime_hint": {
|
||||
"runtimeHint": {
|
||||
"type": "string",
|
||||
"description": "A hint to help clients determine the appropriate runtime for the package. This field should be provided when `runtime_arguments` are present.",
|
||||
"description": "A hint to help clients determine the appropriate runtime for the package. This field should be provided when `runtimeArguments` are present.",
|
||||
"examples": [
|
||||
"npx",
|
||||
"uvx",
|
||||
|
|
@ -147,21 +147,21 @@
|
|||
],
|
||||
"description": "Transport protocol configuration for the package"
|
||||
},
|
||||
"runtime_arguments": {
|
||||
"runtimeArguments": {
|
||||
"type": "array",
|
||||
"description": "A list of arguments to be passed to the package's runtime command (such as docker or npx). The `runtime_hint` field should be provided when `runtime_arguments` are present.",
|
||||
"description": "A list of arguments to be passed to the package's runtime command (such as docker or npx). The `runtimeHint` field should be provided when `runtimeArguments` are present.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Argument"
|
||||
}
|
||||
},
|
||||
"package_arguments": {
|
||||
"packageArguments": {
|
||||
"type": "array",
|
||||
"description": "A list of arguments to be passed to the package's binary.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Argument"
|
||||
}
|
||||
},
|
||||
"environment_variables": {
|
||||
"environmentVariables": {
|
||||
"type": "array",
|
||||
"description": "A mapping of environment variables to be set when running the package.",
|
||||
"items": {
|
||||
|
|
@ -177,7 +177,7 @@
|
|||
"description": "A description of the input, which clients can use to provide context to the user.",
|
||||
"type": "string"
|
||||
},
|
||||
"is_required": {
|
||||
"isRequired": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
|
|
@ -196,7 +196,7 @@
|
|||
"type": "string",
|
||||
"description": "The default value for the input. If this is not set, the user may be prompted to provide a value. If a value is set, it should not be configurable by end users.\n\nIdentifiers wrapped in `{curly_braces}` will be replaced with the corresponding properties from the input `variables` map. If an identifier in braces is not found in `variables`, or if `variables` is not provided, the `{curly_braces}` substring should remain unchanged.\n"
|
||||
},
|
||||
"is_secret": {
|
||||
"isSecret": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates whether the input is a secret value (e.g., password, token). If true, clients should handle the value securely.",
|
||||
"default": false
|
||||
|
|
@ -253,12 +253,12 @@
|
|||
],
|
||||
"example": "positional"
|
||||
},
|
||||
"value_hint": {
|
||||
"valueHint": {
|
||||
"type": "string",
|
||||
"description": "An identifier-like hint for the value. This is not part of the command line, but can be used by client configuration and to provide hints to users.",
|
||||
"example": "file_path"
|
||||
},
|
||||
"is_repeated": {
|
||||
"isRepeated": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the argument can be repeated multiple times in the command line.",
|
||||
"default": false
|
||||
|
|
@ -267,7 +267,7 @@
|
|||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"value_hint"
|
||||
"valueHint"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -304,7 +304,7 @@
|
|||
"description": "The flag name, including any leading dashes.",
|
||||
"example": "--port"
|
||||
},
|
||||
"is_repeated": {
|
||||
"isRepeated": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the argument can be repeated multiple times.",
|
||||
"default": false
|
||||
|
|
@ -377,7 +377,7 @@
|
|||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"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.",
|
||||
"description": "URL template for the streamable-http transport. Variables in {curly_braces} reference argument valueHints, argument names, or environment variable names. After variable substitution, this should produce a valid URI.",
|
||||
"example": "https://api.example.com/mcp"
|
||||
},
|
||||
"headers": {
|
||||
|
|
@ -432,7 +432,7 @@
|
|||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "JSON Schema URI for this server.json format",
|
||||
"example": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json"
|
||||
"example": "https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json"
|
||||
},
|
||||
"packages": {
|
||||
"type": "array",
|
||||
|
|
@ -475,4 +475,4 @@
|
|||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ import (
|
|||
// EditServerInput represents the input for editing a server
|
||||
type EditServerInput struct {
|
||||
Authorization string `header:"Authorization" doc:"Registry JWT token with edit permissions" required:"true"`
|
||||
ID string `path:"id" doc:"Server ID (UUID)" format:"uuid"`
|
||||
ServerID string `path:"server_id" doc:"Server ID (UUID)" format:"uuid"`
|
||||
Version string `query:"version" doc:"Version to edit (e.g., '1.0.0')" required:"true" example:"1.0.0"`
|
||||
Body apiv0.ServerJSON `body:""`
|
||||
}
|
||||
|
||||
|
|
@ -30,9 +31,9 @@ func RegisterEditEndpoints(api huma.API, registry service.RegistryService, cfg *
|
|||
huma.Register(api, huma.Operation{
|
||||
OperationID: "edit-server",
|
||||
Method: http.MethodPut,
|
||||
Path: "/v0/servers/{id}",
|
||||
Path: "/v0/servers/{server_id}",
|
||||
Summary: "Edit MCP server",
|
||||
Description: "Update an existing MCP server (admin only)",
|
||||
Description: "Update an existing MCP server (admin only). Requires version query parameter to specify which version to edit.",
|
||||
Tags: []string{"admin"},
|
||||
Security: []map[string][]string{
|
||||
{"bearer": {}},
|
||||
|
|
@ -53,7 +54,8 @@ func RegisterEditEndpoints(api huma.API, registry service.RegistryService, cfg *
|
|||
}
|
||||
|
||||
// Get current server to check permissions against existing name
|
||||
currentServer, err := registry.GetByID(input.ID)
|
||||
currentServer, err := registry.GetByServerIDAndVersion(input.ServerID, input.Version)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, database.ErrNotFound) {
|
||||
return nil, huma.Error404NotFound("Server not found")
|
||||
|
|
@ -76,8 +78,13 @@ func RegisterEditEndpoints(api huma.API, registry service.RegistryService, cfg *
|
|||
return nil, huma.Error400BadRequest("Cannot change status of deleted server. Deleted servers cannot be undeleted.")
|
||||
}
|
||||
|
||||
// Edit the server
|
||||
updatedServer, err := registry.EditServer(input.ID, input.Body)
|
||||
// Edit the server using the version_id from the current server
|
||||
versionID := currentServer.GetVersionID()
|
||||
if versionID == "" {
|
||||
return nil, huma.Error500InternalServerError("Server version ID not found in metadata", nil)
|
||||
}
|
||||
|
||||
updatedServer, err := registry.EditServer(versionID, input.Body)
|
||||
if err != nil {
|
||||
if errors.Is(err, database.ErrNotFound) {
|
||||
return nil, huma.Error404NotFound("Server not found")
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue