Skip to content

[cc] switch JSON Schema generator from anyOf to oneOf for the discriminated union #82

@anipotts

Description

@anipotts

Source: Apr 2026 conventions audit

Problem

`lib/action.ts` uses `zod-to-json-schema` with default options, which produces `anyOf` for discriminated unions. `anyOf` matches "at least one branch"; `oneOf` matches "exactly one branch". With const discriminators they're behaviorally equivalent, but `oneOf` is the more accurate signal:

  1. JSON Schema 2020-12 spec says discriminated unions SHOULD use `oneOf`
  2. OpenAPI tooling (which the model's tool-selection layer may resemble) uses `oneOf`+`discriminator` keyword
  3. Some MCP clients may treat `anyOf` permissively (multi-branch match) whereas `oneOf` is exclusive

Fix

```ts
// lib/action.ts
const _raw = zodToJsonSchema(ActionSchema, {
$refStrategy: "none",
target: "openApi3", // emits oneOf with discriminator
});
```

Or post-process the output to rename `anyOf` → `oneOf`.

Acceptance criteria

  • tools/list inputSchema uses oneOf (not anyOf)
  • Existing tests still pass (action shape unchanged)
  • Snapshot test for byte-stable schema (see issue for snapshot test)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions