ci: publish server.json to the Official MCP Registry from GitHub Actions

Merged
LI
2mo ago
+112-3

Why

Publishing io.github.tester-army/testerarmy to the Official MCP Registry from a laptop only works for an org Owner: the registry grants an organisation's io.github.<org>/* namespace to GitHub users whose org role is Owner (its github_at.go and authentication docs), and refuses ordinary members with "only io.github.lil-bsz/* allowed". Public membership makes no difference.

The route that needs nobody's personal login is GitHub Actions OIDC: the registry grants io.github.<repository owner>/* to any workflow running in this organisation's repositories. So the publish moves into CI. Tracked in Linear GTM-86 (Listings project).

What changes

.github/workflows/publish-mcp-registry.yml runs when server.json (or the workflow file) lands on main, and on demand from the Actions tab (main only). Steps:

  1. install mcp-publisher 1.8.1, verifying the download against the release checksums
  2. mcp-publisher validate server.json (the registry's own validator, schema plus semantic rules)
  3. skip cleanly if this version is already in the registry, so re-runs and later workflow edits stay green
  4. login github-oidc, publish
  5. confirm the exact version entry exists (the step fails on a 404) and print it plus the Glama page link in the job summary

Permissions are contents: read plus id-token: write on the publish job only. No pull_request trigger, no secrets, no npm code runs in the job, so fork PRs cannot reach anything. The job declares the mcp-registry-publish environment so an Owner can add a deployment branch rule and a required reviewer later without a code change; until then the if: github.ref == 'refs/heads/main' guard is the gate, because the registry authorises on the repository owner alone and never checks the branch.

Merging this PR triggers the first publish of version 1.0.0 (the workflow file is in its own path filter and server.json is already on main).

scripts/check-plugin-manifests.sh and validate-plugin.yml now cover server.json: valid JSON, version equal to plugin.json, remotes[0].url equal to the MCP files. It runs on pull requests that touch server.json, so a version bump that forgets the registry manifest fails before merge. actions/checkout goes to v5 in both workflows ahead of GitHub removing Node 20 from runners on September 23.

glama.json names the maintainers (Oskar, Szymon, Bartek) who may claim the Glama pages that the registry entry will generate. Glama, PulseMCP and the other aggregators ingest the official registry.

Verification

  • actionlint clean on both workflows; YAML parses
  • mcp-publisher validate server.json against the live registry: valid
  • consistency script passes on the tree and fails when server.json is bumped alone (tested)
  • exact version endpoint checked live: 200 with the expected shape for a published server, 404 for ours today
  • checksum file format and tarball layout confirmed against the v1.8.1 release assets
  • not exercised: the OIDC exchange itself, which only runs inside Actions on this repo; if the first run fails, the Actions log names the step

After merge

  1. Watch the "Publish to MCP Registry" run; the job summary shows the entry. Manual check: https://registry.modelcontextprotocol.io/v0/servers?search=io.github.tester-army/testerarmy
  2. Claim the Glama pages once they appear (usually within days): https://glama.ai/mcp/connectors/io.github.tester-army/testerarmy and https://glama.ai/mcp/servers/tester-army/cli, signed in to glama.ai with GitHub as one of the maintainers in glama.json.
  3. Optional hardening for an Owner: Settings > Environments > mcp-registry-publish, deployment branches limited to main, add a required reviewer.

šŸ¤– Generated with Claude Code