Skip to content

[Bug]: registration.schema.json missing $defs causes PointerToNowhere for all structured-output tools #419

@KShad10

Description

@KShad10

Summary

In v2.5.0-beta.1 and later (current latest: v2.5.2), the registration wrapper schema produced by getMcpOutputSchemaForRegistrationJson in src/core/structured-output-schema.ts declares its own $id (…/N.registration.schema.json) but contains no $defs. The two inner schemas it wraps in oneOf have already been bundled with #/$defs/<name> refs that were relative to their own $id. JSON Schema 2020-12 says embedded $id should re-base those refs, but many spec-conformant validators do not currently chase the embedded resource boundary across a oneOf subschema. The result is that the refs resolve against the registration document root, where no $defs exists, and fail.

The clearest symptom on the consumer side is Python's jsonschema/referencing library raising:

_WrappedReferencingError: PointerToNowhere: '/$defs/errorConsistency' does not exist within
  {'\$schema': 'https://json-schema.org/draft/2020-12/schema',
   '\$id':     'https://xcodebuildmcp.com/schemas/structured-output/xcodebuildmcp.output.session-defaults/1.registration.schema.json',
   'type': 'object',
   'allOf': [{'\$ref': '#/\$defs/errorConsistency'}],
   ... }

(Captured from a real session — session_show_defaults was the first tool call, hit this immediately, and every subsequent structured-output tool call would hit the same wall.)

Impact

This affects every tool with a structured output schema, not just session_show_defaults. The underlying tool operation succeeds, but the MCP client cannot validate the returned payload against the registered output schema, so the client surfaces a failure. From the agent's perspective, all of:

  • session_show_defaults / session_set_defaults / session_use_defaults_profile
  • build_sim, build_run_sim, test_sim, build_device, …
  • list_sims, list_devices, show_build_settings
  • get_app_bundle_id, get_sim_app_path, …
  • and the rest of the output.* schemas

are unusable through any MCP client that validates output schemas with a JSON-Schema 2020-12 library that doesn't re-base \$ref across embedded \$id (which includes the common Python implementations).

Root cause

src/core/structured-output-schema.ts:

```ts
function getMcpOutputSchemaForRegistrationJson(ref: StructuredOutputSchemaRef): JsonObject {
const toolSchema = getMcpOutputSchema(ref);
if (ref.schema === STRUCTURED_ERROR_SCHEMA_REF.schema) {
return toolSchema;
}

return {
$schema: 'https://json-schema.org/draft/2020-12/schema',
$id: `https://xcodebuildmcp.com/schemas/structured-output/\${ref.schema}/\${ref.version}.registration.schema.json\`,
type: 'object',
oneOf: [toolSchema, getMcpOutputSchema(STRUCTURED_ERROR_SCHEMA_REF)],
};
}
```

Both `toolSchema` and the error schema contain refs like `#/$defs/errorConsistency` that were inlined into their own `$defs` by `bundleSchema()`. Wrapping them in a new document with a new `$id` and no top-level `$defs` invalidates those refs for many validator implementations.

Suggested fix

After building the `oneOf` registration wrapper, also merge the union of inner schemas' `$defs` into the wrapper's top-level `$defs`, and rewrite the inner `$id`s / refs accordingly. Conceptually:

```ts
const mergedDefs: JsonObject = {
...((toolSchema.$defs as JsonObject) ?? {}),
...((errorSchema.$defs as JsonObject) ?? {}),
};
// then drop $id from the inner schemas and clear their $defs so the wrapper
// is the single self-contained resource.
return {
$schema: 'https://json-schema.org/draft/2020-12/schema',
$id: '…/registration.schema.json',
type: 'object',
oneOf: [strippedToolSchema, strippedErrorSchema],
$defs: mergedDefs,
};
```

Alternative: keep the inner `$id`s intact (treat each as an embedded resource) and document that consumers must use a validator that resolves embedded resources across subschemas — but in practice the first form is more interoperable.

Reproduction

```bash

any MCP client that validates output schemas with Python jsonschema/referencing

npx -y xcodebuildmcp@2.5.2 mcp

Call session_show_defaults

```

Workaround for users hitting this today

Pin to v2.3.2 (last release before the structured-output system was introduced):

```yaml

e.g. for a Hermes-style MCP config

xcodebuildmcp:
command: npx
args: [-y, xcodebuildmcp@2.3.2, mcp]
```

Versions in scope: introduced in v2.5.0-beta.1 (2026-04-30); reproduced on v2.5.2 (2026-05-12, current `latest`).

Environment

  • xcodebuildmcp v2.5.2 via `npx -y xcodebuildmcp@latest mcp`
  • MCP client: Hermes Agent (Python), output schemas validated with `jsonschema` / `referencing`
  • Host: macOS 25.3.0 (Darwin)
  • Node: v$(ssh OrionHermes@100.127.12.36 'node -v' 2>/dev/null || echo 'unknown')

Thanks for the project — happy to test a fix against the same session if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions