Help us improve
Share bugs, ideas, or general feedback.
From obsidian-mcp-server
Publishes a release to npm, MCP Registry, GitHub Releases, and GHCR after git wrapup (version bumps, changelog, commit, tag) is complete. Retries transient network failures and reports partial-state on terminal errors.
npx claudepluginhub cyanheads/cyanheads --plugin obsidian-mcp-serverHow this skill is triggered — by the user, by Claude, or both
Slash command
/obsidian-mcp-server:release-and-publishThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill runs **after** git wrapup. By the time it's invoked:
Publishes a release to npm, MCP Registry, GitHub Releases, and GHCR after git wrapup (version bumps, changelog, commit, tag) is complete. Retries transient network failures and reports partial-state on terminal errors.
Publishes a release to npm, MCP Registry, GitHub Releases, and GHCR after git wrapup. Retries transient network failures and reports partial state on terminal errors.
Guides npm publishing for @mcp-b monorepo packages using changesets: validate build/test/typecheck, create/apply changesets for version bumps and CHangelogs, NPM_TOKEN auth, pnpm publish -r in topological order.
Share bugs, ideas, or general feedback.
This skill runs after git wrapup. By the time it's invoked:
field-test, security-pass, polish-docs-meta as applicable)package.json version is bumpedchangelog/<major.minor>.x/<version>.md is authoredCHANGELOG.md is regeneratedchore: release v<version>) existsv<version>) exists locallyIf any are missing, halt and tell the user to finish wrapup first. Do not attempt to redo wrapup work from inside this skill.
Steps 3–7 are network-bound. For those, retry transient failures up to 2 times with short backoff (~5 s before the first retry, ~15 s before the second) before halting. All other steps halt on the first non-zero exit — they're deterministic and a second attempt won't change the outcome.
Match stderr (case-insensitive) against any of these — if matched, the failure is almost always a network blip; retry:
integrity check failed / IntegrityCheckFailed — corrupt tarball during downloadECONNRESET / EAI_AGAIN / ETIMEDOUT / ENOTFOUND — network layerconnection reset / connection refused — transport bliptimed out / request timeout — server or network timeout502 / 503 / 504 — transient registry errorBefore retrying docker buildx --push (step 7), run docker builder prune -f to drop any cached corrupt layer. Skip this extra step for other retries.
These mean the step already succeeded on a prior run — treat as success and proceed to the next step:
bun publish): version already exists, You cannot publish over the previously published versionsmcp-publisher publish): cannot publish duplicate versiongh release create): release already exists — fall back to gh release upload --clobber (see step 6)If retries are exhausted, or the failure matches none of the transient patterns, halt and report:
.mcpb? GHCR?) — the partial state across destinationsThe user fixes locally and re-invokes. On re-invocation, already-published destinations hit the idempotent-success signal and skip naturally — no manual step-skipping required.
Read package.json → capture version. Then use your git tools to verify:
v<version> — matches the package.json versionIf working tree is dirty or HEAD isn't on v<version>, halt.
All three must succeed. Check package.json scripts for test:all; if absent, fall back to test:
bun run devcheck
bun run rebuild
bun run test:all # or `bun run test` if no test:all
Any non-zero exit → halt with the failing command's output.
Use your git tools to push the branch commits first, then push tags to origin. If the remote rejects either push, halt.
bun publish --access public
bun publish uses whatever npm auth the user has configured in ~/.npmrc. If 2FA is enabled on the npm account, the command will prompt for an OTP or open a browser — that's expected; the user completes it interactively.
Friction reducers (optional, configure once):
| Option | How |
|---|---|
| npm granular access token with "Bypass 2FA for publish" | Generate at npmjs.com → replace _authToken in ~/.npmrc → no OTP prompt at all |
1Password CLI TOTP injection (requires brew install --cask 1password-cli + signed-in op) | bun publish --access public --otp="$(op item get 'npm' --otp)" |
Halt on publish error other than "version already exists" (which means this step already ran).
Only if server.json exists at the repo root (otherwise skip). Note: server.json (MCP Registry metadata) and manifest.json (MCPB bundle manifest, step 6) are independent — a project may have either, both, or neither.
bun run publish-mcp
If publish-mcp isn't defined in package.json, add it permanently (one-time setup, macOS):
"publish-mcp": "mcp-publisher login github -token \"$(security find-generic-password -a \"$USER\" -s mcp-publisher-github-pat -w)\" && mcp-publisher publish"
Prereq: a GitHub PAT with read:org + read:user scopes stored in Keychain under the service name mcp-publisher-github-pat:
security add-generic-password -a "$USER" -s mcp-publisher-github-pat -w
# paste PAT at the silent prompt
Halt on any publisher error other than "cannot publish duplicate version".
For all projects (including those without manifest.json):
bun run release:github
The script (scripts/release-github.ts) handles everything in one command:
version from package.jsongit for-each-ref refs/tags/v<version>gh release create v<version> --verify-tag --notes-from-tag --title "v<version>: <subject>"dist/*.mcpb when manifest.json exists (skip the bun run bundle step first if not already built — see below).mcpb asset (if applicable) and patches the title via gh release editIf manifest.json exists, build the bundle first so the asset is ready:
bun run bundle # produces dist/<name>.mcpb (stable filename, no version)
bun run release:github # attach + release in one step
The stable filename matters: it lets the README "Install in Claude Desktop" badge point at releases/latest/download/<name>.mcpb and always resolve to the most recent release. The bundle script in the templates outputs dist/{{PACKAGE_NAME}}.mcpb for this reason.
Deterministic download URLs (for MCPB projects):
https://github.com/<OWNER>/<REPO>/releases/download/v<VERSION>/<name>.mcpbhttps://github.com/<OWNER>/<REPO>/releases/latest/download/<name>.mcpbIf server.json includes an MCPB packages[] entry, its identifier should match this URL and fileSha256 should match shasum -a 256 <bundle> — keep these in sync during wrapup, not here.
Framework note: mcp-ts-core has no manifest.json — the bundle attach path is skipped automatically. Skip the Docker build/push step too (this framework package is consumed via npm, not as a container image).
Halt on any non-zero exit not handled by the script's built-in fallback.
Only if Dockerfile exists at the repo root (otherwise skip).
Derive:
OWNER/REPO from the origin remote URL — use your git tools to read it; strip .git, handle both https://github.com/<owner>/<repo> and git@github.com:<owner>/<repo> formsVERSION from package.json (step 1)docker buildx build --platform linux/amd64,linux/arm64 \
-t ghcr.io/<OWNER>/<REPO>:<VERSION> \
-t ghcr.io/<OWNER>/<REPO>:latest \
--push .
If the project uses a non-GHCR registry or a custom image name, respect the project's convention. If push fails with a 401/403, prompt the user to authenticate (echo $GITHUB_TOKEN | docker login ghcr.io -u <OWNER> --password-stdin) and retry. Halt on build failure or non-auth push failure.
Print clickable URLs for every destination that succeeded:
https://www.npmjs.com/package/<package.json#name>/v/<version>https://registry.modelcontextprotocol.io/v0.1/servers/<mcpName>/versions/<version> — mcpName is the name field from server.json (URL-encode the / as %2F)https://github.com/<OWNER>/<REPO>/releases/tag/v<VERSION> (with .mcpb asset attached)ghcr.io/<OWNER>/<REPO>:<VERSION>Skip any destination that was skipped in its step.
Confirm each published artifact is actually live — don't rely on a successful push exit code alone. For each destination that succeeded:
npm view <package.json#name>@<version> version — must return the version stringcurl -s "https://registry.modelcontextprotocol.io/v0.1/servers/<mcpName>/versions/<version>" — must return HTTP 200 with server.version matching <version> (mcpName is the name field from server.json; URL-encode / as %2F). The search endpoint (/v0.1/servers?search=) paginates and may not include the latest version for packages with many releases — always use the direct version lookup.gh release view v<VERSION> -R <OWNER>/<REPO> --json assets --jq '.assets[].name' — must list the .mcpb filecurl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" "https://ghcr.io/v2/<OWNER>/<REPO>/manifests/<VERSION>" — must return HTTP 200If any check fails, halt and report which destination is unreachable. A successful docker push or bun publish exit code does not guarantee the artifact is queryable — registry propagation delays, auth scoping, and partial failures all exist.
v<version>; current branch name noted for pushbun run devcheck passesbun run rebuild succeedsbun run test:all (or test) passesbun publish --access public succeedsbun run publish-mcp succeeds (if server.json present)bun run bundle (if manifest.json present) + bun run release:github succeedsDockerfile present)