Skip to content

fix(admin): use PATCH status endpoints in takedown script and runbook - #1518

Merged
rdimitrov merged 1 commit into
mainfrom
fix/admin-takedown-endpoints
Aug 10, 2026
Merged

fix(admin): use PATCH status endpoints in takedown script and runbook#1518
rdimitrov merged 1 commit into
mainfrom
fix/admin-takedown-endpoints

Conversation

@rdimitrov

Copy link
Copy Markdown
Member

The admin takedown script cannot work as written, and the runbook that documents it has the same problem.

The bug

tools/admin/takedown.sh sent PUT with a ?status=deleted query parameter to two routes:

What the script sent Reality
PUT /v0/servers/{name}/versions/{version}?status=deleted Route exists, but requires a full ServerJSON body and has no status query parameter
PUT /v0/servers/{name}?status=deleted Not registered at all — the whole-server takedown path 404s

The real endpoints are PATCH /v0/servers/{name}/versions/{version}/status and PATCH /v0/servers/{name}/status (status.go:83, :198), both taking {"status": ..., "statusMessage": ...}. edit.go even says so in its own description: use the status endpoint for status changes.

Script changes

  • Send PATCH with a JSON body built via jq
  • Require VERSION or ALL_VERSIONS=true explicitly. Previously a missing VERSION meant "entire server". Since PATCH .../status updates every version, an operator who simply forgot VERSION would have taken down the whole server. Now that needs saying out loud.
  • Support STATUS (default deleted) and STATUS_MESSAGE, so a takedown can record its reason
  • set -euo pipefail, non-zero exit on HTTP errors, and print the response body so huma error detail is visible instead of being swallowed

Runbook changes

  • GET /v0/servers/{name} is not a route — use GET .../versions/latest (which is supported, see servers.go:155-178)
  • Replace the per-version ?status=deleted loop with the single all-versions PATCH .../status call, which reports updatedCount
  • Keep the per-version PUT loop for content edits, which genuinely has no bulk endpoint, and show that it needs the full body
  • Correct the closing note claiming server-wide changes must be applied per version — true for content, not for status
  • Fix the broken moderation-guidelines.md link (dead since the docs restructuring; the file is now modelcontextprotocol-io/moderation-policy.mdx)

Verification

shellcheck clean, bash -n clean, and all three guard paths exercised (no args / neither VERSION nor ALL_VERSIONS / both set). Both PATCH paths confirmed present in docs/reference/api/openapi.yaml. I did not run a live takedown against production.

Kept on /v0 rather than /v0.1 to match the existing admin/deploy convention — happy to switch if you would rather admin tooling target the frozen version.

🤖 Generated with Claude Code

`tools/admin/takedown.sh` could not work. It sent `PUT` with a `?status=deleted`
query parameter to two routes:

- `PUT /v0/servers/{name}/versions/{version}?status=deleted` — this route exists
  but requires a full `ServerJSON` body and has no `status` query parameter
- `PUT /v0/servers/{name}?status=deleted` — this route is not registered at all,
  so the whole-server takedown path returned 404

The real endpoints are `PATCH /v0/servers/{name}/versions/{version}/status` and
`PATCH /v0/servers/{name}/status`, both taking `{"status": ..., "statusMessage": ...}`.

Script changes:

- Send `PATCH` with a JSON body built by `jq`
- Require either `VERSION` or `ALL_VERSIONS=true` explicitly. Previously a missing
  `VERSION` silently meant "entire server"; since `PATCH .../status` updates every
  version, an operator who forgot `VERSION` would have taken down the whole server
- Support `STATUS` (default `deleted`) and `STATUS_MESSAGE` for recording a reason
- Add `set -euo pipefail`, propagate a non-zero exit on HTTP errors, and print the
  response body so huma's error detail is visible

Runbook changes in `docs/administration/admin-operations.md`:

- `GET /v0/servers/{name}` is not a route; use `GET .../versions/latest`
- Replace the per-version `?status=deleted` loop with the single all-versions
  `PATCH .../status` call, which reports `updatedCount`
- Keep the per-version `PUT` loop for content edits, which genuinely has no bulk
  endpoint, and show that it needs the full body
- Correct the note claiming server-wide changes must be applied per version; that
  is true for content but not for status
- Fix the broken `moderation-guidelines.md` link, which has been
  `../modelcontextprotocol-io/moderation-policy.mdx` since the docs restructuring

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@rdimitrov
rdimitrov merged commit 43fbc1d into main Aug 10, 2026
7 checks passed
@rdimitrov
rdimitrov deleted the fix/admin-takedown-endpoints branch August 10, 2026 13:24
rdimitrov added a commit that referenced this pull request Aug 10, 2026
)

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](#1278)
closed [issue
#767](#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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant