MCP schema conversion collapses array items.oneOf(object) to string[]

Open 💬 2 comments Opened May 1, 2026 by attila-kun
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

Codex appears to lose MCP tool input schema fidelity when an array's items schema is expressed via oneOf.

In practice, this causes object-array parameters from MCP tools to be exposed to the model as string[] instead of an array of structured objects.

Expected behavior

Given a schema like:

{
  "type": "array",
  "items": {
    "oneOf": [
      {
        "type": "object",
        "properties": {
          "id": { "type": "string" }
        },
        "required": ["id"]
      }
    ]
  }
}

Codex should preserve the nested union/object shape, or at least normalize it to an equivalent supported union form.

Actual behavior

Codex parses the items schema as string, which effectively turns the overall parameter type into string[].

Minimal repro

I added a failing regression test on my fork here:

https://github.com/attila-kun/codex/commit/86258a13e12873823d072d977d1aabdcc73eb328

The test is:

  • json_schema::tests::parse_tool_input_schema_preserves_array_item_one_of_object_shape

Run:

cd codex-rs
cargo test -p codex-tools parse_tool_input_schema_preserves_array_item_one_of_object_shape

Failing output

running 1 test
test json_schema::tests::parse_tool_input_schema_preserves_array_item_one_of_object_shape ... FAILED

Diff < left / right > :
 JsonSchema {
     schema_type: Some(
         Single(
             Array,
         ),
     ),
     ...
     items: Some(
         JsonSchema {
<            schema_type: Some(
<                Single(
<                    String,
<                ),
<            ),
>            schema_type: None,
             ...
<            any_of: None,
>            any_of: Some(
>                [
>                    JsonSchema {
>                        schema_type: Some(
>                            Single(
>                                Object,
>                            ),
>                        ),
>                        ...
>                    },
>                ],
>            ),
         },
     ),
     ...
 }

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 3 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #17964

Powered by Codex Action

KurodaKayn · 3 months ago

I took a look at this and have a small fix working locally.

The root cause appears to be that parse_tool_input_schema only preserves anyOf, while MCP schemas can emit equivalent union
shapes using oneOf. When oneOf appears under array.items, the sanitizer currently ignores it, so the schema later falls back
to the permissive/default item schema, which is why the model sees this as string[].

My fix is to normalize oneOf into the existing anyOf representation during JSON schema sanitization:

  • if a schema object contains oneOf
  • and it does not already contain anyOf
  • move oneOf to anyOf
  • then continue sanitizing recursively as before

This keeps the existing internal schema model unchanged and preserves the nested object shape for array items.

I also added a regression test:

```bash
cd codex-rs
cargo test -p codex-tools parse_tool_input_schema_preserves_array_item_one_of_object_shape


  The test passes locally.

  The local patch touches:

  - codex-rs/tools/src/json_schema.rs
  - codex-rs/tools/src/json_schema_tests.rs

  The implementation is basically:
```rust
  if let Some(value) = map.remove("oneOf")
      && !map.contains_key("anyOf")
  {
      map.insert("anyOf".to_string(), value);
  }

This resolves the repro from the issue by preserving:

  {
    "type": "array",
    "items": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "id": { "type": "string" }
          },
          "required": ["id"]
        }
      ]
    }
  }

as an array whose item schema is an anyOf containing the object schema, instead of collapsing to string[].

I cannot open a PR directly because Codex PRs appear to be invite/restricted, but I’m happy to share the branch/patch https://github.com/KurodaKayn/codex/tree/fix-mcp-schema-oneof-array-items if a maintainer wants to apply it.