registry/docs/reference/api/official-registry-api.md
Preeti Dewani bb84ea69e8
Publisher-managed "deleted" support (#893)
(Updated auto-generated PR description from @tadasant / Claude on Feb
22, 2026)

## Motivation and Context

Fixes #637

Server lifecycle management (deprecation and yanking) is a standard
requirement for package registries. Use cases like rebranding, security
vulnerabilities, and end-of-life servers demand the ability to mark
servers as deprecated or deleted, with optional messaging to guide
consumers toward alternatives.

## Changes

### New API endpoints

- **`PATCH /v0/servers/{serverName}/versions/{version}/status`** —
Update the lifecycle status of a single server version
- **`PATCH /v0/servers/{serverName}/status`** — Update the lifecycle
status of all versions of a server in a single transaction

Both endpoints accept:
```json
{
  "status": "active|deprecated|deleted",
  "statusMessage": "Optional message (max 500 chars) explaining the change"
}
```

### New CLI command

- **`mcp-publisher status <serverName> [version]`** — Update server
lifecycle status from the command line
  - `--status` (required): `active`, `deprecated`, or `deleted`
  - `--message`: Optional status message
- `--all-versions`: Apply to all versions of the server (replaces the
`<version>` argument)

### API response changes

`RegistryExtensions` now includes two new fields:
- `statusChangedAt` — Timestamp of the last status change
- `statusMessage` — Optional free-form message (e.g., deprecation
reason, migration guidance)

### List endpoint changes

- New `include_deleted` query parameter on `GET /v0/servers` — defaults
to `false`, hiding deleted servers from listings
- When `updated_since` is provided, `include_deleted` is automatically
set to `true` for incremental sync

### Database

- Migration `013_add_status_fields.sql`: Adds `status_changed_at` (NOT
NULL, initialized from `published_at`) and `status_message` columns to
the `servers` table

### Design decisions (from review discussion)

- **Dedicated status endpoints** rather than overloading the existing
edit endpoint
- **Bidirectional status transitions** — all transitions between
`active`, `deprecated`, and `deleted` are allowed
- **`statusMessage` as free-form text** — no structured `nextName` or
`alternativeUrl` fields (per maintainer feedback, to avoid complexity
around chaining, trust transfer, etc.)
- **Publish permission** grants status change access (not limited to
admin/edit)
- **Status message auto-cleared** when transitioning back to `active`
Good, now I have the full picture. Here's the addendum:

### Consumer-facing API changes

The new status fields live inside
`_meta["io.modelcontextprotocol.registry/official"]` on every
`ServerResponse`. This is the existing `RegistryExtensions` object — two
new fields are added alongside the existing ones:

**Before:**
```json
{
  "server": { "name": "com.example/my-server", "...": "..." },
  "_meta": {
    "io.modelcontextprotocol.registry/official": {
      "status": "active",
      "publishedAt": "2025-06-01T00:00:00Z",
      "updatedAt": "2025-06-15T00:00:00Z",
      "isLatest": true
    }
  }
}
```

**After:**
```json
{
  "server": { "name": "com.example/my-server", "...": "..." },
  "_meta": {
    "io.modelcontextprotocol.registry/official": {
      "status": "deprecated",
      "statusChangedAt": "2026-02-01T12:00:00Z",
      "statusMessage": "Deprecated in favor of com.example/my-server-v2",
      "publishedAt": "2025-06-01T00:00:00Z",
      "updatedAt": "2026-02-01T12:00:00Z",
      "isLatest": true
    }
  }
}
```

| New field | Type | Present when |
|-----------|------|-------------|
| `statusChangedAt` | `string` (RFC3339) | Always — initialized to
`publishedAt` for existing records |
| `statusMessage` | `string` (max 500 chars) | Only when set —
`null`/omitted for active servers (auto-cleared on transition to active)
|

These fields appear on **every endpoint that returns a
`ServerResponse`**: `GET /v0/servers`, `GET /v0/servers/{name}`, `GET
/v0/servers/{name}/versions/{version}`, and the new PATCH status
endpoints.

### List endpoint filtering

`GET /v0/servers` gains an `include_deleted` query parameter:

| Scenario | Behavior |
|----------|----------|
| No `include_deleted` param | Deleted servers hidden (default `false`)
|
| `include_deleted=true` | Deleted servers included in results |
| `updated_since` provided | `include_deleted` forced to `true` for
incremental sync |

## How Has This Been Tested?

- Unit tests for status handler (`status_test.go`) covering status
transitions, permission checks, validation errors, and the all-versions
endpoint
- Unit tests for the CLI command (`status_test.go`)
- Integration with existing server/edit handler tests
- Database layer tests for the new status update and query methods
- Tested locally with `make dev-compose`

## Types of changes

- [x] New feature (non-breaking change which adds functionality)

## Checklist

- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed

## Open items from review

- [ ] `include_deleted` silent override: When `updated_since` is
provided and `include_deleted=false` is explicitly passed, should return
a 400 error rather than silently overriding
([thread](https://github.com/modelcontextprotocol/registry/pull/893#discussion_r2100879360))
— agreed upon but may not yet be implemented
2026-02-27 09:00:07 -08:00

5.1 KiB

Official MCP Registry API

This document describes the API for the official MCP Registry hosted at registry.modelcontextprotocol.io.

This API is based on the generic registry API with additional endpoints and authentication. For publishing servers using the API, see the publishing guide.

Base URLs

  • Production: https://registry.modelcontextprotocol.io
  • Staging: https://staging.registry.modelcontextprotocol.io

Interactive Documentation

Extensions

The official registry implements the Generic Registry API with the following specific configurations and extensions:

Authentication

Publishing requires namespace-based authentication:

  • GitHub OAuth - For io.github.* namespaces
  • GitHub OIDC - For publishing from GitHub Actions
  • DNS verification - For domain-based namespaces (com.example.*)
  • HTTP verification - For domain-based namespaces (com.example.*)

See Publisher Commands for authentication setup.

Package Validation

The official registry enforces additional package validation requirements when publishing.

Server List Filtering

The official registry extends the GET /v0.1/servers endpoint with additional query parameters for improved discovery and synchronization:

  • updated_since - Filter servers updated after RFC3339 timestamp (e.g., 2025-08-07T13:15:04.280Z)
  • search - Case-insensitive substring search on server names (e.g., filesystem)
    • This is intentionally simple. For more advanced searching and filtering, use a subregistry.
  • version - Filter by version (currently supports latest for latest versions only)
  • include_deleted - Include deleted servers in results (default: false, but automatically true when updated_since is provided for incremental sync)

These extensions enable efficient incremental synchronization for downstream registries and improved server discovery. Parameters can be combined and work with standard cursor-based pagination.

Example: GET /v0.1/servers?search=filesystem&updated_since=2025-08-01T00:00:00Z&version=latest

Server Detail

The GET /v0.1/servers/{serverName}/versions/{version} endpoint returns detailed information about a specific server version.

Path parameters:

  • serverName - URL-encoded server name (e.g., io.github.user%2Fmy-server)
  • version - Server version or latest for the most recent version

Query parameters:

  • include_deleted - Include deleted servers in results (default: false)

Server Version History

The GET /v0.1/servers/{serverName}/versions endpoint returns all versions of a server.

Path parameters:

  • serverName - URL-encoded server name (e.g., io.github.user%2Fmy-server)

Query parameters:

  • include_deleted - Include deleted servers in results (default: false)

Additional endpoints

Auth endpoints

  • POST /v0.1/auth/dns - Exchange signed DNS challenge for auth token
  • POST /v0.1/auth/http - Exchange signed HTTP challenge for auth token
  • POST /v0.1/auth/github-at - Exchange GitHub access token for auth token
  • POST /v0.1/auth/github-oidc - Exchange GitHub OIDC token for auth token
  • POST /v0.1/auth/oidc - Exchange Google OIDC token for auth token (for admins)

Status endpoints

Update Single Version Status

PATCH /v0.1/servers/{serverName}/versions/{version}/status - Update status of a specific server version.

Path parameters:

  • serverName - URL-encoded server name (e.g., io.github.user%2Fmy-server)
  • version - Server version to update

Request body:

  • status (required) - New status: active, deprecated, or deleted
  • statusMessage (optional) - Message explaining the status change (max 500 characters, not allowed when status is active)
Update All Versions Status

PATCH /v0.1/servers/{serverName}/status - Update status of all versions of a server in a single transaction.

Path parameters:

  • serverName - URL-encoded server name (e.g., io.github.user%2Fmy-server)

Request body:

  • status (required) - New status: active, deprecated, or deleted
  • statusMessage (optional) - Message explaining the status change (max 500 characters, not allowed when status is active)

Status values:

  • active - Server is active and visible in default listings
  • deprecated - Server is deprecated but still visible with a warning message
  • deleted - Server is hidden from default listings (use include_deleted=true to show)

Authentication: Requires publish or edit permission for the server namespace.

Admin endpoints

  • GET /metrics - Prometheus metrics endpoint
  • GET /v0.1/health - Basic health check endpoint
  • PUT /v0.1/servers/{serverName}/versions/{version} - Edit specific server version