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.
Summary
In v2.5.0-beta.1 and later (current
latest: v2.5.2), the registration wrapper schema produced bygetMcpOutputSchemaForRegistrationJsoninsrc/core/structured-output-schema.tsdeclares its own$id(…/N.registration.schema.json) but contains no$defs. The two inner schemas it wraps inoneOfhave already been bundled with#/$defs/<name>refs that were relative to their own$id. JSON Schema 2020-12 says embedded$idshould re-base those refs, but many spec-conformant validators do not currently chase the embedded resource boundary across aoneOfsubschema. The result is that the refs resolve against the registration document root, where no$defsexists, and fail.The clearest symptom on the consumer side is Python's
jsonschema/referencinglibrary raising:(Captured from a real session —
session_show_defaultswas 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_profilebuild_sim,build_run_sim,test_sim,build_device, …list_sims,list_devices,show_build_settingsget_app_bundle_id,get_sim_app_path, …are unusable through any MCP client that validates output schemas with a JSON-Schema 2020-12 library that doesn't re-base
\$refacross 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
Thanks for the project — happy to test a fix against the same session if useful.