registry/docs/design/tech-architecture.md
Radoslav Dimitrov a25f166b4b
docs: remove stale complete.md and fix remaining stale references (#1522)
Deletes `complete.md` and cleans up the last references to the
pre-restructuring docs layout.

## Why `complete.md` goes

It is 2,944 lines (31% of all documentation lines in the repo)
self-described as *"all documentation from the docs/ directory compiled
into a single markdown file"*. But:

- **No generator exists.** No make target, no workflow, no script. `grep
-rn "complete\.md"` finds **zero** references anywhere in the repo.
- **It mirrors a docs tree that no longer exists** — `docs/guides/`,
`docs/explanations/`, `docs/concepts/`.
- **All 72 of its relative links are broken**, and six of the basenames
it references exist nowhere in the repo.
- **~14 current docs are missing from it entirely** (`about.mdx`,
`authentication.mdx`, `package-types.mdx`, both CHANGELOGs, ...).
- **Its `server.json` examples pin the superseded `2025-07-09` schema**
(current is `2025-12-11`).

The strongest argument is its own last commit. [PR
#1278](https://github.com/modelcontextprotocol/registry/pull/1278)
closed [issue
#767](https://github.com/modelcontextprotocol/registry/issues/767) — a
real user-reported CLI flag bug — by editing **only `complete.md`**. A
genuine fix landed in a file nobody reads, while the docs a reader would
actually find stayed wrong.

A generated file with no generator degrades into a trap: authoritative
enough that people edit it, with nothing validating it. If the
LLM-consumption use case is worth keeping, the right shape is a `make
docs-bundle` target plus a `check-docs-bundle` CI job mirroring the
existing `check-schema` pattern — happy to do that instead if you would
rather keep it.

## Remaining stale references

| File | Was | Now |
|---|---|---|
| `contributing/add-package-registry.md` | Add
`docs/guides/publishing/publish-[yourregistry].md`, update
`docs/guides/publishing/README.md` | Add a section to
`package-types.mdx`. These were the **last live references** to the
obsolete `docs/guides/` layout outside `complete.md` |
| `administration/maintainer-onboarding.md` | Add them to "Current key
maintainers" in README | "Registry Working Group" — the section that
actually exists |
| `reference/README.md` | Omitted 6 reference docs | Adds
`api/extensions.md`, `api/openapi.yaml`, `api/CHANGELOG.md`,
`server-json/CHANGELOG.md`, `server-json/CONTRIBUTING.md`,
`server-json/draft/` |
| `docs/README.md` | Index omitted `community-projects.md` | Listed |
| `reference/api/generic-registry-api.md` | `PUT .../versions/{version}`
"not implemented by official registry" | It **is** implemented
([edit.go:36](https://github.com/modelcontextprotocol/registry/blob/main/internal/api/handlers/v0/edit.go#L36)),
and `official-registry-api.md` already lists it as an admin endpoint |
| `reference/api/official-registry-api.md` | Omitted 3 registered routes
| Adds `POST /v0.1/validate` (which `mcp-publisher validate` calls),
`GET /v0.1/ping`, `GET /v0.1/version`, and notes these plus `/health`
are absent from `openapi.yaml` |
| `server-json/official-registry-requirements.md` | Per-registry
verification → `quickstart.mdx` | → `package-types.mdx`, which has an
Ownership Verification section per registry |
| `design/design-principles.md` | Sections 1,2,3,4,**6**,7 | Renumbered
1–6 |
| `contributing/releasing.md` | Steps 1,2,3,**5**,6 | Renumbered 1–5 |

I left the sibling `DELETE` claim in `generic-registry-api.md` alone —
it is accurate, no DELETE route is registered (the `http.MethodDelete`
hit in `server.go` is CORS config, not a route).

## Staleness banners rather than rewrites

**`design/tech-architecture.md`** is substantially fictional. Rather
than a vague "may be outdated", the banner lists what I verified is
wrong:

- Describes Helm-chart deployment; the registry is a plain `Deployment`
([registry.go:65](https://github.com/modelcontextprotocol/registry/blob/main/deploy/pkg/k8s/registry.go#L65)).
Helm is used only for third-party components.
- Diagram shows a `StatefulSet` on port **27017** — MongoDB's port. The
DB is PostgreSQL on 5432 via the CloudNativePG operator.
- Documents a `verify-domain` challenge flow (`POST /verify-domain`,
`/verify-domain/check`, server-issued tokens) that **was never built**.
- Documents `/admin/*` routes that are not registered.
- Says the DB stores user auth state and DNS verification records; only
`servers` and `server_extensions` tables exist.

**`design/roadmap.md`** still says "Phase 1: MVP/Go-Live (Current
Focus)" ~11 months after launch. I added a dated note rather than
inventing a current phase — that is a working-group call.

## Verification

All **101** remaining relative links across every `.md`/`.mdx` in the
repo resolve. The only two non-resolving matches are the intentional
`[project-name](link)` template placeholder and the moderation link
fixed in #1518.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 16:32:37 +03:00

6.8 KiB

MCP Registry Technical Architecture

Warning

This document has drifted from the shipped system and is kept as a design record. For the architecture as deployed, see deploy/README.md; for the API as implemented, see the API reference.

Known inaccuracies below, as of 2026-08-10:

  • The registry is not deployed via a Helm chart. It is a plain Kubernetes Deployment created by Pulumi; Helm is used only for third-party components (ingress-nginx, cert-manager, cloudnative-pg, k8up, monitoring).
  • The database diagram shows a StatefulSet on port 27017 (MongoDB). The database is PostgreSQL on 5432, provisioned by the CloudNativePG operator.
  • The DNS verification sequence (mcp verify-domain, POST /verify-domain, POST /verify-domain/check, server-issued challenge tokens) describes a design that was never built. The shipped flow signs a timestamp with the operator's key and posts it to POST /v0/auth/dns, with the public key published in a v=MCPv1; k=...; p=... TXT record.
  • No /admin/* routes exist. Admin actions use the regular server endpoints with an admin-permissioned token.
  • The CLI is mcp-publisher, not mcp, and publishing posts to /v0/publish.
  • The database stores servers and server extensions only; it holds no user authentication state and no DNS verification records.

This document describes the technical architecture of the MCP Registry, including system components, deployment strategies, and data flows.

System Overview

The MCP Registry is designed as a lightweight metadata service that bridges MCP server creators with consumers (MCP clients and aggregators).

Core Components

REST API (Go)

The main application server implemented in Go, providing:

  • Public read endpoints for server discovery
  • Authenticated write endpoints for server publication
  • GitHub OAuth integration (extensible to other providers)
  • DNS verification system (optional for custom namespaces)

Database (PostgreSQL)

Primary data store for:

  • Versioned server metadata (server.json contents)
  • User authentication state
  • DNS verification records

CDN Layer

Critical for scalability:

  • Caches all public read endpoints
  • Reduces load on origin servers
  • Enables global distribution
  • Designed for daily consumer polling patterns

CLI Tool

Developer interface for:

  • Server publication workflow
  • GitHub OAuth flow
  • DNS verification

Deployment Architecture

Kubernetes Deployment (Helm)

The registry is designed to run on Kubernetes using Helm charts:

graph TB
    subgraph "Kubernetes Cluster"
        subgraph "Namespace: mcp-registry"
            subgraph "Registry Service"
                LB[Load Balancer<br/>:80]
                RS[Registry Service<br/>:8080]
                RP1[Registry Pod 1]
                RP2[Registry Pod 2]
                RP3[Registry Pod N]
            end
            
            subgraph "Database Service"
                DBS[DB Service<br/>:27017]
                SS[StatefulSet]
                PV[Persistent Volume]
            end
            
            subgraph "Secrets"
                GHS[GitHub OAuth Secret]
            end
        end
    end
    
    LB --> RS
    RS --> RP1
    RS --> RP2
    RS --> RP3
    RP1 --> DBS
    RP2 --> DBS
    RP3 --> DBS
    DBS --> SS
    SS --> PV
    RP1 -.-> GHS
    RP2 -.-> GHS
    RP3 -.-> GHS

Data Flow Patterns

1. Server Publication Flow

sequenceDiagram
    participant Dev as Developer
    participant CLI as CLI Tool
    participant API as Registry API
    participant DB as Database
    participant GH as GitHub
    participant DNS as DNS Provider
    
    Dev->>CLI: mcp publish server.json
    CLI->>CLI: Validate server.json
    CLI->>GH: OAuth flow
    GH-->>CLI: Access token
    CLI->>API: POST /servers
    API->>GH: Verify token
    API->>DNS: Verify domain (if applicable)
    API->>DB: Store metadata
    API-->>CLI: Success
    CLI-->>Dev: Published!

2. Consumer Discovery Flow

sequenceDiagram
    participant Client as MCP Client Host App
    participant INT as Intermediary<br/>(Marketplace/Aggregator)
    participant CDN as CDN Cache
    participant API as Registry API
    participant DB as Database
    
    Note over INT,CDN: Daily ETL Process
    INT->>CDN: GET /servers
    alt Cache Hit
        CDN-->>INT: Cached response
    else Cache Miss
        CDN->>API: GET /servers
        API->>DB: Query servers
        DB-->>API: Server list
        API-->>CDN: Response + cache headers
        CDN-->>INT: Response
    end
    INT->>INT: Process & enhance data
    INT->>INT: Store in local cache
    
    Note over Client,INT: Real-time Client Access
    Client->>INT: Request server list
    INT-->>Client: Curated/enhanced data

3. DNS Verification Flow

sequenceDiagram
    participant User as User
    participant CLI as CLI Tool
    participant API as Registry API
    participant DNS as DNS Provider
    participant DB as Database
    
    User->>CLI: mcp verify-domain example.com
    CLI->>API: POST /verify-domain
    API->>API: Generate verification token
    API->>DB: Store pending verification
    API-->>CLI: TXT record: mcp-verify=abc123
    CLI-->>User: Add TXT record to DNS
    User->>DNS: Configure TXT record
    User->>CLI: Confirm added
    CLI->>API: POST /verify-domain/check
    API->>DNS: Query TXT records
    DNS-->>API: TXT records
    API->>API: Validate token
    API->>DB: Store verification
    API-->>CLI: Domain verified
    CLI-->>User: Success!

4. Admin OIDC Authentication Flow

For registry administration, users with @modelcontextprotocol.io Google Cloud Identity accounts can authenticate using OIDC:

sequenceDiagram
    participant Admin as Admin User
    participant CLI as Admin CLI
    participant GCP as Google Cloud Identity
    participant API as Registry API
    
    Admin->>CLI: Request admin token
    CLI->>GCP: gcloud auth print-identity-token --audiences=mcp-registry
    GCP-->>CLI: ID Token (with hd: "modelcontextprotocol.io")
    CLI->>API: POST /v0.1/auth/oidc {"oidc_token": "eyJ..."}
    API->>GCP: Verify token signature (JWKS)
    API->>API: Validate claims (issuer, audience, hd)
    API->>API: Grant admin permissions (edit: *, publish: *)
    API-->>CLI: Registry JWT Token
    CLI->>API: POST /admin/* (with Registry JWT)
    API->>API: Validate JWT + permissions
    API-->>CLI: Admin operation success

Usage:

# Get Google Cloud Identity token
ID_TOKEN=$(gcloud auth print-identity-token)

# Exchange for Registry JWT token  
REGISTRY_TOKEN=$(curl -X POST /v0.1/auth/oidc \
  -H "Content-Type: application/json" \
  -d '{"oidc_token": "'$ID_TOKEN'"}' | jq -r .registry_token)

# Use for admin operations
curl -H "Authorization: Bearer $REGISTRY_TOKEN" /v0.1/...