Skip to content

fix(agent-runtime): keep MCP schemas JSON-serializable - #877

Open
fortissolucoescontato-bit wants to merge 1 commit into
CodebuffAI:mainfrom
fortissolucoescontato-bit:fix/mcp-json-schema-serialization
Open

fix(agent-runtime): keep MCP schemas JSON-serializable#877
fortissolucoescontato-bit wants to merge 1 commit into
CodebuffAI:mainfrom
fortissolucoescontato-bit:fix/mcp-json-schema-serialization

Conversation

@fortissolucoescontato-bit

Copy link
Copy Markdown

Summary

Keeps MCP tool input schemas as plain JSON Schema objects while they are stored
in the agent runtime.

Previously, MCP input schemas were converted to Zod schemas before storage.
Those Zod instances contain circular internal references and could reach a
JSON.stringify boundary, causing normal Freebuff prompts to fail with:

JSON.stringify cannot serialize cyclic structures

The runtime now preserves the original JSON Schema and converts through
ensureZodSchema only at the point where schema consumption or validation is
required.

Behavior

  • MCP tool definitions remain JSON-serializable
  • input schemas preserve their JSON Schema representation
  • Zod conversion still occurs when consumed (ensureZodSchema in getToolSet)
  • normal prompts work with MCP servers enabled
  • Engram tools can be listed and invoked
  • no circular serialization error is produced

Verification

  • schema handling tests: 15/15 passing
  • mcp schema serialization unit tests: 13/13 passing
  • mcp schema integration tests: 3/3 passing
  • agent-runtime tests: 475/477 (2 pre-existing missing-module failures)
  • SDK build: PASS
  • Freebuff build: PASS
  • TUI post-install: no cyclic error, no auth error

Note

This PR is independent from the read-only /mcp status command in PR #876.

Store MCP tool input schemas as plain JSON Schema objects instead of
converting them to Zod schemas before storage. Zod schemas contain
circular internal references that cause JSON.stringify to fail with
'cannot serialize cyclic structures' when the agent state is serialized.

The runtime now preserves the original JSON Schema and converts through
ensureZodSchema only at the consumption boundary (getToolSet).

Tests: 16 new tests covering schema storage, serialization roundtrip,
multi-server scenarios, circular rejection defense, and full pipeline
validation.
@codebuff-team

Copy link
Copy Markdown
Contributor

The actual fix here is good: getMCPToolData in packages/agent-runtime/src/mcp.ts was eagerly calling convertJsonSchemaToZod at storage time, and Zod schema instances carry internal circular refs (_def, _cached, etc.) that blow up JSON.stringify when the agent state gets serialized. Storing the raw JSON Schema and deferring to ensureZodSchema at the consumption boundary (in getToolSet) is the right layer for this conversion, assuming that boundary already handles plain JSON Schema input — which the PR body claims but the diff doesn't show, since tools/prompts.ts isn't touched here. Worth double-checking there isn't some other consumer of inputSchema on MCP tool definitions that expects a Zod instance directly (e.g. calls .safeParse without going through ensureZodSchema) — if so this would just move the breakage rather than fix it.

The two new test files are enormous relative to the actual code change (555 lines of tests for a 2-line diff) and have a lot of redundant assertions (checking for _def/_cached/_type absence, multiple near-identical roundtrip checks). I'd trim these down to a handful of focused tests: one for the storage invariant (plain object, not Zod), one for the roundtrip through JSON.stringify, and one for ensureZodSchema correctly rehydrating a Zod schema for validation. As they stand they're not harmful, just more than a maintainer will want to carry forward verbatim.

Overall: correct root-cause identification, minimal core fix, in-scope package. Recommend porting the mcp.ts change with a trimmed-down test file.

@codebuff-team codebuff-team added bot:triaged Classified by the community triage bot pr:port-candidate Worth porting into the private source tree labels Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:triaged Classified by the community triage bot pr:port-candidate Worth porting into the private source tree

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants