feat: publish Coder MCP server to official MCP Registry (#21673)

## Summary

This adds the necessary configuration to publish Coder's remote MCP
server to the official MCP Registry at registry.modelcontextprotocol.io.

## Changes

- **`server.json`**: MCP server metadata for registry discovery
- **`.github/workflows/publish-mcp-registry.yaml`**: GitHub Actions
workflow to automatically publish on release

## How it works

1. When a new Coder release is published, the workflow automatically
publishes to the MCP Registry
2. MCP clients (Claude, ChatGPT, VS Code, etc.) can discover Coder via
the registry
3. Users just need to provide their Coder deployment URL - OAuth handles
authentication automatically via RFC 7591 Dynamic Client Registration

## MCP Registry Entry

The server will be listed as `io.github.coder/coder` with:
- **Transport**: `streamable-http` 
- **Endpoint**: `{coder_url}/api/experimental/mcp/http`
- **Auth**: OAuth2 (automatic via
`/.well-known/oauth-authorization-server`)

## Testing

After merge and next release, verify at:
```bash
curl "https://registry.modelcontextprotocol.io/v0.1/servers?q=io.github.coder"
```

Closes #21275

---
_Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking:
`medium`_

---------

Co-authored-by: Ben Potter <me@bpmct.net>
This commit is contained in:
Atif Ali
2026-06-26 11:20:45 -05:00
committed by GitHub
co-authored by Ben Potter
parent 0f1e792f3f
commit 18efcb6c41
3 changed files with 319 additions and 33 deletions
@@ -0,0 +1,80 @@
name: Publish to MCP Registry
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: "Version to publish (semver, e.g. 2.20.0). Used only for manual runs."
required: false
type: string
publish:
description: "Actually publish to the live registry. Leave false to validate only."
required: false
default: false
type: boolean
jobs:
publish-mcp:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for GitHub OIDC
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install mcp-publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
- name: Determine version
id: version
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
if [ "${EVENT_NAME}" = "release" ]; then
# Tag refs look like refs/tags/v2.20.0
VERSION="${GITHUB_REF#refs/tags/v}"
else
VERSION="${INPUT_VERSION}"
fi
if [ -z "${VERSION}" ]; then
echo "::error::No version provided. Pass the 'version' input for manual runs."
exit 1
fi
# Reject anything that isn't clean semver so we never publish refs/heads/... etc.
if ! echo "${VERSION}" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then
echo "::error::Refusing to publish invalid version '${VERSION}'."
exit 1
fi
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
- name: Set version in server.json
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
jq --arg v "${VERSION}" '.version = $v' server.json > server.tmp
mv server.tmp server.json
cat server.json
- name: Validate server.json (no publish)
run: ./mcp-publisher validate
- name: Authenticate to MCP Registry
if: github.event_name == 'release' || inputs.publish
run: ./mcp-publisher login github-oidc
- name: Publish server to MCP Registry
if: github.event_name == 'release' || inputs.publish
run: ./mcp-publisher publish