Code-mode MCP schema compaction erases nested operation unions into Array<unknown | …>
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of Codex CLI is running?
codex-cli 0.153.4. This report is scoped to that installed version; no claim of reproduction on a newer release.
What subscription do you have?
Not collected.
Which model were you using?
GPT-6 family, code-mode tool declarations (ALL_TOOLS / functions.exec).
What platform is your computer?
macOS, Apple Silicon.
Terminal / Codex doctor report
Not collected. No local configuration, credentials or private session logs are included.
What issue are you seeing?
A connected MCP tool has a fully typed input schema, but the model-visible TypeScript declaration erases every nested operation variant:
apply_image_operations(args: {
expectedRevision: number;
idempotencyKey: string;
jobId: string;
operations: Array<unknown | unknown | unknown | unknown | unknown | unknown | unknown | unknown | unknown | unknown | unknown | unknown | unknown | unknown>;
}): Promise<CallToolResult>;
The released schema contains 14 inline object variants under properties.operations.items.oneOf, each with its own type discriminator and typed fields. This is not an unresolved $ref or sibling-properties-at-root case.
Observed with @formseed2d/mcp@1.1.2. After restarting/resuming the same CLI conversation, /mcp and the actual model-visible catalog both expose all 12 server tool names. Live health reports the expected package version, process identity, aggregate input hash and per-tool hashes. Thus this report concerns lost input structure, not missing tool names or a failed server connection. The server's hash report is supporting evidence, not independent executable attestation.
What steps can reproduce the bug?
Use an MCP input schema with this shape and enough typed fields to exceed the host's normalized schema budget. This standalone Python generator provides a synthetic fixture with no application data:
import json
variants = []
for i in range(14):
props = {"type": {"type": "string", "const": f"operation_{i}"}}
props.update({f"field_{j}": {"type": "integer", "minimum": 0,
"maximum": 1023} for j in range(12)})
variants.append({"type": "object", "properties": props,
"required": list(props), "additionalProperties": False})
schema = {
"type": "object",
"properties": {
"expectedRevision": {"type": "integer", "minimum": 0},
"idempotencyKey": {"type": "string"},
"jobId": {"type": "string"},
"operations": {"type": "array", "minItems": 1, "maxItems": 20,
"items": {"oneOf": variants}},
},
"required": ["expectedRevision", "idempotencyKey", "jobId", "operations"],
}
print(json.dumps(schema))
Register this as a disposable MCP tool's inputSchema and inspect its actual code-mode declaration. No mutation handler is needed to inspect declarations. Also test the host pipeline directly: MCP schema parsing/compaction → TypeScript rendering.
Evidence scope: the real FormSeed tool declaration above was observed live. Separately, applying the source depth-collapse pass to the exact released FormSeed schema reproduces 14 empty objects at the operation-variant positions. The standalone synthetic generator above is supplied as a proposed regression fixture; it has not been run through a complete fresh CLI session.
What is the expected behavior?
Preserve useful typed operation discriminants and fields in the model-visible declaration, or provide a supported way to retrieve the full input schema when compaction is necessary. A silent union of 14 unknown alternatives prevents callers from discovering valid operations and arguments through the tool declaration.
Additional information / source investigation
In the inspected rust-v0.153.4 source:
codex-rs/tools/src/mcp_tool.rsroutes inputs throughparse_tool_input_schema.codex-rs/tools/src/json_schema/compaction.rsuses a 5,000-byte compact-normalized schema budget and a depth-3 collapse pass.- The pass replaces complex schemas at that depth with
{}. The FormSeed schema is 8,145 bytes as raw compact JSON (distinct from the policy's normalized-byte measurement), and its inline operation objects sit at depth 3. codex-rs/code-mode-protocol/src/json_schema_types.rsrenders empty schemas asunknown.
This source-level mechanism reproduces the observed shape, but a complete pipeline regression test is still needed to establish the exact triggering passes and normalized size. Please retain resource/recursion limits when addressing this; the request is not to remove all schema budgets.
Related: #42283 also concerns code-mode schema information loss, but describes sibling properties beside root-level oneOf; this report concerns large nested discriminated operation unions erased by compaction.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in codex-rs/tools/src/mcp_tool.rs and follow parse_tool_input_schema into codex-rs/tools/src/json_schema/compaction.rs; then inspect rendering in codex-rs/code-mode-protocol/src/json_schema_types.rs. Run the supplied synthetic schema through the MCP schema-compaction and TypeScript-rendering pipeline, and establish a regression test showing nested operation discriminants and fields remain discoverable within resource limits.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- devtools, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100