Skip to content

fix(agentic): do not advertise an output schema devframe cannot derive - #400

Open
erkamyaman wants to merge 2 commits into
devframes:mainfrom
erkamyaman:fix/structured-content-non-object
Open

erkamyaman wants to merge 2 commits into
devframes:mainfrom
erkamyaman:fix/structured-content-non-object

Conversation

@erkamyaman

Copy link
Copy Markdown

An RPC function whose returns validator 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 MCP outputSchema, 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:

-32602 Invalid tools/call result: [{ "expected": "record", "code": "invalid_type",
  "path": ["structuredContent"], "message": "Invalid input: expected record, received array" }]

Found via a valibot-based devframe tool where four of five RPC tools returned v.array(...) and every tools/call failed. Object-returning ones worked, which is what made it look selective.

returnToJsonSchema now yields no schema when the validator has no native converter, so the result travels as text content only. Guarding structuredContent at 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-schema unit test that asserted the old fallback, and added an MCP-level test that fails on main with the error above.

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.
Copilot AI lite review requested due to automatic review settings September 20, 2026 16:13
@coldtea-pr-lens

coldtea-pr-lens Bot commented Sep 20, 2026

Copy link
Copy Markdown

◈ PR Lens

🟢 +0 new · 🟠 ~2 changed · 🔴 -0 removed · 1 flow · 4 files · commit 7ef52dc


Architecture

Architecture diagram for devframes/devframe at 7ef52dc

2 components touched across 3 lanes.

Play the interactive walkthrough


Data flow

Data flow diagram for devframes/devframe at 7ef52dc

Calling an RPC tool with unconvertible return schema

Follow each request, response and payload


View

  • Architecture lens
  • Data flow lens
  • Expand every detail

Tip

Run npx skills add coldteadotai/pr-lens, then tell your coding agent: "Diagram the change you just made with PR Lens and attach it to the pull request."

🪧 More tips
  • Run npx @coldtea/pr-lens-cli analyze --base origin/main on a branch, then npx @coldtea/pr-lens-cli render .pr-lens/graph.json. Same lenses, your own model key, before the pull request exists
  • Untick Architecture lens or Data flow lens under View to hide a diagram, or tick Expand every detail to open every section. The comment redraws in a few seconds
  • Click the link under each diagram to open it on a canvas you can zoom, pan and step through
  • The diagrams are links. Click one to open it on the canvas, then press W or click play to walk through the change
  • Open a diagram on the canvas, then press W or click play to walk through the change one step at a time
  • The CLI's render reads .github/pr-lens.yml and applies your renames, exclusions and lane pins at draw time
  • Set github.comment.collapsed: true in .github/pr-lens.yml to fold the comment behind one View architecture and data flow row. Drawing still runs on every push
  • Set github.draw: on-demand in .github/pr-lens.yml and PR Lens stops drawing every push. Comment @pr-lens draw on a pull request when you want that one drawn
  • Add .github/workflows/pr-lens.yml with coldteadotai/pr-lens/packages/action@v0 and your model provider's key as its api-key to run PR Lens from your own CI. Any /chat/completions endpoint works
  • Push a commit and the comment redraws for the new head. A slow older run never overwrites a newer one
  • Switch GitHub to dark mode and the diagrams follow. The moving dots are this pull request's data in motion

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.

❤️ Share

@vercel

vercel Bot commented Sep 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
devframe Skipped Skipped Sep 20, 2026 4:18pm UTC

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 High severity

Open (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.

Comment thread packages/devframe/src/agent/to-json-schema.ts Outdated
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.
Copilot AI review requested due to automatic review settings September 20, 2026 16:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

No unresolved blocking issues were identified.

Review effort: Lite
Findings: None

Resolved since last review (1)

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.

2 participants