Skip to content

ci: auto-publish to npm + MCP Registry on version tags - #3

Merged
fengyat merged 3 commits into
mainfrom
ci/auto-publish-mcp-registry
May 25, 2026
Merged

fengyat merged 3 commits into
mainfrom
ci/auto-publish-mcp-registry

Conversation

@fengyat

@fengyat fengyat commented May 25, 2026

Copy link
Copy Markdown
Member

Summary

Adds .github/workflows/publish-mcp.yml that fully automates releases. After this lands, the publish dance we did manually for v1.1.3 collapses into a git tag && git push.

How releases work after this

# 1. Open a release PR that bumps:
#    - package.json: version
#    - server.json: version + packages[0].version
#    - CHANGELOG.md
# 2. Merge the PR
# 3. Tag the merge commit:
git tag v1.1.4
git push origin v1.1.4
# 4. CI does everything: typecheck → test → build → npm publish → mcp-publisher publish

Pipeline (in order)

  1. actions/checkout@v5 + actions/setup-node@v5
  2. npm ci
  3. Version drift check — fails the build if any of these don't match:
    • git tag (v1.1.4)
    • package.json version
    • server.json version
    • server.json packages[0].version
    • Also asserts package.json.mcpName == server.json.name
  4. npm run typecheck
  5. npm test
  6. npm run build
  7. npm publish --access public (uses NPM_TOKEN secret)
  8. Install mcp-publisher CLI from latest release
  9. mcp-publisher login github-oidc (uses GitHub OIDC, no secret)
  10. mcp-publisher publish

Authentication

What How Setup
npm publish NODE_AUTH_TOKEN from NPM_TOKEN secret You must add this once
MCP Registry GitHub OIDC (id-token: write permission) No secret needed — works because we're publishing from a repo under Continuum-AI-Corp org to the matching io.github.Continuum-AI-Corp/... namespace

Required setup before this can run

Add an NPM_TOKEN secret to the repo:

  1. Generate an npm Automation token at https://www.npmjs.com/settings//tokens (choose Automation type so 2FA-on-publish doesn't block CI)
  2. Add it as a repo secret named NPM_TOKEN at https://github.com/Continuum-AI-Corp/orcarouter-mcp-server/settings/secrets/actions

The OIDC side needs no setup — it works out of the box because:

  • Our mcpName is io.github.Continuum-AI-Corp/orcarouter-mcp
  • The workflow runs in a repo under Continuum-AI-Corp org
  • registry.modelcontextprotocol.io validates the repository_owner OIDC claim matches the namespace

Why the drift check matters

It catches the most common release-PR mistake: bumping package.json but forgetting to bump server.json (or vice versa). The MCP Registry would reject a mismatched publish anyway, but failing in CI before npm publish runs prevents shipping an orphaned npm version.

Out of scope

  • Auto-bumping versions from the tag (kept manual to keep the release PR as the source of truth)
  • CHANGELOG validation (could add later — check the new tag has a matching entry)
  • Auto-PR creation for version bumps (future improvement)

Test plan

  • YAML parses (python3 -c 'import yaml; yaml.safe_load(...)')
  • Reviewer: confirm NPM_TOKEN secret will be added before merging
  • After merge, dry-run by tagging a no-op v1.1.3-test (or whatever) on a feature branch and inspecting CI output — actually, since npm publish would 409 on the existing v1.1.3, the safer way to dry-run is to wait for the real next release (v1.1.4) and watch closely

Triggers on git tag v* (e.g. v1.1.4). Pipeline:

1. Checkout + npm ci
2. Validate tag == package.json.version == server.json.version ==
   server.json.packages[0].version, and package.json.mcpName ==
   server.json.name. Fails fast if any of these drift.
3. typecheck + test + build
4. npm publish --access public (uses NPM_TOKEN secret)
5. mcp-publisher login github-oidc (no secret needed, uses GitHub OIDC)
6. mcp-publisher publish

Removes the manual publish dance (brew install + login + publish)
from future releases. After this lands, releasing becomes:
  bump versions in PR → merge → git tag v1.1.4 && git push --tags

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 39461ae6c4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/publish-mcp.yml Outdated
Addresses Codex review P1 on PR #3: if any step after npm publish fails
(transient network issue during mcp-publisher download/login/publish),
"Re-run failed jobs" would crash at npm publish with "version already
exists" — leaving the release stuck in a manual-recovery state.

Both publish steps now check whether the exact version is already
published first:

- npm: use `npm view @orcarouter/mcp@<version>` to probe; skip on hit
- MCP Registry: query /v0/servers?search=<name> and filter for matching
  (name, version); skip on hit

This makes the job safe to rerun any number of times. A partial failure
between the two publish steps can now recover with a single click.
@fengyat

fengyat commented May 25, 2026

Copy link
Copy Markdown
Member Author

@codex review

Addressed the P1 finding from your previous review (rerun-safety for npm publish). Both publish steps now check whether the exact version is already published and skip if so:

  • npm: npm view @orcarouter/mcp@${VERSION} version → skip publish on hit
  • MCP Registry: query /v0/servers?search=<name> and filter (name, version) → skip publish on hit

Pushed as 8d775e4. Could you take another look and check whether this rerun-safety pattern is sound, and flag anything else worth addressing before we merge?

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8d775e427f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +65 to +66
if npm view "@orcarouter/mcp@${VERSION}" version >/dev/null 2>&1; then
echo "@orcarouter/mcp@${VERSION} already on npm — skipping publish"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Define release version before idempotency checks

Both idempotency guards use ${VERSION}, but this workflow never sets VERSION (the earlier TAG_VERSION is local to a different run step), so these checks do not test the tagged release version. In reruns, that means the npm/registry probes can miss the already-published tag and still execute publish, recreating the original "version already exists" failure mode the change is meant to prevent. Set VERSION at job/workflow scope (or export via $GITHUB_ENV) and use that in both checks.

Useful? React with 👍 / 👎.

Codex P1 on PR #3 follow-up: the npm and MCP Registry idempotency
checks reference ${VERSION}, but the validation step only set a
local bash TAG_VERSION inside its own run block. Across GitHub
Actions steps the variable was undefined, so the probes were running
with an empty version string — meaning the "already published?"
check never matched and the publish ran every time, defeating the
rerun-safety fix in 8d775e4.

Fix: write TAG_VERSION to $GITHUB_ENV after validation passes, so
later steps see VERSION as a real env var.
@fengyat

fengyat commented May 25, 2026

Copy link
Copy Markdown
Member Author

@codex review

Good catch — VERSION was never exported to \$GITHUB_ENV, so the idempotency probes were running with an empty version and would have re-tripped the original failure mode.

Fixed in 954579d: write TAG_VERSION to \$GITHUB_ENV after the validation passes, so the npm and registry probes see a real version. Also gated the echo behind a non-zero fail exit so we don't accidentally export when validation rejects the tag.

Please take another look.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@fengyat
fengyat merged commit e592a25 into main May 25, 2026
1 check passed
fengyat added a commit that referenced this pull request May 26, 2026
`npm ci` requires a package-lock.json. This repo uses bun as its
primary package manager and only commits bun.lock, so the v1.1.4 tag
push triggered a CI failure at the Install dependencies step:

    npm error The `npm ci` command can only install with an existing
    package-lock.json or npm-shrinkwrap.json

PR #3 originally chose `npm ci` from the official MCP Registry docs
example — that example assumes an npm-managed project. Our Dockerfile
(merged in #5) already uses `npm install --no-audit --no-fund` against
the same package.json with no issues; this commit aligns the publish
workflow with that pattern.

We accept the trade-off of non-pinned transitive deps in CI: deps are
pinned to caret ranges in package.json that have been stable across
releases, the build is bundled by tsup so transitive shape doesn't
leak into the published artifact, and tag-gated runs are infrequent
enough that drift detection is moot.

After this merges, the existing v1.1.4 tag needs to be re-pointed at
the new commit (delete + recreate) to retrigger publish — there is no
v1.1.4 on npm or MCP Registry yet, since the failed run aborted before
either publish step.

Co-authored-by: fengyat <fengya.tian@continuum01.ai>
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