Thanks for your interest. mcpm is a security tool, so the bar is correctness and determinism over feature breadth.
AGENTS.md is the shared contributor entry point; Claude Code imports it through CLAUDE.md. Repo-owned development/release skills and current project context are indexed in maintainer workflow. The separately distributed public mcpm usage skill is for CLI consumers; installing the npm package does not install contributor skills.
Requires Node.js ^22.22.2 || ^24.15.0 || >=26.0.0 and pnpm 10. That range is
the intersection of every runtime dependency's own engines, not a preference —
src/__tests__/engines-invariant.test.ts fails the build if package.json promises
a Node a dependency does not support.
pnpm install --frozen-lockfile
pnpm run typecheck # tsc --noEmit + tooling configs (this is also `lint`)
pnpm run build # tsup -> dist/
pnpm test # vitest
pnpm run test:coverage # with coverage
CI uses pnpm install --frozen-lockfile. package.json carries pnpm.overrides;
Dependabot's regenerated pnpm-lock.yaml drops that block, so npm bump PRs fail
with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH before tests run. Refresh the lockfile
locally with pnpm update <pkg> (not frozen) so the overrides survive, rather than
merging Dependabot's lockfile. GitHub Actions bumps are unaffected.
@types/node is pinned to the engines floor (22), so a local typecheck only proves
the code compiles against Node 22's API. CI re-runs it per matrix leg against that
leg's own typings. To reproduce a Typecheck against @types/node <major> failure,
use an isolated clean checkout so restoring the two experiment files cannot erase existing work:
pnpm add -D @types/node@26 # or 24 — the major CI failed on
pnpm run typecheck
git checkout -- package.json pnpm-lock.yaml
pnpm dogfood:release packs the tarball, clean-installs it, and smoke-runs the real
binary. The supported tag-release workflow requires this gate before publishing.
A direct local pnpm publish only runs the package's build lifecycle hook; it does not
automatically run this smoke. The smoke uses your local build and needs a Node
inside engines.node.
To smoke an already-published version instead, set MCPM_DOGFOOD_SPEC — the same
script, same assertions, no build and no pnpm:
MCPM_DOGFOOD_SPEC=@getmcpm/cli@latest ./scripts/dogfood-release.sh
Three places to run that, in increasing order of "not your machine":
| where | how | good for |
|---|---|---|
| your machine | the command above | fastest, but needs a conforming Node, and it is your machine |
| a container | docker run --rm -v "$PWD/scripts:/w/scripts:ro" -w /w -e MCPM_DOGFOOD_SPEC=@getmcpm/cli@latest node:26 ./scripts/dogfood-release.sh |
any Node major, disposable, no local Node needed |
| GitHub | Actions → Dogfood → Run workflow | Node 22/24/26 + macOS, zero local setup |
The release script sets a throwaway $HOME for its CLI smoke commands, so
doctor sees synthetic client state. Build, pack and npm installation happen
before that switch and use the normal home/caches; this is not an OS sandbox
for package installation. dogfood-confine.sh also uses a disposable home for
its fixture commands; pnpm dogfood:confine builds before running that script.
macOS-only end-to-end check for the --confine sandbox:
pnpm dogfood:confine # hermetic; must print "✓ confine dogfood PASSED"
For offline direct/guarded stdio comparisons using the pinned published release
and official SDK v1/v2 peers, run bash scripts/dogfood-protocol.sh /tmp/mcpm-protocol-evidence.
Docker provisions the test dependencies, then runs with no network or host
mounts. See the matrix, evidence and limits.
For installed VS Code/Claude Code checks inside disposable macOS VMs, see
native client validation, including its
account/VM-free self-check command. Native VM runs require the separately pinned
public client/runtime payload.
Candidate changes must use the explicit candidate mode and a fresh packed CLI;
a passing published-baseline run does not validate changed production code.
Use the separate --approvals native suite for default tool consent; the
ordinary lifecycle suite preapproves fixture tools and cannot establish that
permission behavior.
- Tests first, and they must pass. New behaviour needs a test; bug fixes need a
failing repro test that your change turns green. Keep the suite and
typecheckgreen — CI runs them on Node 22/24/26. - Local-first, deterministic, no telemetry. The default path makes no model-API calls and sends no usage data. Don't add a hosted backend or a network call on a path the user didn't ask for. New runtime dependencies are avoided; if one is genuinely needed, call it out explicitly in the PR.
- Validate at the boundary. External data (registry responses, config files, tool traffic) is parsed through Zod before use. Fail closed on integrity/security boundaries; state boundaries honestly in user-facing copy.
- Conventional commits.
feat:,fix:,refactor:,docs:,test:,chore:,perf:,ci:. UpdateCHANGELOG.mdunder## [Unreleased]for user-visible changes.
Keep PRs single-purpose and small enough to review. Describe the problem, the change,
and how you verified it. Changes under .github/workflows/ require CODEOWNERS
review.
See SECURITY.md — please do not open a public issue for a vulnerability.