| name | bc-mcp-release |
| description | Release `business-central-mcp` to npm — bumps version, builds, tests, dry-run-inspects the tarball, publishes, and pushes the tag. Use this whenever the user wants to ship a new version, publish to npm, cut a release, tag a version, or asks "how do we release this". Also use when the user has finished a body of work and asks what's next, since release is often the natural next step after merging features. Walks through preflight checks, semver decision, and post-publish smoke. Does NOT actually run `npm publish` without explicit confirmation — releases are irreversible. |
bc-mcp release runbook
Release business-central-mcp to npm. The package is configured for manual
publish via prepublishOnly (typecheck + build); the rest is gated by you
to keep destructive operations safe.
This is a runbook, not an automated tool. Walk the user through each step,
pausing on anything destructive (version bump, publish, tag push) for
explicit confirmation. Releases are irreversible — npm allows unpublish only
within 72 hours of publish, and only if no other package depends on the
exact version.
Preflight checklist
Run these before suggesting a version bump. If any fail, stop and surface
the failure — don't paper over it.
cd U:/Git/bc-mcp
git status --short
git rev-parse --abbrev-ref HEAD
git fetch origin
git status -sb
npm run typecheck
npm test
npm run test:integration
grep -q "^## \[Unreleased\]" CHANGELOG.md && echo "OK: [Unreleased] section exists"
If integration tests can't run (no live BC), explicitly tell the user
"integration tests skipped — running CI to compensate". CI will run unit +
protocol on Node 20/22/24 against the master branch via
.github/workflows/ci.yml.
Step 1: Pick the version
Read package.json to see the current version. Compare against published
versions on npm:
npm view business-central-mcp versions --json
Decide the bump per semver:
| Change kind | pre-1.0 (0.x.y) | post-1.0 (x.y.z) |
|---|
| Bug fix only | 0.x.y patch | x.y.z patch |
| New feature, backwards-compatible | 0.x.0 minor | x.y.0 minor |
| Breaking change to public API | 0.x.0 minor (allowed pre-1.0) | x.0.0 major |
For bc-mcp specifically: the public API surface is the MCP tool output
shapes (what bc_open_page, bc_read_data, etc. return) and the env
var contract (BC_BASE_URL, BC_PROFILE, etc.). Changes to internal
protocol/services/operations are not public API.
Tell the user the proposed version and the reasoning. Wait for confirmation
before running npm version.
Step 2: Update CHANGELOG
The CHANGELOG follows Keep a Changelog.
Before bumping, rename the [Unreleased] section header to
[<version>] - YYYY-MM-DD and add a fresh empty [Unreleased] section above
it.
## [Unreleased]
### Added
### Changed
### Fixed
## [0.2.0] - 2026-04-28
### Added
... (the previous Unreleased content) ...
Commit this CHANGELOG-only change BEFORE running npm version, so the
version bump commit is solely the package.json + lockfile change. Cleaner
history.
git add CHANGELOG.md
git commit -m "docs: prepare CHANGELOG for v<version>"
Step 3: Bump version
npm version updates package.json, runs the
prepublishOnly script (typecheck + build), creates a tagged commit. It
will refuse if the working tree is dirty — that's why Step 2 commits first.
npm version <patch|minor|major>
Verify:
git log -1 --format='%H %s'
git tag --list 'v*' --sort=-creatordate | head -3
Step 4: Inspect the tarball
Before publishing, see exactly what npm will ship. The files field in
package.json is ["dist/"] — only compiled output. Verify nothing
sensitive sneaks in (no .env, no reference/, no logs/).
npm pack --dry-run 2>&1 | tail -50
Look for:
dist/stdio-server.js — the bin entry
dist/server.js — the HTTP server
package.json, README.md, LICENSE, CHANGELOG.md (auto-included)
- NOTHING from
reference/, tests/, scripts/, .env*, logs/,
docs/, *.md other than README/CHANGELOG
If the tarball looks wrong, stop and fix files or .npmignore. Don't
publish a leaky tarball — npm unpublish is restricted.
Step 5: Verify the bin shebang
The bin file (dist/stdio-server.js) must start with #!/usr/bin/env node
or npx business-central-mcp won't execute. tsc preserves shebangs from the
source by default; verify just in case.
head -1 dist/stdio-server.js
If it's missing, add the shebang to src/stdio-server.ts (top line, before
imports) and rebuild.
Step 6: Publish
This is the irreversible step. Confirm with the user before running.
npm whoami
npm publish
If 2FA is enabled, npm will prompt for a one-time code. The user must enter
it interactively — bc-mcp can't supply it.
If the package is scoped (@org/business-central-mcp), add --access public
on first publish.
Step 7: Push the tag
npm version created the tag locally; push it to GitHub:
git push --follow-tags
This triggers GitHub Actions CI on the new commit (sanity check) and makes
the tag available for issue references and changelog links.
Step 8: Post-publish smoke
Verify the publish actually worked by installing fresh in a temp dir:
cd /tmp
mkdir bc-mcp-smoke && cd bc-mcp-smoke
npm init -y > /dev/null
npm install business-central-mcp@<version>
npx business-central-mcp --help 2>&1 | head -5
ls node_modules/business-central-mcp/dist/
cd .. && rm -rf bc-mcp-smoke
If the smoke fails (binary not executable, missing files, missing
dependency), the publish is broken. Options:
- Within 72 hours:
npm unpublish business-central-mcp@<version> then
fix and re-publish a new patch version. Don't re-use the same version
number — npm forbids it even after unpublish.
- After 72 hours, or if forbidden: publish a patch on top
(e.g. 0.2.0 broken → 0.2.1 with the fix). Update the npm "deprecated"
message on the broken version:
npm deprecate business-central-mcp@0.2.0 "broken bin shebang, use 0.2.1+".
Step 9: GitHub release notes (optional)
For visibility, create a GitHub release tied to the new tag:
gh release create v<version> \
--title "v<version>" \
--notes-from-file <(awk '/^## \[<version>\]/,/^## \[/' CHANGELOG.md | sed '$d')
The awk extracts the just-released CHANGELOG section. Read the output before
running gh release create — escape characters in version numbers can trip
the regex.
Failure recovery
If something goes wrong mid-flow:
| Failure | Recovery |
|---|
npm version succeeded, npm publish failed | Fix the issue, run npm publish again. The tag is already created and harmless. |
npm publish succeeded, git push failed | git push origin master --tags separately. The package is live, the tag isn't synced — fix immediately so users can't git checkout v<version> and find nothing. |
| Wrong version published | npm unpublish business-central-mcp@<version> (within 72h) OR publish a corrected patch and npm deprecate the bad one. |
| Tarball leaked secrets | Treat as a credential rotation: revoke the leaked secret, npm unpublish if within 72h, otherwise publish a fixed version + deprecate. Tarballs on npm cache servers may persist even after unpublish. |
| CI failed on the release commit | Don't unpublish — investigate the failure. CI failures on a freshly-released commit usually mean a flaky test or a Node-version-specific issue (matrix runs Node 20/22/24). If a real regression, ship a patch ASAP. |
What the user should hand-verify
After all steps complete, ask the user to confirm:
npm view business-central-mcp version returns the new version.
npm view business-central-mcp dist-tags shows latest: <new-version>.
- The GitHub Actions CI run on the new commit is green.
- Optional:
npx -y business-central-mcp@<version> works in a fresh shell.
If any of these are wrong, flag it — the release isn't truly done.
Skipping CHANGELOG / running ad-hoc
If the user wants a quick patch publish without going through CHANGELOG
ceremony (e.g. fixing a critical post-publish bug), the minimal flow is:
npm version patch
npm publish
git push --follow-tags
This skips Step 2 (CHANGELOG) — fine for emergencies. Backfill the CHANGELOG
in the next non-emergency commit.