fix(agentic): do not advertise an output schema devframe cannot derive - #400
erkamyaman wants to merge 2 commits into
Conversation
An RPC function whose `returns` validator has no Standard JSON Schema
converter degraded to a permissive `{ type: 'object' }` schema. That is
fine as documentation, but it is advertised as the MCP `outputSchema`,
which obliges the tool to return a matching object on every call.
Any such function returning an array or a primitive therefore failed
`tools/call` with -32602, the SDK rejecting the server's own response:
Invalid tools/call result: expected record, received array
Return no output schema instead when the converter is absent, so the
result travels as text content only. Validators with a native converter
(zod 4) are unaffected.
◈ PR Lens
Architecture 2 components touched across 3 lanes. Play the interactive walkthrough Data flow
Follow each request, response and payload View
Tip Run 🪧 More tips
Thanks for using PR Lens! It's built by Coldtea, free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Output conversion failures can still advertise an incorrect structured output schema.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
What changed in this PR
This PR prevents unsupported RPC return validators from being advertised as MCP output schemas.
Changes:
- Omits unsupported output schemas.
- Updates schema conversion tests.
- Adds an MCP regression test for array results.
- Critical issue remains: converter failures may still produce incorrect fallback schemas.
| File | Reviewed changes |
|---|---|
packages/devframe/src/agent/to-json-schema.ts |
Adjusts return-schema generation. |
packages/devframe/src/agent/__tests__/to-json-schema.test.ts |
Updates schema conversion expectations. |
packages/agentic/src/mcp/__tests__/mcp-server.test.ts |
Adds MCP regression coverage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Checking only for a converter's presence left the throwing path on the fallback: `input`/`output` may throw when conversion is unsupported, and that was caught into the permissive object schema, reproducing the same MCP rejection. Convert via the converter's `output` too, since a transforming validator returns its output type, and the return value is what `outputSchema` describes.

An RPC function whose
returnsvalidator has no Standard JSON Schema converter degrades to the permissive{ type: 'object', additionalProperties: true }schema. That is fine as documentation, but it is also advertised as the MCPoutputSchema, which obliges the tool to return a matching object on every call.So any such function returning an array or a primitive fails
tools/call, with the SDK rejecting the server's own response:Found via a valibot-based devframe tool where four of five RPC tools returned
v.array(...)and everytools/callfailed. Object-returning ones worked, which is what made it look selective.returnToJsonSchemanow yields no schema when the validator has no native converter, so the result travels as text content only. GuardingstructuredContentat call time instead does not work: the client then rejects the response for advertising an output schema without returning structured content.Validators with a native converter (zod 4) are unaffected. Args keep their permissive fallback, since that schema is a container devframe does construct rather than one inferred from the validator.
Updated the
to-json-schemaunit test that asserted the old fallback, and added an MCP-level test that fails onmainwith the error above.