Skip to content

Optional Toolcraft install can dedupe AJV 8 to incompatible AJV 6 #511

Description

@kamilio

Summary

A project that declares toolcraft@0.0.109 as an optional dependency and already has AJV 6 through development tooling can receive an invalid clean npm install. npm dedupes Toolcraft's required ajv@^8.20.0 to the incompatible root AJV 6 instead of installing AJV 8 beneath the optional Toolcraft package.

The Toolcraft CLI/MCP entrypoint then fails at startup when bundled tiny-stdio-mcp-server imports AJV.

Reproduction

Use npm with a package containing:

{
  "devDependencies": {
    "eslint": "9.39.4"
  },
  "optionalDependencies": {
    "toolcraft": "0.0.109"
  }
}

Then run:

npm install --package-lock-only
rm -rf node_modules
npm ci --ignore-scripts
npm ls ajv --all
node -e 'import("toolcraft/mcp")'

Observed dependency result:

toolcraft@0.0.109
└── ajv@6.15.0 deduped invalid: "^8.20.0"

Observed startup error:

Cannot find package '.../node_modules/toolcraft/node_modules/ajv/index.js'
imported from .../toolcraft/node_modules/tiny-stdio-mcp-server/dist/server.js

The lockfile contains an intended node_modules/toolcraft/node_modules/ajv@8.20.0 entry marked optional, but npm ci does not materialize it and reuses the incompatible root AJV 6.

Workaround

Declaring ajv@8.20.0 as another direct optional dependency makes AJV 8 the root selection and moves ESLint's AJV 6 under ESLint, after which Toolcraft CLI/MCP starts correctly. This leaks another Toolcraft implementation dependency into downstream manifests.

Expected behavior

Installing optional Toolcraft must provide a compatible AJV 8 runtime even when the consuming project already uses AJV 6.

A package-side fix could bundle the AJV runtime needed by the bundled stdio server, avoid resolving it through the optional parent dependency graph, or otherwise ensure npm cannot dedupe it to an incompatible major.

Acceptance criteria

The reproduction installs cleanly with only Toolcraft declared by the consumer, npm ls ajv --all reports no invalid dependency, and importing/running toolcraft/mcp succeeds.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is not working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions