Skip to content

@genclass/mcp: the plugin ships the launcher's lockfile for the Anthropic directory - #125

Merged
Karanvir1729 merged 1 commit into
mainfrom
claude/busy-hawking-abb88b
Oct 28, 2026
Merged

Karanvir1729 merged 1 commit into
mainfrom
claude/busy-hawking-abb88b

Conversation

@Karanvir1729

Copy link
Copy Markdown
Collaborator

What

The Claude Code plugin folder (packages/mcp/plugin/) now ships package.json (private; its one dependency is @genclass/mcp at the package's version) and package-lock.json (lockfileVersion 3; @genclass/mcp@0.2.1 with its registry tarball and sha512 integrity, 659 bytes), generated with npm install --package-lock-only --ignore-scripts in that folder. No node_modules is committed and the root package-lock.json is untouched. The daily sync carries both files to genclass-dev/genclass-plugin (the generator test, byte-identical copy within 256 KiB per file and 512 files, passes with them).

Anthropic's directory validator said on 2026-10-28 (genclass-dev/genclass-plugin, main @ e911b25): warning "Launcher lock missing · .mcp.json · mcpServers.genclass: Ship a package-lock.json (npm ci) or uv.lock next to the manifest that declares this server; exact versions, registry sources and hashes are required for the Verified badge", and a policy hold "Runs a pinned npx or uvx package (2 findings): Prefer a package that ships a lockfile, or vendor the package's readable source into the plugin and run it from ${CLAUDE_PLUGIN_ROOT}".

Expected to clear, and what it cannot

  • Clears "Launcher lock missing": package.json and package-lock.json sit next to .mcp.json at the plugin root, with the exact version, the registry source and the integrity, which is what the warning asks for.
  • Cannot clear by itself: the hold "Runs a pinned npx or uvx package" (2 findings, .mcp.json and hooks/hooks.json). Its text prefers "a package that ships a lockfile", which the plugin now does, but a hold is a reviewer's decision, and the launchers still run npx -y @genclass/mcp@0.2.1. The certain way around it remains vendoring dist/cli.js into the plugin and running it from ${CLAUDE_PLUGIN_ROOT} (a committed build output; left to the owner, as docs/adoption/listings/mcp.md says).
  • Possibly still "MCP server command wasn't read" (the server is not a file inside the plugin folder).

Local validator

claude plugin validate --profile directory (Claude Code 2.1.311) on the assembled tree (node packages/mcp/scripts/plugin-repo.mjs <out>) says "These checks found nothing to report", with and without the lock, also with --strict: the lockfile check runs in the portal only. CI's pinned @anthropic-ai/claude-code@2.1.296 plugin validate ... --strict passes on the plugin folder and the repository root.

What the lock does at install time (verified)

Claude Code 2.1.311 installs a plugin's dependencies when it installs the plugin if package.json and a v2/v3 package-lock.json (or npm-shrinkwrap.json, bun.lock) are at the plugin root: npm ci --ignore-scripts --workspaces=false --no-audit --no-fund in the plugin's cache folder. Installing the assembled plugin into an isolated CLAUDE_CONFIG_DIR put node_modules/@genclass/mcp 0.2.1 (1.3 MB unpacked) under plugins/cache/genclass/genclass/0.2.1/. The launchers are unchanged, so that copy is not what runs. .mcp.json could later point at ${CLAUDE_PLUGIN_ROOT}/node_modules/@genclass/mcp/bin/genclass-mcp.mjs, but a Claude Code without the installer would then have no server, so that is not done here. npm pack also puts plugin/package.json and plugin/package-lock.json into the @genclass/mcp tarball (the plugin folder is in files); harmless.

The test (packages/mcp/test/manifests.test.ts)

  • plugin/package.json is a JSON pin: its dependency equals package.json's version; the sync rewrites it.
  • plugin/package-lock.json is a lock pin: lockfileVersion 3, the root dependency on @genclass/mcp at the version, that entry resolved to the registry tarball of that version, every entry with an exact version, a registry source and a sha512 integrity. A missing integrity fails and is never rewritten: only npm writes the lock.
  • The release window. Only npm can write the lock, and only once npm serves the version, while release-mcp.yml runs these tests at the tag before publishing and mcp.yml runs them on the bump commit. So between a bump and its release the lock may stay at the previous release, consistent at its own version, while npm does not serve the new version (asked with npm view in that state only: E404 means not served; an unreachable npm counts as unknown and passes with a note that --silent=false shows). Once npm serves it, the test fails until the lock is regenerated. In the steady state no npm call is made.
  • npm run sync -w @genclass/mcp (GENCLASS_SYNC=1) regenerates the lock with npm install --package-lock-only --ignore-scripts when it is not at the version; while npm does not serve the version (ETARGET) the lock stays. A release is therefore: bump, sync, tag; after the publish, sync again and commit the lock. In that window the daily sync carries a lock one release behind to the plugin repository.
  • Checked by hand: steady state (35 tests pass, no npm call); the sync as a no-op; a stale lock at 0.2.0 while npm serves 0.2.1 fails on the lock pin alone, naming the three problems, and the sync regenerates it byte-identical to the committed one; a simulated bump to 0.2.2 (sync pins everything, the lock stays at 0.2.1 with npm's ETARGET, the plain run passes 35/35). Pre-existing and unchanged: a sync run that rewrites files reports the skill-copy and generator tests stale in that same run; the next run passes.

Docs

packages/mcp/CHANGELOG.md (Unreleased), docs/adoption/listings/mcp.md section 3 ("What the checks will say"), one sentence in the plugin README.

Checks run

npm run typecheck -w @genclass/mcp, npm run build -w @genclass/mcp, cd packages/mcp && npx vitest run: 12 files, 149 tests pass. Not run: the e2e (race.e2e.mjs) and the bundle. Nothing published; nothing pushed besides this branch.

🤖 Generated with Claude Code

…ge.json, package-lock.json)

Anthropic's directory validator warned "Launcher lock missing" for mcpServers.genclass in .mcp.json
(2026-10-28, genclass-dev/genclass-plugin main @ e911b25): a package-lock.json next to the manifest that
declares the server, with exact versions, registry sources and hashes, is required for the Verified badge,
and its hold on pinned npx launchers prefers a package that ships a lockfile.

- plugin/package.json: private, one dependency, @genclass/mcp at package.json's version.
- plugin/package-lock.json: lockfileVersion 3, from `npm install --package-lock-only --ignore-scripts` in
  the plugin folder (the version, its registry tarball, its sha512 integrity; 659 bytes). No node_modules
  committed; the root package-lock.json is untouched. The daily sync carries both to genclass-plugin.
- test/manifests.test.ts: package.json is a JSON pin; the lock is a lock pin (lockfileVersion 3, the root
  dependency and the entry at the version, resolved to the registry tarball, every entry with an exact
  version, a registry source and a sha512 integrity; a missing integrity fails, never rewrites). Only npm
  writes the lock, and only once npm serves the version, while release-mcp.yml runs the tests at the tag
  before publishing: between a bump and its release the lock may stay at the previous release, consistent
  at its own version, while npm does not serve the new one (npm view, in that state only); once npm serves
  it the test fails until the lock is regenerated. The sync regenerates it with the npm command.
- Claude Code 2.1.311 installs a plugin's lockfile when it installs the plugin (npm ci --ignore-scripts
  --workspaces=false --no-audit --no-fund in the plugin's cache folder); the launchers still run npx.
- CHANGELOG (Unreleased), docs/adoption/listings/mcp.md section 3, one sentence in the plugin README.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@MeharPro
MeharPro force-pushed the claude/busy-hawking-abb88b branch from 5208c73 to 14c2cf0 Compare October 28, 2026 17:01
@Karanvir1729
Karanvir1729 merged commit d15192a into main Oct 28, 2026
5 checks passed
@MeharPro
MeharPro deleted the claude/busy-hawking-abb88b branch October 28, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant