[codex-apps] Filter optional file fields by tool schema (#31686)

## Summary

Codex Apps file parameters are exposed to the model as local paths,
uploaded at execution time, and rewritten into provided-file payloads
before the MCP tool call.

The rewrite currently includes the documented optional fields
`mime_type` and `file_name` for every file parameter. Apps with strict
schemas can reject those fields when they are not declared.

## Changes

- Derive the supported optional file fields from each
`openai/fileParams` parameter's raw input schema before replacing it
with the model-visible local-path schema.
- Always include `download_url` and `file_id`.
- Include `mime_type` and `file_name` only when that specific file
parameter's schema accepts them, including schemas that allow additional
properties.
- Handle scalar and array file parameters, including items-only arrays,
composed schemas, and local JSON Schema references.
- Preserve the existing restriction that only the host-owned Codex Apps
MCP server can use this upload path.

This supports tools with different file contracts in the same app: one
parameter can accept the optional fields while another remains strict.

## Validation

- `just test -p codex-mcp`
- `just test -p codex-core mcp_openai_file`
- `just test -p codex-core codex_apps_file_params_`
- `just fix -p codex-mcp`
- `just fix -p codex-core`
- `just fmt`
- `git diff --check`
- Manually verified in the Codex Electron app that:
  - a strict file schema receives only `download_url` and `file_id`
  - a rich file schema also receives `mime_type` and `file_name`

Related: #31330
This commit is contained in:
thomas authored and GitHub committed 2026-07-09 14:32:23 -07:00
1 parent 6d3cde7fcd
commit 8347b8de21
21 files changed
+613 -233

No files matched your search

+2 -2
View File
@@ -14,6 +14,7 @@ use std::time::Duration;
use std::time::Instant;
use crate::McpAuthStatusEntry;
use crate::codex_apps::prepare_openai_file_params_for_model;
use crate::codex_apps_cache::CodexAppsToolsCache;
use crate::codex_apps_cache::CodexAppsToolsCacheKey;
use crate::codex_apps_cache::CodexAppsToolsFetchSource;
@@ -36,7 +37,6 @@ use crate::server::McpServerMetadata;
use crate::tools::ToolInfo;
use crate::tools::filter_tools;
use crate::tools::normalize_tools_for_model_with_prefix;
use crate::tools::tool_with_model_visible_input_schema;
use anyhow::Context;
use anyhow::Result;
use anyhow::anyhow;
@@ -599,7 +599,7 @@ impl McpConnectionManager {
let tools = filter_tools(tools, &managed_client.tool_filter)
.into_iter()
.map(|mut tool| {
tool.tool = tool_with_model_visible_input_schema(&tool.tool);
prepare_openai_file_params_for_model(&mut tool);
self.with_server_metadata(tool)
});
let tools = normalize_tools_for_model_with_prefix(tools, self.prefix_mcp_tool_names);