Skip to content

fix(validators): cache compiled schemas to prevent memory leak (#2605) - #2608

Open
elang2 wants to merge 1 commit into
modelcontextprotocol:mainfrom
elang2:fix/ajv-validator-memory-leak
Open

fix(validators): cache compiled schemas to prevent memory leak (#2605)#2608
elang2 wants to merge 1 commit into
modelcontextprotocol:mainfrom
elang2:fix/ajv-validator-memory-leak

Conversation

@elang2

@elang2 elang2 commented Aug 3, 2026

Copy link
Copy Markdown

Summary

  • Add content-keyed compilation cache (Map<string, AjvValidateFunction>) to AjvSchemaValidatorProvider and CfWorkerSchemaValidatorProvider
  • Schemas without $id were recompiled on every getValidator() call, leaking Ajv instances over time
  • Cache key uses JSON.stringify(schema) with JSON.parse(key) for compilation (avoids stale identity-cache hits from mutated schemas)
  • Non-serializable schemas (cyclic refs, BigInt) gracefully fall back to uncached compilation

Test plan

  • 10 new tests in validatorCaching.test.ts covering: cache hits, content changes, $id preservation, mutation safety, error isolation
  • All 1443 tests pass (1433 existing + 10 new)
  • TypeScript typecheck passes
  • ESLint + Prettier clean

Fixes #2605

… leak (modelcontextprotocol#2605)

Add content-keyed caches to AjvJsonSchemaValidator and CfWorkerJsonSchemaValidator
so that schemas without $id are not recompiled on every getValidator() call. This
prevents Ajv's internal scope from growing without bound in long-running MCP clients
that periodically refresh their tool catalogue.

The cache key is the JSON-serialised schema content. Schemas with $id continue to use
Ajv's built-in identity cache. Non-serialisable schemas (cyclic, BigInt) fall back to
uncached compilation.
@elang2
elang2 requested a review from a team as a code owner August 3, 2026 00:04
@changeset-bot

changeset-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 2dde718

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Aug 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2608

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2608

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2608

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2608

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2608

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2608

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2608

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2608

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2608

commit: 2dde718

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.

Memory leak: AjvJsonSchemaValidator.getValidator() recompiles schemas without $id on every call

1 participant