Conversation
What changed - New file: docs/hosted-tools-mcp-builtin.md (single source of truth for hosted-tool dispatch via the MCP-builtin pattern). Why - The Responses API protocol surface now declares a wide set of hosted tools (image_generation, web_search_preview, web_search, code_interpreter, file_search, computer, computer_use_preview, custom, namespace, shell, local_shell, apply_patch, mcp). Several of them are dispatched via the MCP-builtin pattern: a server registered with builtin_type + builtin_tool_name has its tool result reshaped into the OpenAI-spec response item by the gateway. There has been no single contributor-facing reference describing which hosted tools support this pattern, what config a deployment needs, what the response item shape looks like, or what streaming events fire and in what order. - This doc consolidates that surface so contributors adding a new hosted tool, or operators wiring an MCP backend behind one, can find the authoritative answer in one place. How - Structured the doc as Overview, per-tool sections, cross-tool patterns, user-forwarding placeholder, and an "Adding a new hosted tool" checklist. - Per-tool sections cover image_generation, web_search_preview, web_search, code_interpreter, and file_search. Each includes status, server-config recipe (mirroring the canonical e2e_test/responses/conftest.py::_image_generation_mcp_config fixture), expected response-item shape pasted from real OpenAI captures (gpt-5-nano, Responses API), the verbatim streaming-event sequence, and tool-specific quirks. - Documented the "image_generation never emits .completed sub-event" finding from three independent capture variants — production OpenAI signals image_generation completion only via response.output_item.done, unlike web_search_* and code_interpreter which do emit a .completed sub-event. - Truncated all base64 result fields with leading-80-char + total-length annotations to keep the page readable; full payloads remain in the capture artefacts under /tmp/openai_ground_truth/results/. - Listed the non-MCP-builtin ResponseTool variants (function, mcp, custom, namespace, computer, computer_use_preview, shell, local_shell, apply_patch, tool_search) with brief reasons so contributors don't try to register MCP servers for them. - The "Adding a new hosted tool" checklist names every file a new hosted-tool variant has to touch: crates/protocols/src/responses.rs::ResponseTool, crates/mcp/src/core/config.rs::BuiltinToolType, crates/mcp/src/transform/transformer.rs, model_gateway/src/routers/common/mcp_utils.rs and the OpenAI passthrough loop in model_gateway/src/routers/openai/mcp/, plus the e2e fixture pattern under e2e_test/responses/. - Cross-references existing MCP docs (getting-started/mcp.md and concepts/extensibility/mcp.md) so the new page sits inside the existing MCP documentation graph instead of duplicating it. No source code is modified. No existing doc files are modified. Refs: hosted-tool dispatch tracking Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
📝 WalkthroughWalkthroughAdds a new documentation page defining SMG’s “MCP-builtin” hosted-tools dispatch contract: how Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~2 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive documentation page for the MCP-builtin pattern, detailing how OpenAI hosted tools are dispatched through MCP servers. It includes sections on request flow, tool-specific configurations, streaming event sequences, and a guide for adding new tools. Feedback indicates several inconsistencies between the documentation and the current implementation, specifically regarding the routing of web_search and file_search tools, as well as the emission of completion events for image_generation.
| | `web_search_preview` | `web_search_call` | `web_search_call` | Supported | | ||
| | `web_search` | `web_search_call` | `web_search_call` | Supported (alias of `web_search_preview` in dispatch; same response format) | | ||
| | `code_interpreter` | `code_interpreter_call` | `code_interpreter_call` | Supported | | ||
| | `file_search` | `file_search_call` | `file_search_call` | Partial (transformer present; vector-store integration is up to the MCP server backing it) | | ||
| | `image_generation` | `image_generation_call` | `image_generation_call` | Supported | |
There was a problem hiding this comment.
The status matrix indicates that web_search and file_search are supported or partially supported for MCP-builtin routing. However, the implementation in model_gateway/src/routers/common/mcp_utils.rs (specifically extract_builtin_types and collect_builtin_routing) does not currently handle these ResponseTool variants. Consequently, requests using these tool types will not be routed to MCP servers as described. Please update the documentation to reflect the current implementation or ensure the implementation is updated to match these claims.
References
- Use literal slugs for technical values in documentation to ensure accuracy and copy-paste friendliness.
- Focus on fixing inaccuracies during documentation audits and avoid adding documentation for undocumented features.
| - **No `.completed` sub-event.** Real OpenAI does **not** emit | ||
| `response.image_generation_call.completed`. Verified across three capture | ||
| variants (default, full-config, partial_images=0) — none of them contain | ||
| it. Completion is signaled solely by `response.output_item.done` for the | ||
| `image_generation_call` item. The constant | ||
| `ImageGenerationCallEvent::COMPLETED` exists in | ||
| `crates/protocols/src/event_types.rs` for forward-compat, but production | ||
| OpenAI does not currently emit it. MCP-builtin dispatch should match this | ||
| behavior. Other hosted tools (`web_search_preview`, `web_search`, | ||
| `code_interpreter`) **do** emit their respective `.completed` sub-event | ||
| before `output_item.done`. |
There was a problem hiding this comment.
This section states that image_generation does not emit a response.image_generation_call.completed sub-event and that MCP-builtin dispatch should match this behavior. However, the current implementation in model_gateway/src/routers/openai/mcp/tool_loop.rs (lines 541 and 554) explicitly emits this event. This discrepancy between the documentation's prescription and the actual gateway behavior should be addressed to ensure the documentation accurately describes the system's operation.
References
- Use literal slugs for technical values in documentation to ensure accuracy and copy-paste friendliness.
- Focus on fixing inaccuracies during documentation audits and avoid adding documentation for undocumented features.
| **Server config recipe**: identical to `web_search_preview` above; register | ||
| one MCP server with `builtin_type: web_search_preview` (the canonical key) | ||
| and both `{"type": "web_search_preview"}` and `{"type": "web_search"}` / | ||
| `{"type": "web_search_2025_08_26"}` request entries will be dispatched | ||
| through it. There is no separate `BuiltinToolType::WebSearch` — see | ||
| `crates/mcp/src/core/config.rs::BuiltinToolType`. |
There was a problem hiding this comment.
The claim that web_search and web_search_2025_08_26 request entries will be dispatched through the web_search_preview MCP server is currently incorrect. In model_gateway/src/routers/common/mcp_utils.rs, the routing logic only matches on ResponseTool::WebSearchPreview. Since web_search is a distinct variant in crates/protocols/src/responses.rs, it must be explicitly added to the match arms in mcp_utils.rs for this aliasing behavior to work.
References
- Use literal slugs for technical values in documentation to ensure accuracy and copy-paste friendliness.
- Focus on fixing inaccuracies during documentation audits and avoid adding documentation for undocumented features.
Removes a stray R6.5 reference in the 'Adding a new hosted tool' section. The doc is user-facing and shouldn't carry internal task labels. Citation now points at the test file path directly. Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/hosted-tools-mcp-builtin.md`:
- Around line 156-174: The fenced code blocks containing the event sequences
(e.g., the block showing "000 response.created ... 016 response.completed", the
block with "000 response.created ... 019 response.completed", and the block that
includes "004 response.output_item.added (item.type=code_interpreter_call, ...
016 response.output_item.done (item.type=code_interpreter_call,") should be
marked with a language identifier to satisfy markdownlint MD040; update each
triple-backtick fence to start with ```text (or another appropriate language) so
the blocks become ```text ... ``` to silence the lint warnings.
- Around line 28-30: Update the docs to include the separate builtin type for
web_search (add `web_search` to the list alongside `web_search_preview`,
`code_interpreter`, `file_search`, `image_generation`) and remove the incorrect
statement that `web_search_preview` covers both request types; explicitly
document that there is a distinct BuiltinToolType::WebSearch and that
ResponseTool::WebSearch maps to BuiltinToolType::WebSearch (referencing the
config symbol BuiltinToolType::WebSearch and the mapping in mcp_utils that maps
ResponseTool::WebSearch), so the text aligns with crates/mcp/src/core/config.rs
and model_gateway mapping.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: ca500c1d-806c-4c81-8108-cb65078355a4
📒 Files selected for processing (1)
docs/hosted-tools-mcp-builtin.md
| `mcp.yaml` that binds a `BuiltinToolType` (`web_search_preview`, | ||
| `code_interpreter`, `file_search`, `image_generation`) to a specific tool on | ||
| that MCP server. Once a server is registered with `builtin_type` + |
There was a problem hiding this comment.
Correct web_search builtin-type docs; current text contradicts code and can mislead config.
Line 28-30 omits web_search, and Lines 76-82 + 307-312 claim there is no separate BuiltinToolType::WebSearch / that web_search_preview registration covers both request types. That conflicts with crates/mcp/src/core/config.rs:298-320 (has BuiltinToolType::WebSearch) and model_gateway/src/routers/common/mcp_utils.rs:224-250 (maps ResponseTool::WebSearch to BuiltinToolType::WebSearch).
📌 Suggested doc corrections
-The MCP-builtin pattern is a registration knob on an MCP server entry in
-`mcp.yaml` that binds a `BuiltinToolType` (`web_search_preview`,
-`code_interpreter`, `file_search`, `image_generation`) to a specific tool on
+The MCP-builtin pattern is a registration knob on an MCP server entry in
+`mcp.yaml` that binds a `BuiltinToolType` (`web_search_preview`, `web_search`,
+`code_interpreter`, `file_search`, `image_generation`) to a specific tool on
that MCP server.-`web_search` and `web_search_preview` share dispatch routing today. Both map
-to the `web_search_call` output item.
+`web_search` and `web_search_preview` both map to the same response shape
+(`web_search_call`) but are distinct request-side builtin types in routing.
@@
-both — register one MCP server with `builtin_type: web_search_preview` and it
-will pick up both request shapes.
+both. Configure the matching `builtin_type` for the request type(s) you want
+to route.-and both `{"type": "web_search_preview"}` and `{"type": "web_search"}` /
-`{"type": "web_search_2025_08_26"}` request entries will be dispatched
-through it. There is no separate `BuiltinToolType::WebSearch` — see
-`crates/mcp/src/core/config.rs::BuiltinToolType`.
+and route the corresponding request type. `BuiltinToolType::WebSearch` is a
+separate variant in `crates/mcp/src/core/config.rs::BuiltinToolType`.Also applies to: 76-82, 307-312
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/hosted-tools-mcp-builtin.md` around lines 28 - 30, Update the docs to
include the separate builtin type for web_search (add `web_search` to the list
alongside `web_search_preview`, `code_interpreter`, `file_search`,
`image_generation`) and remove the incorrect statement that `web_search_preview`
covers both request types; explicitly document that there is a distinct
BuiltinToolType::WebSearch and that ResponseTool::WebSearch maps to
BuiltinToolType::WebSearch (referencing the config symbol
BuiltinToolType::WebSearch and the mapping in mcp_utils that maps
ResponseTool::WebSearch), so the text aligns with crates/mcp/src/core/config.rs
and model_gateway mapping.
| ``` | ||
| 000 response.created | ||
| 001 response.in_progress | ||
| 002 response.output_item.added (item.type=reasoning) | ||
| 003 response.output_item.done (item.type=reasoning) | ||
| 004 response.output_item.added (item.type=image_generation_call) | ||
| 005 response.image_generation_call.in_progress (output_index=1) | ||
| 006 response.image_generation_call.generating (output_index=1) | ||
| 007 response.image_generation_call.partial_image (output_index=1) | ||
| 008 response.output_item.done (item.type=image_generation_call) | ||
| 009 response.output_item.added (item.type=reasoning) | ||
| 010 response.output_item.done (item.type=reasoning) | ||
| 011 response.output_item.added (item.type=message) | ||
| 012 response.content_part.added | ||
| 013 response.output_text.done | ||
| 014 response.content_part.done | ||
| 015 response.output_item.done (item.type=message) | ||
| 016 response.completed | ||
| ``` |
There was a problem hiding this comment.
Add language identifiers to fenced event-sequence blocks (markdownlint MD040).
Lines 156, 271, and 396 use fenced code blocks without a language tag; lint will continue to warn.
🧹 Minimal lint fix
-```
+```text
000 response.created
...
016 response.completed- +text
000 response.created
...
019 response.completed
-```
+```text
004 response.output_item.added (item.type=code_interpreter_call,
...
016 response.output_item.done (item.type=code_interpreter_call,
Also applies to: 271-290, 396-407
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 156-156: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/hosted-tools-mcp-builtin.md` around lines 156 - 174, The fenced code
blocks containing the event sequences (e.g., the block showing "000
response.created ... 016 response.completed", the block with "000
response.created ... 019 response.completed", and the block that includes "004
response.output_item.added (item.type=code_interpreter_call, ... 016
response.output_item.done (item.type=code_interpreter_call,") should be marked
with a language identifier to satisfy markdownlint MD040; update each
triple-backtick fence to start with ```text (or another appropriate language) so
the blocks become ```text ... ``` to silence the lint warnings.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bb067becc9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| and both `{"type": "web_search_preview"}` and `{"type": "web_search"}` / | ||
| `{"type": "web_search_2025_08_26"}` request entries will be dispatched | ||
| through it. There is no separate `BuiltinToolType::WebSearch` — see |
There was a problem hiding this comment.
Correct web_search MCP-builtin routing claim
This states that {"type": "web_search"} requests are dispatched through the web_search_preview built-in server, but current routing does not do that: collect_builtin_routing and extract_builtin_types only match ResponseTool::WebSearchPreview, CodeInterpreter, and ImageGeneration (see model_gateway/src/routers/common/mcp_utils.rs around lines 186-190 and 228-231). As written, operators following this doc will configure MCP expecting web_search to route locally, but those calls will bypass built-in MCP routing.
Useful? React with 👍 / 👎.
| **Status**: Partial. The transformer is implemented | ||
| (`crates/mcp/src/transform/transformer.rs::ResponseTransformer::to_file_search_call`) | ||
| and the `BuiltinToolType::FileSearch` variant is wired through orchestration, |
There was a problem hiding this comment.
Remove file_search support statement from MCP-builtin docs
This section says file_search is wired through orchestration, but the OpenAI Responses built-in routing path currently never selects it: model_gateway/src/routers/common/mcp_utils.rs does not include ResponseTool::FileSearch in either collect_builtin_routing or extract_builtin_types. Documenting it as supported/partial will send contributors to debug non-working configs that cannot activate the built-in dispatch path today.
Useful? React with 👍 / 👎.
| - **No `.completed` sub-event.** Real OpenAI does **not** emit | ||
| `response.image_generation_call.completed`. Verified across three capture | ||
| variants (default, full-config, partial_images=0) — none of them contain | ||
| it. Completion is signaled solely by `response.output_item.done` for the |
There was a problem hiding this comment.
Align image_generation completion-event guidance with runtime
The doc says response.image_generation_call.completed is not emitted and that MCP-builtin should omit it, but the gateway currently emits that event for image_generation_call in send_tool_call_completion_events (model_gateway/src/routers/openai/mcp/tool_loop.rs, item-type match at lines 537-542) and has a lock test asserting this behavior (image_generation_completion_events_fire_before_output_item_done, lines 1615+). This mismatch will cause downstream tests/consumers built from this “single source of truth” to diverge from actual SMG behavior.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
docs/hosted-tools-mcp-builtin.md (1)
156-174:⚠️ Potential issue | 🟡 MinorAdd language identifiers to fenced event-sequence blocks.
The fenced code blocks showing streaming event sequences are missing language identifiers, causing markdownlint MD040 warnings.
🧹 Suggested fix
-``` +```text 000 response.created 001 response.in_progress ...Apply the same fix to the blocks at lines 271-290 and 396-407.
Also applies to: 271-290, 396-407
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/hosted-tools-mcp-builtin.md` around lines 156 - 174, The fenced code blocks that show streaming event sequences (the blocks that start with lines like "000 response.created" and contain numbered response.* events) are missing a language identifier and should be changed to fenced blocks with the "text" language (e.g., replace ``` with ```text) to silence markdownlint MD040; apply this change to the three event-sequence blocks (the one beginning with "000 response.created" and the other two similar blocks referenced in the comment).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@docs/hosted-tools-mcp-builtin.md`:
- Around line 156-174: The fenced code blocks that show streaming event
sequences (the blocks that start with lines like "000 response.created" and
contain numbered response.* events) are missing a language identifier and should
be changed to fenced blocks with the "text" language (e.g., replace ``` with
```text) to silence markdownlint MD040; apply this change to the three
event-sequence blocks (the one beginning with "000 response.created" and the
other two similar blocks referenced in the comment).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b856ed22-976a-4516-97e9-96d676336004
📒 Files selected for processing (1)
docs/hosted-tools-mcp-builtin.md
Summary
Adds
docs/hosted-tools-mcp-builtin.md, a single source of truth for how SMG dispatches OpenAI Responses API hosted-tool calls (image_generation,web_search_preview,web_search,code_interpreter,file_search) through MCP servers, and what the resulting response items / streaming events look like on the wire.Why
The Responses API protocol surface (
crates/protocols/src/responses.rs::ResponseTool) declares a wide set of hosted tools, several of which are dispatched via the MCP-builtin pattern: an MCP server is registered withbuiltin_type+builtin_tool_name, and the gateway routes the model's hosted-tool call through that server while shaping the result into the OpenAI-spec response item. Until now there was no single contributor-facing reference describing:This doc consolidates that surface so contributors adding a new hosted tool (or operators wiring an MCP backend behind one) can find authoritative answers in one place.
What changed
docs/hosted-tools-mcp-builtin.md(~650 lines).Sections
crates/mcp/src/core/config.rs::BuiltinToolType.image_generation— captured (with the no-.completedfinding documented).web_search_preview— captured.web_search— captured (alias ofweb_search_previewon the dispatch path).code_interpreter— captured (37-event sequence, code-delta / code-done / interpreting / completed sub-events).file_search— partial; schema-only because no ground-truth capture is available.function,mcp,custom,namespace,computer,computer_use_preview,shell,local_shell,apply_patch, andtool_search(planned, PR feat(protocols): implement T10 tool_search hosted/client-executed tool #1383 in flight) so contributors don't try to register MCP servers for them.output_item.added/.done, hosted-tool sub-events sit between the bracket, terminal-signal semantics, and theoutput_item.donesnapshot caveat.userforwarding placeholder — describes the intended forwarding behavior with a<TBD>PR-number placeholder for the in-flight fix.Ground-truth captures
Per-tool sections embed real captured data from
gpt-5-nanoagainsthttps://api.openai.com/v1/responses(OpenAI Python SDK 2.8.1):image_generation.completedsub-eventweb_search_previewweb_searchcode_interpreterfile_searchAll base64 image bytes truncated to leading 80 chars + total-length annotation (full payloads remain in capture artefacts on disk; not committed).
Canonical example
e2e_test/responses/test_image_generation.py(R6.5) is cited as the canonical worked example — it covers the OpenAI cloud router, the gRPC-harmony router, and the gRPC-regular router for the same MCP-builtin dispatch via the in-processMockMcpServer. The doc's server-config recipes mirrore2e_test/responses/conftest.py::_image_generation_mcp_config.Test plan
scripts/).crates/protocols/src/responses.rs::ResponseToolcrates/protocols/src/event_types.rs::{WebSearchCallEvent, CodeInterpreterCallEvent, FileSearchCallEvent, ImageGenerationCallEvent}crates/mcp/src/core/config.rs::BuiltinToolTypecrates/mcp/src/core/orchestrator.rs::find_builtin_servercrates/mcp/src/transform/transformer.rs::ResponseTransformermodel_gateway/src/routers/common/mcp_utils.rs::{extract_builtin_types, collect_builtin_routing, ensure_request_mcp_client, ensure_mcp_servers}model_gateway/src/routers/openai/mcp/{tool_handler.rs, tool_loop.rs}e2e_test/responses/conftest.py::_image_generation_mcp_confige2e_test/responses/test_image_generation.pye2e_test/infra/mock_mcp_server.pydocs/getting-started/mcp.md,docs/concepts/extensibility/mcp.md).Checklist
Refs: hosted-tool dispatch tracking
Summary by CodeRabbit