Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ jobs:
with:
version: v2.11.4

# Node is required by `make validate`: the server.json JSON Schema is
# generated from docs/reference/server-json/schema.ts and checked for drift.
- name: Set up Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: docs/reference/server-json/package-lock.json

- name: Validate schemas and examples
run: make validate

Expand Down
14 changes: 6 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ publisher: ## Build the publisher tool with version info
go build -ldflags="-X main.Version=dev-$(shell git rev-parse --short HEAD) -X main.GitCommit=$(shell git rev-parse HEAD) -X main.BuildTime=$(shell date -u +%Y-%m-%dT%H:%M:%SZ)" -o bin/mcp-publisher ./cmd/publisher

# Schema generation targets
generate-schema: ## Generate server.schema.json from openapi.yaml
@mkdir -p bin
go build -o bin/extract-server-schema ./tools/extract-server-schema
@./bin/extract-server-schema
SCHEMA_DIR := docs/reference/server-json

check-schema: ## Check if server.schema.json is in sync with openapi.yaml
@mkdir -p bin
go build -o bin/extract-server-schema ./tools/extract-server-schema
@./bin/extract-server-schema -check
generate-schema: ## Generate server.schema.json from schema.ts (TypeScript source of truth)
cd $(SCHEMA_DIR) && npm ci && npm run generate

check-schema: ## Check server.schema.json + openapi.yaml are in sync with schema.ts
cd $(SCHEMA_DIR) && npm ci && npm run check && npm run validate

# Test targets
test-unit: ## Run unit tests with coverage (requires PostgreSQL)
Expand Down
376 changes: 15 additions & 361 deletions docs/reference/api/openapi.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/reference/server-json/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
47 changes: 42 additions & 5 deletions docs/reference/server-json/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,58 @@ This document describes the process for making and releasing changes to the `ser

## Making Changes

1. **Modify the OpenAPI spec**: Edit `docs/reference/api/openapi.yaml` with your schema changes. The `ServerDetail` component defines the server.json structure.
The schema has a single source of truth: [`schema.ts`](./schema.ts). The committed
artifact [`draft/server.schema.json`](./draft/server.schema.json) is generated from it
and must not be edited by hand.

2. **Regenerate the schema**: Run `make generate-schema` to update `server.schema.json` from the OpenAPI spec.
1. **Edit the source of truth**: Modify [`schema.ts`](./schema.ts) with your schema changes.

3. **Update the changelog**: Add your changes to the "Draft (Unreleased)" section in `CHANGELOG.md`.
2. **Regenerate the schema**: Run `make generate-schema` (or, from this directory,
`npm run generate`) to update `draft/server.schema.json` from `schema.ts`.

4. **Open a PR**: Submit a pull request to this repository for review.
3. **OpenAPI references the schema automatically**: `docs/reference/api/openapi.yaml`
no longer duplicates these definitions — its `components/schemas` exposes each
server.json type as an external `$ref` into the generated `draft/server.schema.json`.
You do **not** need to edit `openapi.yaml` for an ordinary schema change. The only
time it needs a manual edit is when you **add or remove a top-level definition** in
`schema.ts`: add (or delete) the matching one-line `$ref` stub under
`components/schemas`. `npm run check` enforces that every definition has a stub and
every stub targets a real definition. Because the stubs are relative-path `$ref`s
into `draft/server.schema.json`, the reference `openapi.yaml` now needs the repo
checkout alongside it to fully resolve; the self-contained spec that subregistries
consume is the runtime-served one at `registry.modelcontextprotocol.io/openapi.yaml`
(generated independently from the Go types), which is unaffected.

4. **Add or update examples**: Example documents under [`examples/`](./examples) are
validated against the generated schema. `examples/valid/` must validate cleanly and
`examples/invalid/` must fail at least one constraint. Run `npm run validate` (or
`make validate`) to check.

5. **Update the changelog**: Add your changes to the "Draft (Unreleased)" section in `CHANGELOG.md`.

6. **Open a PR**: Submit a pull request to this repository for review.

### Local tooling

From this directory (`docs/reference/server-json/`):

```bash
npm ci # install dev dependencies (tsx, typescript, ajv, yaml)
npm run generate # regenerate draft/server.schema.json from schema.ts
npm run check # schema up to date + openapi $ref stubs in sync + type-check schema.ts
npm run validate # validate examples/ against the generated schema
```

The generated JSON deliberately reproduces the previous Go (`encoding/json`) output
byte-for-byte, so the schema *content* is unchanged by this pipeline.

## Releasing Changes

When the draft changes are ready for release:

1. **Update the changelog**: Move changes from "Draft (Unreleased)" to a new dated section (e.g., `## 2025-XX-XX`).

2. **Update the schema URL**: Change the `$id` in the schema and the example URL in `openapi.yaml` from `draft` to the release date (e.g., `2025-XX-XX`).
2. **Update the schema URL**: Change the `$id` in [`schema.ts`](./schema.ts) from `draft` to the release date (e.g., `2025-XX-XX`) and run `make generate-schema`.

3. **Merge the PR**: Get approval and merge the changes to main.

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/server-json/draft/server.schema.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$comment": "This file is auto-generated from docs/reference/api/openapi.yaml. Do not edit manually. Run 'make generate-schema' to update.",
"$comment": "This file is auto-generated from docs/reference/server-json/schema.ts. Do not edit manually. Run 'make generate-schema' to update.",
"$id": "https://raw.githubusercontent.com/modelcontextprotocol/registry/main/docs/reference/server-json/draft/server.schema.json",
"$ref": "#/definitions/ServerDetail",
"$schema": "http://json-schema.org/draft-07/schema#",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "no-namespace-separator",
"description": "The name must contain exactly one slash separating namespace from name.",
"version": "1.0.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "io.github.user/verbose",
"description": "This description deliberately exceeds the one-hundred character maximum length enforced by the schema for sure.",
"version": "1.0.0"
}
4 changes: 4 additions & 0 deletions docs/reference/server-json/examples/invalid/missing-name.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"description": "Server without the required name field.",
"version": "1.0.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "io.github.user/bad-version",
"description": "Package pins the disallowed floating tag 'latest'.",
"version": "1.0.0",
"packages": [
{
"registryType": "npm",
"identifier": "@modelcontextprotocol/server-weather",
"version": "latest",
"transport": { "type": "stdio" }
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "io.github.user/bad-argument",
"description": "Positional argument provides neither valueHint nor value.",
"version": "1.0.0",
"packages": [
{
"registryType": "npm",
"identifier": "@modelcontextprotocol/server-weather",
"version": "1.0.0",
"transport": { "type": "stdio" },
"packageArguments": [
{ "type": "positional", "isRepeated": false }
]
}
]
}
6 changes: 6 additions & 0 deletions docs/reference/server-json/examples/valid/minimal.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.user/weather",
"description": "MCP server providing weather data and forecasts.",
"version": "1.0.2"
}
22 changes: 22 additions & 0 deletions docs/reference/server-json/examples/valid/with-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.user/local-weather",
"description": "Local MCP server distributed as an npm package.",
"version": "1.0.0",
"packages": [
{
"registryType": "npm",
"identifier": "@modelcontextprotocol/server-weather",
"version": "1.0.0",
"transport": { "type": "stdio" },
"runtimeHint": "npx",
"packageArguments": [
{ "type": "positional", "valueHint": "config_path" },
{ "type": "named", "name": "--port", "value": "8080" }
],
"environmentVariables": [
{ "name": "API_KEY", "isSecret": true, "isRequired": true }
]
}
]
}
32 changes: 32 additions & 0 deletions docs/reference/server-json/examples/valid/with-remote.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.user/remote-weather",
"description": "Remote MCP server reachable over streamable HTTP.",
"version": "2.1.0",
"title": "Remote Weather",
"websiteUrl": "https://modelcontextprotocol.io/examples",
"repository": {
"url": "https://github.com/modelcontextprotocol/servers",
"source": "github",
"subfolder": "src/weather"
},
"icons": [
{
"src": "https://example.com/icon.png",
"mimeType": "image/png",
"sizes": ["48x48", "96x96"]
}
],
"remotes": [
{
"type": "streamable-http",
"url": "https://{host}/mcp",
"headers": [
{ "name": "Authorization", "isSecret": true, "isRequired": true }
],
"variables": {
"host": { "description": "API host", "default": "api.example.com" }
}
}
]
}
Loading
Loading