Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions apps/mcp/src/tools/intent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,15 @@ function jsonSchemaPropertyToZod(prop: Record<string, unknown>): z.ZodTypeAny {
}
}

// Complex schemas (oneOf, anyOf, allOf) — pass through as opaque;
// DocumentApi validates the actual payload at dispatch time.
// Complex schemas (oneOf, anyOf, allOf) — pass through as a loose object.
// z.unknown() emits a JSON Schema with no `type` field, which some MCP
// clients (notably the Claude Code harness) treat as a string and fail
// to JSON-encode object payloads. z.looseObject({}) emits
// {type: "object", additionalProperties: true}, so the value reaches
// the server as an object. DocumentApi validates the actual payload
// at dispatch time.
if (prop.oneOf || prop.anyOf || prop.allOf) {
return desc ? z.unknown().describe(desc) : z.unknown();
return desc ? z.looseObject({}).describe(desc) : z.looseObject({});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve scalar oneOf schemas

When a catalog property uses oneOf for scalar variants, this branch now maps it to z.looseObject({}) and MCP validation rejects valid scalar arguments before DocumentApi dispatch. I checked apps/mcp/src/generated/catalog.ts: superdoc_comment.text and superdoc_create.text are string/string unions, superdoc_list.level is an integer union, and superdoc_table.color/cellSpacingPt allow string/number/null, so calls like superdoc_comment { action:"create", text:"...", target:{...} } will fail on text even though only object unions needed the object type hint. Please restrict the loose-object fallback to unions whose variants are objects, or preserve/recurse scalar union types.

Useful? React with 👍 / 👎.

}

switch (type) {
Expand All @@ -69,9 +74,12 @@ function jsonSchemaPropertyToZod(prop: Record<string, unknown>): z.ZodTypeAny {
// z4-mini toJSONSchema cannot convert z.record() from zod v4 classic.
return desc ? z.array(z.unknown()).describe(desc) : z.array(z.unknown());
case 'object':
// Use z.unknown() instead of z.record() to avoid MCP SDK Zod v4 classic/mini
// incompatibility. DocumentApi validates the actual shape at dispatch time.
return desc ? z.unknown().describe(desc) : z.unknown();
// Use z.looseObject({}) so the emitted JSON Schema carries
// `type: "object"`. z.unknown() drops the type (clients treat it
// as a string); z.record() can't be converted by the MCP SDK's
// z4-mini toJSONSchema. DocumentApi validates the actual shape
// at dispatch time.
return desc ? z.looseObject({}).describe(desc) : z.looseObject({});
default:
return desc ? z.unknown().describe(desc) : z.unknown();
}
Expand Down
Loading