From 425d57a1e0222e70471a5cf8e2e6bf48d6a5b4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Wo=C5=82czuk?= Date: Mon, 24 Aug 2026 23:33:01 +0200 Subject: [PATCH] fix(registry): shorten server.json description below the 100-char limit The MCP registry rejected the v0.7.5 publish with a 422: the description was 105 characters against a limit of 100. It only validates at publish time, i.e. after npm has already gone out, so the registry sat a version behind while npm was current. - trim the description to 93 characters - add tests/server-manifest.test.ts so CI catches the registry's constraints (description length, server name vs package.json#mcpName, npm identifier) before a release instead of halfway through one - allow `workflow_dispatch` with publish_registry=true to re-run just the registry half against the current server.json, and verify the target version actually exists on npm before pointing the registry at it Co-Authored-By: Claude Opus 5 --- .github/workflows/release.yml | 33 ++++++++++++++++++++++++++++----- server.json | 2 +- tests/server-manifest.test.ts | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 tests/server-manifest.test.ts diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ebc503..cf229ab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,6 +29,11 @@ on: push: branches: [master] workflow_dispatch: + inputs: + publish_registry: + description: 'Re-publish the current server.json to the MCP registry (npm published but the registry step failed)' + type: boolean + default: false # contents: changesets/action commits the version PR and creates the # GitHub Release at publish time @@ -99,7 +104,11 @@ jobs: publish-registry: name: Publish to MCP Registry needs: release - if: needs.release.outputs.published == 'true' + # The registry validates the manifest only at publish time, i.e. after npm + # has already gone out — so this job can fail on its own and leave the + # registry a version behind. `workflow_dispatch` with publish_registry + # re-runs just this half against whatever server.json currently says. + if: needs.release.outputs.published == 'true' || inputs.publish_registry runs-on: ubuntu-latest timeout-minutes: 10 permissions: @@ -109,11 +118,24 @@ jobs: - uses: actions/checkout@v4 # server.json is bumped in the version PR by scripts/sync-version.js, so - # by now it should already match. Fail loudly rather than publish a stale - # entry that points at a version npm does not have. - - name: Verify server.json matches the published version + # after a release it should already match. On a manual re-run there is no + # released version to compare against and server.json itself is the + # source of truth. + - name: Resolve the version to publish + id: target env: - VERSION: ${{ needs.release.outputs.version }} + RELEASED: ${{ needs.release.outputs.version }} + run: | + VERSION="${RELEASED:-$(node -p "require('./server.json').version")}" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "publishing $VERSION" + + # Fail loudly rather than point the registry at something npm does not + # have — either because the manifest is stale, or because a manual re-run + # was fired before the matching npm publish landed. + - name: Verify server.json matches a published npm version + env: + VERSION: ${{ steps.target.outputs.version }} run: | node -e ' const s = require("./server.json"); @@ -125,6 +147,7 @@ jobs: } console.log(`server.json is in sync at ${v}`); ' + npm view "pseudonym-mcp@$VERSION" version - name: Install mcp-publisher run: | diff --git a/server.json b/server.json index c09787c..0071495 100644 --- a/server.json +++ b/server.json @@ -1,7 +1,7 @@ { "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.woladi/pseudonym-mcp", - "description": "MCP tools for locally pseudonymizing sensitive text before cloud LLM work and restoring tokens afterward.", + "description": "Locally pseudonymizes sensitive text before cloud LLM work and restores the tokens afterward.", "repository": { "url": "https://github.com/woladi/pseudonym-mcp.git", "source": "github" diff --git a/tests/server-manifest.test.ts b/tests/server-manifest.test.ts new file mode 100644 index 0000000..cd1d720 --- /dev/null +++ b/tests/server-manifest.test.ts @@ -0,0 +1,32 @@ +import { describe, it, expect } from 'vitest' +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' + +const readJson = (name: string): T => + JSON.parse(readFileSync(resolve(process.cwd(), name), 'utf-8')) as T + +// The MCP registry only validates server.json at publish time — which happens +// after npm has already gone out, so a rejected manifest leaves the registry +// stranded on an older version. These are the constraints that bit us (v0.7.5 +// was rejected for a 105-character description); check them in CI instead. +describe('server.json (MCP registry manifest)', () => { + const server = readJson<{ + name: string + description: string + packages: Array<{ identifier: string; registryType: string }> + }>('server.json') + const packageJson = readJson<{ name: string; mcpName: string }>('package.json') + + it('keeps the description within the registry limit of 100 characters', () => { + expect(server.description.length).toBeLessThanOrEqual(100) + }) + + it('claims the same server name as the published npm package', () => { + expect(server.name).toBe(packageJson.mcpName) + }) + + it('points at this npm package', () => { + expect(server.packages[0]?.registryType).toBe('npm') + expect(server.packages[0]?.identifier).toBe(packageJson.name) + }) +})