This file is automatically read by Claude Code on every session. Keep it updated as decisions are made. Last updated: 2026-06-03.
An open-source, CLI-first MCP package manager — "npm for MCP servers".
A registry where developers can search, install, audit, publish, and update MCP servers across all major clients (Claude Desktop, Cursor, VS Code, Windsurf) from a single tool.
npm package: @getmcpm/cli (v0.8.1) | bin command: mcpm | repo: github.com/getmcpm/cli | web UI: deferred to V1+
The MCP ecosystem has 5,800+ servers and 185M+ monthly SDK downloads, but:
- Servers are scattered across GitHub, npm, PyPI, and personal blogs
- No standardized validation — you don't know if a server works
- No security signals — 66% of servers have security findings (AgentSeal scan)
- No universal installer — each IDE uses different config formats
- No ratings, reviews, or community quality signals on any existing platform
- Discovery is word-of-mouth or Reddit threads
- 185M+ combined monthly SDK downloads (Anthropic figure)
- Python SDK: 161.5M monthly downloads on PyPI
- TypeScript SDK: ~24.5M monthly downloads on npm
- 36,864 npm projects depend on the TypeScript SDK
modelcontextprotocol/serversrepo: 76,000 GitHub stars- 5,800+ production-grade servers (873% growth in 8 months)
- Adopted by OpenAI, Microsoft, Google, AWS, Cloudflare, Bloomberg
- MCP donated to Linux Foundation's Agentic AI Foundation (AAIF) in Dec 2025
- AgentSeal: 66% of 1,808 scanned servers had security findings
- Astrix: 88% require credentials, 53% use insecure static secrets
- Cornell study: 5.5% of servers had tool-poisoning vulnerabilities
- Docker: 43% had command injection flaws
- Real incidents: Postmark MCP infostealer (1,643 downloads), RCE in
mcp-remoteaffecting 437,000+ downloads
- GitHub blog: "MCP servers scattered across numerous registries, random repos, buried in community threads"
- DEV.to: "Imagine if npm didn't exist... That's where MCP is right now"
- VS Code's Harald Kirschner: "copying around JSON blobs and hard-coding API keys"
- GitHub issues: silent MCP server failures with no helpful error messages
| Player | Strength | Weakness | Threat Level |
|---|---|---|---|
| Official MCP Registry | Authority, Anthropic-backed | Intentionally minimal, no UI, no curation | Low — they want us to build on top |
| Smithery.ai | CLI, hosted execution, 2,880+ servers | No security scanning, VC-backed centralization | Medium |
| mcp.so | Volume (19,075 servers) | Quality problems, duplicates, no CLI | Low |
| Glama.ai | Deduplication, basic scanning | Single-maintainer, no CLI | Low |
| PulseMCP | Best metadata enrichment, 12,870+ servers | No install tooling | Low |
| JFrog MCP Registry | Enterprise governance, security scanning | $532M company, enterprise pricing, not OSS | High (enterprise) |
| GitHub MCP Gallery | VS Code integration, curated | IDE-locked, Microsoft-controlled | Medium |
- Runlayer — $11M seed (Khosla + Felicis), MCP security gateway
- Alpic — €5.1M pre-seed (Partech), MCP-native cloud platform
- Manufact (mcp-use) — $6.3M YC S25, enterprise MCP infra
The official MCP Registry is intentionally a meta-registry — it stores metadata only, no UI, no curation, and explicitly invites "subregistries" to build on top. This is the green light we need.
Build the open-source, community-owned npm+npm_audit for MCP:
- CLI-first (search, install, audit, update, publish)
- Integrated security scanning in the publish pipeline
- Community quality signals (ratings, reviews — missing everywhere)
- Works across Claude Desktop, Cursor, VS Code, Windsurf
- OSS and community-owned — differentiated vs Smithery (VC) and JFrog (enterprise)
- Hosted execution (Smithery's lane)
- Enterprise governance/policy enforcement (JFrog's lane)
- A closed/VC-backed product
- Free public registry + CLI (loss leader, drives adoption)
- Private/enterprise registry with SSO + audit logs ($15–50/user/month)
- Premium security scanning as add-on
- Hosted MCP server execution (per-invocation billing) — V2
- Runtime: Node.js (>=22.0.0), TypeScript, ESM
- npm package:
@getmcpm/cli(bin command:mcpm) - CLI framework: Commander.js
- Schema validation: Zod (single source of truth for all types)
- Prompts: @inquirer/prompts (trust score UX, multi-select, confirmations)
- Output: chalk + cli-table3
- Local storage: JSON files in
~/.mcpm/(servers.json, aliases.json, cache/) - Testing: Vitest + @vitest/coverage-v8 (80% line, 75% branch thresholds)
- Build: tsup (TypeScript → JS)
- MCP server:
mcpm serveexposes 9 tools via@modelcontextprotocol/sdk(stdio transport) - Commands:
mcpm search,mcpm install,mcpm list,mcpm remove,mcpm info,mcpm audit,mcpm update,mcpm outdated,mcpm doctor,mcpm init,mcpm import,mcpm serve,mcpm disable,mcpm enable,mcpm alias,mcpm completions,mcpm export,mcpm lock,mcpm up,mcpm diff,mcpm publish,mcpm guard,mcpm secrets,mcpm why
- Official MCP Registry:
registry.modelcontextprotocol.io— we consume this, not build our own - API version: v0.1 (v0 lacks search and version filter params)
- Search:
?search=<name>— substring match on server name only (no full-text) - Pagination: cursor-based, max 100 per page,
metadata.nextCursor - Key schema:
packages[]containsregistryType(npm/pypi/oci),environmentVariables[] - Metadata:
_meta.io.modelcontextprotocol.registry/officialhasstatus,publishedAt,isLatest
- Tier 1 (built-in, zero deps): Regex-based secrets detection (with NFKC normalization), prompt injection patterns in descriptions/titles/headers/runtimeArgs, typosquatting detection, exfil-shaped argument schemas, runtime arg allowlist validation
- Tier 2 (optional): Wraps MCP-Scan if installed (
npx @invariantlabs/mcp-scan) - Trust score: 0-100 (health check 30pts, static scan 40pts, external scanner 20pts, registry metadata 10pts, capped to 0 on critical/high findings). Green ≥80, Yellow 50-79, Red <50
When community quality signals require a backend (user reviews, aggregated telemetry):
- Framework: Fastify
- Database: PostgreSQL (SQLite schema designed to ease migration)
- Cache: Redis
- Search: Typesense
- Auth: JWT + OAuth 2.1 for publisher namespaces
- Artifacts: S3 + CloudFront
- Compute: AWS ECS (Fargate)
- Framework: Next.js
- Hosting: Vercel or ECS
- Design: Minimal, developer-focused (think registry.npmjs.com)
-
mcpm search <query>— search official MCP Registry, display with trust scores -
mcpm install <name>— resolve server, trust assessment, write config for Claude Desktop + Cursor + VS Code -
mcpm list— show installed servers across all clients -
mcpm remove <name>— remove from client configs -
mcpm info <name>— full server details -
mcpm audit— scan all installed servers, tabular trust report -
mcpm update— check for newer versions, re-scan -
mcpm doctor— check MCP setup health (clients, configs, runtimes) -
mcpm init <pack>— curated starter packs (developer, data, web) - Auto-detect and import existing MCP configs on first run
- Metadata-based trust assessment on every install (Tier 1 built-in + Tier 2 MCP-Scan)
- Rich trust score visualization (color bar, breakdown)
- Cross-IDE config management (Claude Desktop, Cursor, VS Code, Windsurf experimental)
- Config backup-before-write for safety
- Cross-platform paths (macOS, Linux, Windows)
- Published to npm as
@getmcpm/cli, bin commandmcpm - CI/CD: Node 20/22/24, SHA-pinned actions, npm provenance, Snyk integration
- Security: NFKC normalization, runtime arg allowlist, file permissions, CODEOWNERS
-
mcpm serve— mcpm as an MCP server over stdio, 8 tools withregisterToolAPI - Tools:
mcpm_search,mcpm_install,mcpm_info,mcpm_list,mcpm_remove,mcpm_audit,mcpm_doctor,mcpm_setup(composite NL-to-install) - MCP tool annotations:
readOnlyHinton read tools,destructiveHinton write tools -
mcpm_setupkeyword extraction + parallel search + trust-gated install - Publish mcpm's own MCP server to the official registry (live: io.github.getmcpm/cli)
- Health check tiers (config validation → process start → list_tools verification)
- Demo recording (asciinema: https://asciinema.org/a/Oua80yhXkjz071MP)
-
mcpm disable <name>— disable a server without removing it from config -
mcpm enable <name>— re-enable a previously disabled server -
mcpm alias— short aliases for long server names (stored in ~/.mcpm/aliases.json) -
mcpm completions <shell>— shell completion scripts for bash, zsh, fish -
mcpm listnow shows disabled/active status column -
disabledfield in McpServerEntry +setServerDisabledin ConfigAdapter - Shared toggle handler (deduplicated disable/enable logic)
- Strict alias validation (alphanumeric + hyphens, max 64 chars, prototype pollution guard)
- Client ID validation before unsafe casts
- Security hardening: tool path allowlist, health check sandboxing
-
mcpm export— dump installed servers to mcpm.yaml stack file format -
mcpm lock— resolve semver ranges from registry, trust assess, write mcpm-lock.yaml -
mcpm up— batch install from mcpm.yaml with trust policy enforcement -
mcpm diff— compare installed state vs declared state (colored output + --json) -
mcpm_upMCP server tool (destructiveHint: true) - Stack file Zod schemas (mcpm.yaml + mcpm-lock.yaml) with YAML parse/serialize
- Semver version resolution (caret + tilde ranges via
semverpackage) - Trust policy enforcement with normalized percentage comparison
- .env file parser for env var resolution (process.env → .env → default → prompt)
- Parallel registry resolution, sequential config writes
- Single .bak snapshot before batch writes
- Per-server error isolation (failures collected, others continue)
- URL server support (Cursor-only, warn for other clients)
- --dry-run, --ci, --profile, --strict, --yes flags on
mcpm up - --strict --ci requires --yes for unattended server removal
- Path traversal protection on mcpm_up MCP tool input
- Prototype poisoning protection in .env parser
- Shared isEnoent() utility extracted to src/utils/fs.ts
-
mcpm publish— submit to official registry with mandatory security scan gate - User ratings and reviews (requires backend)
- Verified publisher badge
- Usage stats (installs, active users)
- Optional anonymous telemetry
-
mcpm guard enable / disable / status— auto-wraps detected client configs (Claude Desktop / Cursor / VS Code / Windsurf) with the inspection relay; per-server scope via--server -
mcpm guard run --inner— production stdio MITM using SDK framing helpers (OQ1 closed: p99 0.065ms small / 3.1ms large, 78×/8× under budget) -
mcpm guard demo— synthetic prompt-injection scenario for the launch screenshot - Pattern engine (
src/guard/patterns.ts) — NFKC + zero-width-strip + JSON leaf walk; 4 target types (tool_response / tool_call_args / tool_description / tool_annotations) - 3 vendored OWASP MCP Top 10 v0.1 signatures (mcp-1 description injection, mcp-2 response injection, mcp-7 path exfil)
- Schema pinning + drift detection (rug-pull defense) — install-time + first-session-pin fallback + per-session same-session hash cache, SHA-256 integrity sidecar
-
mcpm guard accept-drift --new-hash— re-pin after legitimate upgrade (requires explicit hash to close unbounded-window vulnerability) -
mcpm guard mute / unmute / pause— policy file editing CLI with auto-expiry, Zod-validated, integrity-sidecar-protected, lockfile-serialized -
mcpm guard cleanup— prune orphan pin entries for uninstalled servers -
mcpm guard list-signatures— show shipped catalog with OWASP category mapping -
mcpm guard reset-integrity— regenerate pins or policy sidecar after manual edits - Event log
~/.mcpm/guard-events.jsonl— append-only, parse with jq - MCPTox-derived deterministic CI fixture eval (25 attack + benign fixtures; closes OQ2 with MCPoison-equivalent rug-pull)
- FP-rate corpus measurement (5-session seed, 0/24 FP; full 20-server capture in TODOS #29)
- 6 rounds of independent security review during development; all CRITICAL + HIGH fixed before commit
- Docs: README "Runtime defense" section + docs/GUARD.md + docs/SIGNATURES.md + docs/POLICY.md
-
mcpm publish— submit to official registry with mandatory security scan gate - User ratings and reviews (requires backend)
- Verified publisher badge
- Usage stats (installs, active users)
- Optional anonymous telemetry
- Runtime proxy (mcpm-guard) — shipped in v0.5.0 (see above)
- Cross-server flow analysis — track exfil chains across tool calls (research-grade)
- Agent intent contracts — agent declares session intent, guard rejects calls outside the envelope
-
mcpm guard serve— expose guard itself as an MCP server (agents can introspect their own security perimeter) - LLM-as-judge detection tier (opt-in) — close the verbatim-attack-phrase documentation gap
- Separate signatures repo + signing (Sigstore / PGP) — when update cadence requires faster releases than @getmcpm/cli's normal cycle
- HTTP transport guard — currently stdio-only
- Private registry for orgs (SSO, audit logs, policy enforcement)
- Dependency graph (which servers compose well together)
- AI-generated docs (Claude reads source → writes human-friendly tool docs)
- Compatibility matrix (auto-tested)
- No universal installer — each IDE has different config format/location
- No
npm auditequivalent — no vulnerability DB for MCP servers - No quality signals — no ratings, reviews, or maturity indicators anywhere
- No offline browsability — tool schemas only discoverable by connecting to server
- No signed tool descriptions — enables rug-pull attacks after user approval
- No dependency resolution — users reference
@latestand discover breaks manually
- GitHub repo — the registry is the OSS project
- Seed with 100 hand-curated popular servers on day one
- Submit to Anthropic's MCP repo as a community resource
- Post: Hacker News, r/ClaudeAI, r/cursor, AI Discord servers
- Reach out to top 20 MCP server authors for early publisher partnerships
"We scanned 1,808 MCP servers and found 66% had security issues. We built the registry that npm never was for MCP — with security scanning built in from day one."
The first MCP server we build is a project context server for this codebase:
// mcp-project-context — tools:
get_architecture_doc(); // returns this CLAUDE.md
search_decisions(query); // semantic search over ADR log
add_decision_log(decision); // appends to DECISIONS.md
get_roadmap(); // returns current roadmap stateThis serves dual purpose: improves our own workflow with Claude Code, and proves the registry concept end-to-end before we launch publicly.
Developer / AI Agent
│
├── CLI (terminal) ├── MCP Server (stdio)
│ mcpm search/install/... │ mcpm serve
│ │ 9 tools via JSON-RPC
▼ ▼
mcpm core (Node.js, npm: @getmcpm/cli, bin: mcpm)
│
├── Registry ─────────► Official MCP Registry API (v0.1)
│ registry.modelcontextprotocol.io
│
├── Scanner ──────────► Trust Assessment (0-100)
│ ├── Tier 1 (built-in: secrets, injection, typosquatting)
│ └── Tier 2 (MCP-Scan, optional)
│
├── Config Adapters ──► Read/write per-client config (atomic + backup)
│ ├── Claude Desktop
│ ├── Cursor
│ ├── VS Code
│ └── Windsurf
│
└── ~/.mcpm/
├── servers.json (installed server registry)
├── aliases.json (short aliases for server names)
└── cache/ (registry response cache, 1hr TTL)
IDE (Claude Desktop / Cursor / VS Code / Windsurf)
│
│ JSON-RPC over stdio
▼
mcpm guard run --inner --server-name <name> -- <orig> [args]
│
├── Pattern engine (src/guard/patterns.ts)
│ NFKC + zero-width-strip + regex → InspectResult
│ Signatures: src/guard/signatures.ts (vendored OWASP MCP Top 10)
│
├── Schema-drift inspector (src/guard/drift.ts + run-inner.ts sync path)
│ SHA-256(description + schema + annotations) vs ~/.mcpm/pins.json
│ Per-session in-memory cache catches same-session rug-pulls
│
├── Policy filter (run-inner.ts applyPolicy)
│ ~/.mcpm/guard-policy.yaml → ignore / warn / block / log_only
│ Or short-circuit pass-through if paused_until in future
│
├── Production relay (src/guard/relay.ts)
│ SDK ReadBuffer + serializeMessage, 64MB buffer cap,
│ signal forwarding, child.stdin error swallow
│
└── Event log writer (src/guard/event-log.ts)
Append-only to ~/.mcpm/guard-events.jsonl (parse with jq)
│
▼ inspected JSON-RPC over stdio
Wrapped MCP server process (e.g. servers-filesystem)
~/.mcpm/ (guard files)
├── pins.json + pins.json.integrity (sha256 sidecar, proper-lockfile)
├── guard-policy.yaml + .integrity (sha256 sidecar, proper-lockfile, Zod-validated)
└── guard-events.jsonl (append-only)
<client config>.guard-{enable,disable}.bak (per-batch backup, written by orchestrator)
The orchestrator (src/guard/orchestrator.ts) implements two-phase commit
across detected clients: Phase 1 reads all + computes plans, Phase 2 applies
via BaseAdapter.replaceServer. Wrap transformation is centralized in
src/guard/wrap.ts and verified-once on BaseAdapter (all 4 adapters share
the same entry shape).
| Date | Decision | Rationale |
|---|---|---|
| 2026-03 | CLI-first over web-first | Developers live in terminal; npm succeeded this way |
| 2026-03 | OSS community-owned, not VC-backed | Differentiation vs Smithery; trust signal for security tool |
| 2026-03 | Build on top of official MCP Registry | They explicitly invite subregistries; no competition |
| 2026-03 | Node.js CLI (not Python) | TypeScript SDK has 3x more dependents; aligns with npm distribution |
| 2026-03-28 | npm package: @getmcpm/cli, bin: mcpm |
mcpm, mcpx, mcp-pm, mcpman all taken on npm |
| 2026-03-28 | Single package (not monorepo) | Only one consumer (CLI); extract registry client later if needed |
| 2026-03-28 | Registry API v0.1 (not v0) | v0.1 has search param and version filter |
| 2026-03-28 | JSON files, not SQLite for MVP | Zero native deps; better-sqlite3 needs node-gyp on some systems |
| 2026-03-28 | Metadata-based trust assessment (not source scan) | npx downloads at runtime, no pre-install artifact to scan |
| 2026-03-28 | Install-then-verify flow | No code runs pre-confirmation; health check is post-install |
| 2026-03-28 | Commander.js (not oclif) | Lighter, no plugin system needed for V1 |
| 2026-03-28 | @inquirer/prompts (not readline) | Security UX needs multi-select, confirm, styled trust score warnings |
| 2026-03-28 | No telemetry in V1 | Trust paradox: security tool shouldn't track users at launch |
| 2026-03-28 | Deferred Typesense/Fastify/PostgreSQL to V1+ | MVP is local-first; backend needed only when user reviews require it |
| 2026-03-30 | mcpm serve over stdio (not HTTP) |
Matches how Claude Desktop/Cursor/Claude Code consume MCP servers |
| 2026-03-30 | registerTool API with annotations |
destructiveHint on install/remove/setup, readOnlyHint on read ops |
| 2026-03-30 | No LLM in mcpm for mcpm_setup |
Calling agent handles NL understanding; mcpm does keyword extraction |
| 2026-03-30 | CI derives version from git tag | Single source of truth; no manual package.json version bumps |
| 2026-03-30 | Auto GitHub Release on publish | --generate-notes from commit history; grouped by label |
| 2026-05-16 | v0.5.0 mcpm-guard ships as v0.5.0, not v1.6 |
Office-hours user-challenge — pre-1.0 honest framing matches mcpm's actual maturity (V1.5 community trust unshipped). Versioning is a contract with users about stability. |
| 2026-05-16 | Distribution > Detection — guard's wedge is bundling into the package manager | Eng-review verified the runtime-guard market is crowded (10+ OSS proxies, Snyk acquired Invariant Labs, Microsoft Agent Governance Toolkit). Detection sophistication commoditizing fast; distribution-as-moat is the structural play. |
| 2026-05-16 | MITM substrate: SDK ReadBuffer/serializeMessage, not full Transport classes | OQ1 spike measured p99 0.065ms small / 3.1ms large with parse+reserialize — 78×/8× under budget. Eng-review caught that StdioServerTransport hardcodes process.stdin/stdout; only the framing helpers are reusable. |
| 2026-05-16 | MCP stdio is line-delimited JSON only, not Content-Length | Verified against SDK ReadBuffer.readMessage source. Eng-review F2.1's "Content-Length framing" test gap was a false positive for MCP and dropped from the conformance harness. |
| 2026-05-16 | Vendored signatures inside @getmcpm/cli for v0.5.0 |
Defer separate getmcpm/signatures repo + signing (Sigstore/PGP) until update cadence requires faster releases than @getmcpm/cli's normal cycle. Cuts v0.5.0 scope without losing detection coverage. |
| 2026-05-16 | Curated by maintainers, not crowdsourced (signatures) | uBlock-Origin-style community contribution model needs a community we don't have yet (~200 people in the world can write a credible MCP attack signature). v0.5.0 ships curated; community PRs unlocked v0.7+. |
| 2026-05-17 | Pin subprocess uses allowlisted env, not process.env passthrough | Step 5 F4.1 — full env would leak AWS_* / GITHUB_TOKEN / OPENAI_API_KEY to a just-installed server's init handler. Security regression vs current mcpm install (which doesn't execute the server at all). |
| 2026-05-17 | accept-drift requires explicit --new-hash sha256:... |
Step 6 F5 — setting current_hash: null created an unbounded "accept anything next" window an attacker could race into. User copies hash from block-message remediation. |
| 2026-05-17 | applyPolicy: MAX action across remaining findings (not single downgrade var) | Step 7 F1 CRITICAL — original implementation let log_only override on ANY one finding silently downgrade block from unrelated critical findings. Dedicated regression suite in apply-policy.test.ts. |
| 2026-05-17 | Integrity sidecars on both pins.json AND guard-policy.yaml | Step 7 F4 — a stale/naive edit of these files would otherwise go unnoticed. Sidecar is an UNKEYED SHA-256 stored beside the file with the same perms: it provides INTEGRITY (tamper-evidence vs accidental corruption / cross-machine copies / a different OS-user), NOT authenticity vs a same-user/postinstall attacker, who can recompute the sidecar to match. See revised scope 2026-06-02 (issue #19). |
| 2026-06-02 | Integrity sidecars relabeled integrity-not-authenticity (NOT anti-malware) | Security issue #19 — the 2026-05-17 row + code comments wrongly implied the unkeyed SHA-256 sidecars stop a malicious npm postinstall / same-user process. They don't: any process that can write pins.json / guard-policy.yaml can recompute and rewrite the sidecar (no attacker/writer asymmetry). A keyed scheme (HMAC/signature) needs a secret the writable store lacks — same constraint as the secret store (issue #15) — so the honest fix is relabel-only (docs + comments, no behavior change); true authenticity (OS keychain / signed releases) deferred. docs/GUARD.md + docs/POLICY.md already stated this correctly; this reconciles pins.ts, policy.ts, and the Decisions Log. |
| 2026-05-17 | Zod-validated YAML parse with .catch({}) fallback |
Step 7 F2 — paused_until: 99999999999999 (numeric, not ISO string) would otherwise bypass all inspection because new Date(numeric) is year 5138. Fall back to empty policy on any structural mismatch. |
| 2026-05-17 | Same-session "first hash seen" cache | Step 6 F3 — closes the double-tools/list bypass where a malicious server delivers benign-then-poisoned schemas before the off-thread pin write commits. |
| 2026-05-17 | FP-rate threshold 2%; effective floor 4% on the 24-message seed | Step 9 — the threshold becomes meaningful at corpus sizes ≥ 50. Documented inline in fp-rate.test.ts. Full 20-server capture is TODOS #29. |
| 2026-05-17 | MCPTox attack fixtures hand-authored from public methodology, not vendored | Step 8 closes OQ3 — sidesteps the MCPTox redistribution license question. Hand-authored from Invariant Labs disclosure / MCPoison CVE / Equixly-Pillar audits. License-clean. |
| 2026-06-01 | Secret store keyed by machine id (hostname + username), not a real secret | Zero-native-deps constraint (no keytar). AES-GCM with a machine-derived key protects against casual local inspection, NOT same-account file exfiltration — a copied secrets.enc.json decrypts on the same OS account. Runtime notices + docs reworded to drop any exfil-resistance claim. True at-rest resistance (OS keychain / user passphrase) deferred (security issue #15). |
| 2026-06-03 | MCP tool input schemas hardened: bounded name (1–256), client as z.enum(CLIENT_IDS), strictObject |
Security issue #31. The bounded fields + client enum live on the per-field schemas, so they propagate to the live MCP boundary through the SDK's .shape consumption; the object-level strict setting does NOT survive .shape (SDK rebuilds a plain z.object), so the runtime validateMcpServerName / CLIENT_IDS.includes guards in handlers.ts remain the enforced backstop. strict hardens direct .parse() of the exported schemas. Dependabot half of #31 (github-actions + npm) already shipped in .github/dependabot.yml. |
| 2026-06-03 | Secret store gains real exfiltration resistance via an OS-keychain master key — SUPERSEDES 2026-06-01 deferral | Security issue #15. A random 32-byte master key is held in the OS credential store via zero-native-dep shell-outs (macOS security, Linux secret-tool/libsecret, Windows DPAPI-blob via PowerShell — no keytar, constraint preserved); per-value AES-GCM keys are derived from it with HKDF. Because the master key never lands in ~/.mcpm, a copied secrets.enc.json cannot be decrypted off-machine/-account. New entries are tagged k1:; legacy machine-scheme entries stay decryptable and mcpm secrets migrate upgrades them. Where no OS keychain exists (headless/CI, or MCPM_DISABLE_OS_KEYCHAIN=1) it falls back to the honestly-labelled machine key. secrets set now reports which backend actually protected the value. Tests force the fallback via MCPM_DISABLE_OS_KEYCHAIN=1 (vitest.setup.ts) so the suite never touches a real keychain; os-keychain.ts dispatch is unit-tested with mocked spawn. CI is ubuntu-only, so the macOS/Windows shell-outs are not exercised in CI — verified locally on darwin. Known tradeoff (security review, MEDIUM): macOS passes the master key in security argv (the binary has no reliable non-interactive stdin path), briefly visible to a same-user ps during the write; bounded (write-only window; a same-user attacker can already read process memory; read path uses stdout). Linux passes via stdin, Windows via env var. Documented in os-keychain.ts. |
When helping with this project:
- We are building
mcpm— an open-source MCP package manager (npm:@getmcpm/cli) - Trust assessment is a core feature, not an afterthought
- We are OSS-first — avoid design decisions that require proprietary lock-in
- Check
docs/ARCHITECTURE.mdfor the detailed implementation plan - Check
TODOS.mdfor blockers and deferred work - The official MCP Registry API v0.1 is at
registry.modelcontextprotocol.io - V1 is local-first: no server infrastructure, JSON files in
~/.mcpm/ - Immutable data patterns: always return new objects, never mutate
- All config writes use atomic write-then-rename with backup-before-write
- Existing competitors: mcpm.sh, mcp-get, mcpman — we differentiate on trust assessment
Use the /browse skill from gstack for all web browsing. Never use mcp__claude-in-chrome__* tools.
Available gstack skills:
/office-hours, /plan-ceo-review, /plan-eng-review, /plan-design-review,
/design-consultation, /review, /ship, /land-and-deploy, /canary,
/benchmark, /browse, /qa, /qa-only, /design-review,
/setup-browser-cookies, /setup-deploy, /retro, /investigate,
/document-release, /codex, /cso, /careful, /freeze, /guard,
/unfreeze, /gstack-upgrade
If gstack skills aren't working, run cd .claude/skills/gstack && ./setup to build the binary and register skills.