Skip to content

fix: repair tool schemas before AJV compilation to prevent MissingRefError#355

Merged
davideast merged 1 commit into
mainfrom
fix/schema-repair-before-ajv
May 12, 2026
Merged

fix: repair tool schemas before AJV compilation to prevent MissingRefError#355
davideast merged 1 commit into
mainfrom
fix/schema-repair-before-ajv

Conversation

@davideast
Copy link
Copy Markdown
Collaborator

Problem

The MCP SDK (≥1.27) introduced Client.cacheToolMetadata() which eagerly compiles outputSchema with AJV during listTools(). When the Stitch backend returns schemas with $ref to missing $defs (e.g. #/$defs/ScreenInstance, #/$defs/SelectedScreenInstance), AJV throws a MissingRefError before the SDK's existing schema repair code can run.

This causes a hard crash for all consumers:

  • stitch-mcp CLI (bun run src/cli.ts tool list → crash)
  • Any MCP client connecting through StitchProxy
  • Any agent using StitchToolClient.listTools()

Root Cause

CLI → StitchToolClient.listTools()
        → this.client.listTools()          // MCP SDK Client
            → request('tools/list')        // ✅ fetches tools from Stitch
            → cacheToolMetadata(tools)     // 💥 AJV compiles outputSchema, hits missing $ref
        → schema repair code              // ❌ never reached

The schema repair in client.ts ran after this.client.listTools(), but Client.listTools() crashes internally during AJV compilation before returning.

Solution

1. New schema-repair.ts module

Extracted schema repair into a standalone, reusable module that:

  • Scans both inputSchema and outputSchema for $ref targets recursively
  • Injects well-known stub definitions only when referenced but missing
  • Never overwrites existing $defs (preserves backend-provided definitions)
  • Handles ScreenInstance, SelectedScreenInstance, and File types

2. StitchToolClient.listTools() — bypass AJV compilation

Replaced this.client.listTools() with a raw this.client.request() call using ListToolsResultSchema. This bypasses cacheToolMetadata() entirely, allowing schema repair to run first.

3. StitchProxy.refreshTools() — repair before re-serving

Applied repairToolSchemas() in the proxy's refreshTools() so tools are repaired before being re-served to downstream MCP clients whose AJV validators would also crash.

4. Public API export

Exported repairToolSchemas and repairSchema from the SDK's public API for consumers that need custom tool processing pipelines.

Testing

  • 13 new unit tests in schema-repair.test.ts covering injection, preservation, nesting, unknown refs, null safety
  • 170/170 existing tests pass (0 regressions)
  • TypeScript compilation clean
  • End-to-end verified: packed 0.3.5 tarball installed in stitch-mcp, tool list works

Files Changed

File Change
packages/sdk/src/schema-repair.ts New — standalone schema repair module
packages/sdk/src/client.ts listTools() uses raw request() + repairToolSchemas()
packages/sdk/src/proxy/client.ts refreshTools() applies repairToolSchemas()
packages/sdk/src/index.ts Exports repairToolSchemas, repairSchema
packages/sdk/test/unit/schema-repair.test.ts New — 13 unit tests
packages/sdk/package.json Version bump 0.3.40.3.5

…Error

The MCP SDK (≥1.27) introduced Client.cacheToolMetadata() which eagerly
compiles outputSchema with AJV during listTools(). When the Stitch
backend returns schemas with $ref to missing $defs (e.g.
#/$defs/ScreenInstance), AJV throws MissingRefError before the SDK's
schema repair code can run.

Fix:
- Extract schema repair into a standalone module (schema-repair.ts)
  that scans for $ref targets and injects well-known stub definitions
- In StitchToolClient.listTools(): use raw request() instead of
  Client.listTools() to bypass AJV compilation, then apply repair
- In proxy refreshTools(): apply repair before re-serving tools to
  MCP clients whose AJV validators would also crash

The repair module:
- Scans both inputSchema and outputSchema for $ref targets
- Only injects stubs for referenced-but-missing well-known defs
- Never overwrites existing $defs
- Handles ScreenInstance, SelectedScreenInstance, and File types

Includes 13 unit tests covering injection, preservation, nesting,
unknown refs, and null safety.
@davideast davideast merged commit 23e5230 into main May 12, 2026
6 checks passed
@davideast davideast deleted the fix/schema-repair-before-ajv branch May 12, 2026 20:42
davideast added a commit to davideast/stitch-mcp that referenced this pull request May 12, 2026
Fixes AJV MissingRefError crash on tool list by upgrading to the
SDK version that repairs schemas before AJV compilation.

See google-labs-code/stitch-sdk#355
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