[PR #995] [MERGED] fix(mcp): advertise JSON values without recursive schemas #2564

Closed
opened 2026-10-17 21:07:37 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/995
Author: @kaoru0822-kitauji
Created: 10/7/2026
Status: ✅ Merged
Merged: 10/8/2026
Merged by: @N0zoM1z0

Base: main ← Head: fix/non-recursive-json-schemas


📝 Commits (4)

  • ac66a84 fix(mcp): advertise JSON values without recursive schemas
  • 12faa39 Merge remote-tracking branch 'origin/main' into fix/non-recursive-json-schemas
  • 0f87204 Merge remote-tracking branch 'origin/main' into fix/non-recursive-json-schemas
  • 7e81a29 fix(mcp): preserve catalog contracts while updating JSON schema projection

📊 Changes

9 files changed (+147 additions, -41 deletions)

View changed files

📝 docs/error-contract.schema.json (+18 -34)
📝 docs/product-catalog.json (+2 -2)
📝 docs/verification/managed-conformance-manifest.json (+2 -2)
📝 skills/reverse-engineer-anything/SKILL.md (+1 -1)
📝 src/contracts/errorSchemas.ts (+3 -1)
📝 src/contracts/toolOutputSchemaPrimitives.ts (+1 -1)
➕ src/domain/jsonValue.test.ts (+37 -0)
📝 src/domain/jsonValue.ts (+4 -0)
📝 tests/boundary/mcp/toolSchemaValidity.test.ts (+79 -0)

📄 Description

Summary

z.json() projects a self-referential definition:

"__schema0": { "anyOf": [ …, {"type":"array","items":{"$ref":"#/$defs/__schema0"}},
  {"type":"object","additionalProperties":{"$ref":"#/$defs/__schema0"}} ] }

On main, 20 of 133 tool input schemas and 123 output schemas carry it. Clients and model APIs that reject recursive JSON Schemas refuse the whole tool list (#919: Recursive JSON schemas are not currently supported).

Every JSON value satisfies {}, so the shared jsonValueSchema now advertises {} through Zod's per-schema toJSONSchema override. The two contracts that called z.json() directly (errorSchemas.ts, the MCP doctor catalog output) now use jsonValueSchema. The fix sits on the schema rather than on registration. That covers the live server, z.toJSONSchema users, the generated catalog, and docs/error-contract.schema.json.

Runtime parsing is unchanged: jsonValueSchema still rejects undefined, non-finite numbers, functions, and nested non-JSON values.

This differs from the closed #923, which rewrote cyclic $refs after projection at registration.

Scope

Refs #919, not Fixes: this removes the recursion only. Measured after this change over the live tool list ($refs now absent):

check main this PR
input schemas with a recursive $ref 20 0
output schemas with a recursive $ref 123 0
schemas using $defs at all 143 0
max input depth, object/array levels 11 11 (compare_web_captures)

The reported depth limit of 10 still applies to compare_web_captures, whose input embeds whole web-capture inspections. The issue leaves the remedy for that to maintainer choice (compact inputs vs. lowering the wire schema), so this PR does not change it.

Verification

  • src/domain/jsonValue.test.ts (new): projection has no $ref/$defs for input and output, Ajv 2020 accepts nested JSON and still rejects a non-object map; runtime parsing still rejects non-JSON values.
  • tests/boundary/mcp/toolSchemaValidity.test.ts: new recursiveReferences check over the live listTools result and GENERATED_MCP_TOOL_CATALOG. Before regenerating, the catalog assertion failed with 147 recursive references; it passes after.
  • npm run check:changed: typecheck, lint, 135 files / 1303 tests passed.
  • All tests/boundary/mcp/*.test.ts (after npm run build:cached): 56 files passed, 2 skipped.
  • npm run docs:generate then npm run docs:check: passed.
  • Built dist/main.js over real stdio MCP: 133 tools, 0 recursive schemas.

Not verified: a real opencode + Muse Spark 1.3 run. No Hopper/Ghidra/IDA verification is relevant.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/995 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/7/2026 **Status:** ✅ Merged **Merged:** 10/8/2026 **Merged by:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Base:** `main` ← **Head:** `fix/non-recursive-json-schemas` --- ### 📝 Commits (4) - [`ac66a84`](https://github.com/morluto/rea/commit/ac66a84c925179a78817fda91f64e42a37f9200e) fix(mcp): advertise JSON values without recursive schemas - [`12faa39`](https://github.com/morluto/rea/commit/12faa393d24d30fb0309242ee3e367959ec1f282) Merge remote-tracking branch 'origin/main' into fix/non-recursive-json-schemas - [`0f87204`](https://github.com/morluto/rea/commit/0f872045ba77891f5dc2cacbf47698dbcad74fc9) Merge remote-tracking branch 'origin/main' into fix/non-recursive-json-schemas - [`7e81a29`](https://github.com/morluto/rea/commit/7e81a29ed7b9d1afd7c8c21b74492227e3f87545) fix(mcp): preserve catalog contracts while updating JSON schema projection ### 📊 Changes **9 files changed** (+147 additions, -41 deletions) <details> <summary>View changed files</summary> 📝 `docs/error-contract.schema.json` (+18 -34) 📝 `docs/product-catalog.json` (+2 -2) 📝 `docs/verification/managed-conformance-manifest.json` (+2 -2) 📝 `skills/reverse-engineer-anything/SKILL.md` (+1 -1) 📝 `src/contracts/errorSchemas.ts` (+3 -1) 📝 `src/contracts/toolOutputSchemaPrimitives.ts` (+1 -1) ➕ `src/domain/jsonValue.test.ts` (+37 -0) 📝 `src/domain/jsonValue.ts` (+4 -0) 📝 `tests/boundary/mcp/toolSchemaValidity.test.ts` (+79 -0) </details> ### 📄 Description ## Summary `z.json()` projects a self-referential definition: ```json "__schema0": { "anyOf": [ …, {"type":"array","items":{"$ref":"#/$defs/__schema0"}}, {"type":"object","additionalProperties":{"$ref":"#/$defs/__schema0"}} ] } ``` On `main`, 20 of 133 tool input schemas and 123 output schemas carry it. Clients and model APIs that reject recursive JSON Schemas refuse the whole tool list (#919: `Recursive JSON schemas are not currently supported`). Every JSON value satisfies `{}`, so the shared `jsonValueSchema` now advertises `{}` through Zod's per-schema `toJSONSchema` override. The two contracts that called `z.json()` directly (`errorSchemas.ts`, the MCP doctor `catalog` output) now use `jsonValueSchema`. The fix sits on the schema rather than on registration. That covers the live server, `z.toJSONSchema` users, the generated catalog, and `docs/error-contract.schema.json`. Runtime parsing is unchanged: `jsonValueSchema` still rejects `undefined`, non-finite numbers, functions, and nested non-JSON values. This differs from the closed #923, which rewrote cyclic `$ref`s after projection at registration. ## Scope `Refs #919`, not `Fixes`: this removes the recursion only. Measured after this change over the live tool list (`$ref`s now absent): | check | `main` | this PR | |---|---|---| | input schemas with a recursive `$ref` | 20 | 0 | | output schemas with a recursive `$ref` | 123 | 0 | | schemas using `$defs` at all | 143 | 0 | | max input depth, object/array levels | 11 | 11 (`compare_web_captures`) | The reported depth limit of 10 still applies to `compare_web_captures`, whose input embeds whole web-capture inspections. The issue leaves the remedy for that to maintainer choice (compact inputs vs. lowering the wire schema), so this PR does not change it. ## Verification - `src/domain/jsonValue.test.ts` (new): projection has no `$ref`/`$defs` for input and output, Ajv 2020 accepts nested JSON and still rejects a non-object map; runtime parsing still rejects non-JSON values. - `tests/boundary/mcp/toolSchemaValidity.test.ts`: new `recursiveReferences` check over the live `listTools` result and `GENERATED_MCP_TOOL_CATALOG`. Before regenerating, the catalog assertion failed with 147 recursive references; it passes after. - `npm run check:changed`: typecheck, lint, 135 files / 1303 tests passed. - All `tests/boundary/mcp/*.test.ts` (after `npm run build:cached`): 56 files passed, 2 skipped. - `npm run docs:generate` then `npm run docs:check`: passed. - Built `dist/main.js` over real stdio MCP: 133 tools, 0 recursive schemas. Not verified: a real opencode + Muse Spark 1.3 run. No Hopper/Ghidra/IDA verification is relevant. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-17 21:07:37 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#2564
No description provided.