Repository navigation
LOU-Z1, LOU-Z2: robust MCP schema conversion and result handling - #46
Merged
Merged
Conversation
LOU-Z1: jsonSchemaToZod now converts anyOf/oneOf (nullable pattern ->
.nullable()), allOf, local $ref into $defs/definitions (a recursive ref
falls back to z.any() for the inner occurrence), type arrays, mixed enums,
const, additionalProperties, default and the constraints zod can express
(an invalid regex pattern is skipped). Unknown or empty schemas become
z.any() and the converter never throws on schema content; objects keep
extra properties unless additionalProperties is false. loadMcpTools skips
a tool whose schema still fails, warns through an optional Logger and
reports it via an onSkip callback, so one bad tool no longer fails the
whole server. The old tests that asserted a throw for $ref, type 'null'
were changed to assert the new behaviour.
LOU-Z2: MCP results with isError throw McpToolError so the model sees
{ error, toolName, message } through the normal tool-error path. Text
parts are joined, structuredContent is preferred, and image/audio/
resource/resource_link parts are kept in a typed JSON-serializable form.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This was referenced Oct 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
jsonSchemaToZodhandlesanyOf/oneOf(nullable pattern ->.nullable()),allOf, local$refinto$defs/definitions(cycle-safe: inner recursive occurrence ->z.any()), type arrays, mixedenum,const,additionalProperties(bool/schema),default, nested arrays/objects and min/max/length/pattern constraints (invalid regex skipped). Unknown/empty schemas ->z.any(); it never throws on schema content.loadMcpTools(client, name, { logger?, onSkip? }): a tool whose schema still fails is skipped, warned through the SDKLogger(server, tool, reason) and reported viaonSkip({ name, reason }); the rest of the server loads. Return shape unchanged.isError: truethrowsMcpToolError, so the model gets{ error: 'McpToolError', toolName, message }with the server text. Text parts are joined,structuredContentis preferred, image/audio/resource/resource_link parts are preserved as typed JSON (McpContentPart).docs/api-overview.md.Why
One tool using
anyOf/$refmade the whole server's load fail, and since LOU-U4 args are validated with these schemas, strict conversion rejects valid calls.isErrorresults were returned as successes and non-text content was effectively invisible.How verified
npx tsc --noEmit: cleannpm run lint: 0 errors (no new warnings in touched files beyond pre-existinganys)npm run build+ create-loushy-agent build: successnpm run test:coverage: Test Files 95 passed (95), Tests 1177 passed | 3 skippednpm run fallow: exit 0 (0 above threshold)npm run docs:verify-snippets: all 30 snippet(s) type-check; 5 also run cleanlyorigin/main(13a6131) before final verification; already up to date.Notes for reviewer
{ text, content }(existing test still passes viatoMatchObject) or thestructuredContentobject, instead of the rawCallToolResult. Objects now pass unknown keys through (JSON Schema default) instead of zod's strip.$ref/type: 'null'encoded the bug and were rewritten.src/tools/mcp/result.ts,mcpResult.test.ts.🤖 Generated with Claude Code