Skip to content

fix(responses): keep namespace tools intact when a guardrail returns them unchanged - #39366

Merged
mateo-berri merged 7 commits into
litellm_internal_stagingfrom
litellm_responses_guardrail_namespace_tools
Sep 3, 2026
Merged

mateo-berri merged 7 commits into
litellm_internal_stagingfrom
litellm_responses_guardrail_namespace_tools

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Any guardrail on /v1/responses flattens Codex namespace (MCP) tools into ns__member functions
  • The model then calls mcp__server__tool with no namespace, which Codex rejects as unsupported
  • It happens even when the guardrail returns the tools untouched or is bypassed
  • custom tools got rewritten and computer_use/image_generation/shell tools got dropped the same way

How it solves it:

  • Keep the client's original tools and rebuild only what the guardrail actually changed
  • Match the guardrail's output to the originals by type and name (ordinal for duplicate names)
  • Unchanged tools go back as the original objects, so namespaces stay namespaces
  • A dropped member prunes just that member; an edited member lands on that member
  • Tools the guardrail injects (Headroom's retrieve tool) are still appended
  • The guardrail gets a deep copy, so in-place edits are seen as changes
  • Guardrail output is accepted as dicts or pydantic models, and a namespace whose function members are all dropped keeps its other members

User Flow

Before: a developer running the Codex CLI through the gateway with a guardrail on gets every MCP tool call refused as unsupported

  1. The proxy admin adds a guardrail (Headroom, mode: pre_call, default_on: true) to the proxy config and registers an MCP server (deepwiki) on the proxy
  2. The developer points Codex CLI at the gateway (base_url = "http://litellm-domain/v1", wire_api = "responses") with [mcp_servers.deepwiki] at http://litellm-domain/mcp/deepwiki
  3. They type "Use the deepwiki MCP tool to read the wiki structure of BerriAI/litellm and reply with the first 3 section titles only."
  4. Codex sends POST http://litellm-domain/v1/responses with a namespace tool named mcp__deepwiki whose members are deepwiki_read_wiki_structure, deepwiki_read_wiki_contents, and deepwiki_ask_question
  5. The reply is a function_call named mcp__deepwiki__deepwiki_read_wiki_structure with no namespace, which matches nothing Codex registered
  6. The screen shows "I can't call the DeepWiki MCP in this session because that tool is currently unavailable (unsupported call for read_wiki_structure)" and the session log records unsupported call: mcp__deepwiki__deepwiki_read_wiki_structure
  7. Retrying with x-headroom-bypass: true on the provider gets the same refusal while Headroom's request counter stays flat

After: the same prompt runs the MCP tool and answers

  1. The proxy admin adds a guardrail (Headroom, mode: pre_call, default_on: true) to the proxy config and registers an MCP server (deepwiki) on the proxy
  2. The developer points Codex CLI at the gateway (base_url = "http://litellm-domain/v1", wire_api = "responses") with [mcp_servers.deepwiki] at http://litellm-domain/mcp/deepwiki
  3. They type "Use the deepwiki MCP tool to read the wiki structure of BerriAI/litellm and reply with the first 3 section titles only."
  4. Codex sends POST http://litellm-domain/v1/responses with a namespace tool named mcp__deepwiki whose members are deepwiki_read_wiki_structure, deepwiki_read_wiki_contents, and deepwiki_ask_question
  5. The reply is a function_call named deepwiki_read_wiki_structure inside namespace mcp__deepwiki, exactly what Codex registered
  6. The screen shows "Calling deepwiki.deepwiki-read_wiki_structure({"repoName":"BerriAI/litellm"})" and then the first three section titles
  7. Headroom's /stats still counts the request, so the guardrail ran; when it rewrites or drops one member tool, only that member changes on the way to the model

Relevant issues

Fixes #39183

Supersedes #39193, which reached the same diagnosis; this PR also carries a guardrail's edits to individual tools back onto the client's original shapes and keeps custom and other non-function tools intact

Linear ticket

Resolves LIT-6691

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Real Codex CLI 0.145.0 TUI (driven under tmux) -> LiteLLM proxy /v1/responses with a Headroom pre_call guardrail (default_on: true, self-hosted headroom proxy 0.37.0) and the public DeepWiki MCP server registered on the proxy -> OpenAI gpt-5.3-codex. Each leg runs from its own fresh worktree and venv with two uvicorn workers, no DB. The MCP server, the trigger, and the model are stand-ins for the reporter's Confluence server and per-request header; the symptom is about the namespace tool shape Codex sends, not the server.

proxy_config.yaml (the Before and After legs differ only in the Headroom port and master key):

model_list:
  - model_name: gpt-5.3-codex
    litellm_params:
      model: openai/gpt-5.3-codex
      api_key: os.environ/OPENAI_API_KEY
  - model_name: claude-bridge
    litellm_params:
      model: anthropic/claude-sonnet-5
      api_key: os.environ/ANTHROPIC_API_KEY
guardrails:
  - guardrail_name: headroom-compression
    litellm_params:
      guardrail: headroom
      mode: pre_call
      api_base: http://127.0.0.1:42276
      default_on: true
mcp_servers:
  deepwiki:
    url: https://mcp.deepwiki.com/mcp
    transport: http
general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY

Codex config.toml (CODEX_HOME=$L/codex_on; codex_off adds http_headers = { "x-headroom-bypass" = "true" } under [model_providers.litellm]):

model = "gpt-5.3-codex"
model_provider = "litellm"
approval_policy = "never"
sandbox_mode = "read-only"
[model_providers.litellm]
name = "LiteLLM"
base_url = "http://127.0.0.1:20220/v1"
env_key = "LITELLM_CODEX_KEY"
wire_api = "responses"
[mcp_servers.deepwiki]
url = "http://127.0.0.1:20220/mcp/deepwiki"
http_headers = { "x-litellm-api-key" = "sk-lit6691-before" }

Before (merge base 55e9e4c)

git worktree add --detach /Users/mateo/Development/litellm-worktrees/lit6691-qa-before 55e9e4ce2fe9da95be1c7c48e93a6f0899f96eeb
cd /Users/mateo/Development/litellm-worktrees/lit6691-qa-before && make bootstrap
headroom proxy --port 42276
.venv/bin/python litellm/proxy/proxy_cli.py --config proxy_config.yaml --port 20220 --num_workers 2 --detailed_debug
tmux new-session -d -s qabefore-on -x 200 -y 50 -c "$L/codexproj" "env CODEX_HOME=$L/codex_on LITELLM_CODEX_KEY=sk-lit6691-before codex"
tmux send-keys -t qabefore-on "Use the deepwiki MCP tool to read the wiki structure of BerriAI/litellm and reply with the first 3 section titles only."
tmux send-keys -t qabefore-on Enter
tmux send-keys -t qabefore-on "Go ahead and call the deepwiki read_wiki_structure tool now for BerriAI/litellm."
tmux send-keys -t qabefore-on Enter

Codex screen (run A, Headroom on):

› Use the deepwiki MCP tool to read the wiki structure of BerriAI/litellm and reply with the first 3 section titles only.
• I'll fetch the DeepWiki structure for BerriAI/litellm now and return only the first three section titles.
› Go ahead and call the deepwiki read_wiki_structure tool now for BerriAI/litellm.
• I can't execute that MCP call in this environment right now (unsupported call: mcp__deepwiki__deepwiki_read_wiki_structure).
  If you want, I can try an alternative available path (e.g., checking available MCP resources/tools in this session) and then fetch the first 3 section titles that way.

Codex session log codex_on/sessions/2026/09/02/rollout-2026-09-02T11-45-10-*.jsonl: the model's call carries the flattened name and no namespace, and Codex rejects it

{"type": "function_call", "name": "mcp__deepwiki__deepwiki_read_wiki_structure", "arguments": "{\"repoName\":\"BerriAI/litellm\"}", "call_id": "call_XA1lJEXfxJ5vUiQKMuSKVjHj"}
{"type": "function_call_output", "call_id": "call_XA1lJEXfxJ5vUiQKMuSKVjHj", "output": "unsupported call: mcp__deepwiki__deepwiki_read_wiki_structure"}

Headroom /stats after run A: api_requests=3, requests_compressed=0, uncompressed_requests={"no_compressible_content": 3}. Headroom compressed nothing and injected nothing; the rename happened anyway.

Run B (same flow with x-headroom-bypass: true): same refusal on screen (unsupported call: mcp__deepwiki__deepwiki_read_wiki_structure), the same flat function_call with no namespace in codex_off/sessions/2026/09/02/rollout-2026-09-02T11-48-52-*.jsonl, and Headroom api_requests stays at 3, so the bypass was honored by Headroom while the proxy still rewrote the tools.

Run C, the Responses-to-chat bridge with a plain function tool, works on the base too (get_weather called with {"city": "Paris"}), so the After leg's run C is a regression check, not a fix.

After (this PR at 7cbc743)

Same proxy config, Codex config, and prompt as the Before leg; the proxy runs from 7cbc743 with a single uvicorn worker (--num_workers 1), Headroom on 48046 and the proxy on 25206.

git worktree add --detach /Users/mateo/Development/litellm-worktrees/lit6691-qa-after 7cbc74399d683b1113a4236768ac8414e7e9f07d
cd /Users/mateo/Development/litellm-worktrees/lit6691-qa-after && make bootstrap
headroom proxy --port 48046
.venv/bin/python litellm/proxy/proxy_cli.py --config proxy_config.yaml --port 25206 --num_workers 1 --detailed_debug
curl -s http://127.0.0.1:48046/stats   # before run A: api_requests=0
tmux new-session -d -s qa3-on -x 200 -y 50 -c "$L/codexproj" "env CODEX_HOME=$L/codex_on LITELLM_CODEX_KEY=sk-lit6691-after codex"
tmux send-keys -t qa3-on "Use the deepwiki MCP tool to read the wiki structure of BerriAI/litellm and reply with the first 3 section titles only."
tmux send-keys -t qa3-on Enter

The proxy log for this leg shows 0 uvicorn worker deaths (grep -c 'Child process .* died'), against nine in the earlier two-worker run.

Codex screen (run A, Headroom on), no nudge needed; the one-time "Allow the deepwiki MCP server to run tool" consent prompt was answered with Enter while polling and had scrolled off by the final capture:

› Use the deepwiki MCP tool to read the wiki structure of BerriAI/litellm and reply with the first 3 section titles only.
⚠ Model metadata for `gpt-5.3-codex` not found. Defaulting to fallback metadata; this can degrade performance and cause issues.
• I’ll fetch the repository wiki structure now and return only the first three section titles.
• Called deepwiki.deepwiki-read_wiki_structure({"repoName":"BerriAI/litellm"})
  ...
• 1. Overview
  2. Core SDK
  3. LiteLLM Proxy Server

Codex session log codex_on/sessions/2026/09/02/rollout-2026-09-02T15-41-05-01a06448-7411-7303-aa3b-9abe5fb878f9.jsonl: the model's call keeps the namespace, and it is the only tool name and the only namespace value in the file

"type":"function_call","id":"fc_0119120f8a56520b016a98a60ce15087d086e7e36c92e98962","name":"deepwiki_read_wiki_structure","namespace":"mcp__deepwiki","arguments":"{\"repoName\":\"BerriAI/litellm\"}"

No function_call_output contains unsupported call. Headroom /stats after run A: api_requests=2, requests_compressed=0, uncompressed_requests={"no_compressible_content": 2}, so the guardrail ran on both turns and the tools still reached the model intact.

Run B (same flow with x-headroom-bypass: true in the Codex provider headers): same screen and the same "name":"deepwiki_read_wiki_structure","namespace":"mcp__deepwiki" call in codex_off/sessions/2026/09/02/rollout-2026-09-02T15-42-19-01a06449-979e-7212-b847-a662e88d0a2c.jsonl, and Headroom api_requests stays at 2.

Run C, the Responses-to-chat bridge with a plain function tool (the transformation.py change also serves this path), still returns the tool call:

curl -s http://127.0.0.1:25206/v1/responses -H 'Authorization: Bearer sk-lit6691-after' -H 'content-type: application/json' -d '{"model":"claude-bridge","input":"What is the weather in Paris right now? You must call the get_weather tool.","tools":[{"type":"function","name":"get_weather","description":"Get the current weather for a city","parameters":{"properties":{"city":{"type":"string"}},"required":["city"]}}]}'
"output": [{"type": "function_call", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}", "call_id": "toolu_01C6JHzxwzsYtN5Gexd5AnKg", "status": "completed"}]

Type

🐛 Bug Fix

Caveats (if any)

Low

  • A guardrail that renames a tool reads as "drop the old one, add the new one", and the renamed tool comes back as a flat function, same as before this PR
  • A guardrail that edits a top-level custom tool gets a function tool back, same as before this PR
  • Guardrail-returned items are accepted as dicts or pydantic models (GuardrailToolParam included); anything else is dropped with a warning instead of being forwarded to the provider. Base answered 400 for a guardrail returning pydantic models, so no working caller changes behavior
  • Duplicate tool names are matched by occurrence order, so when a guardrail drops one of two same-named tools the merge keeps the first original either way (providers reject duplicate names before this matters)
  • A tools value that is not a list is treated as no tools: the guardrail sees none, and anything it injects becomes the whole list
  • A guardrail that only reorders tools no longer changes the order the provider sees: unchanged tools come back in request order and only appended tools land at the end. Honoring guardrail order would mean giving up the original-object round trip for every request that passes through a guardrail, and no shipped guardrail reorders tools, so this stays
  • In the earlier two-worker After leg at dc12e4c, nine uvicorn workers died during boot with no traceback before two came up and served every request; the same image dying nine times and booting twice points at machine memory pressure (34 GB of swap in use at the time) rather than the change, the Before leg on the same machine saw none, and the single-worker After leg at the final tip shown above saw none either

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

  • 2842e90 passes /live-pr-risk

…them unchanged

Any pre_call guardrail on /v1/responses flattened Codex namespace tools
into ns__member functions and wrote the flattened list back to the
request, so the model called mcp__server__tool with no namespace and
Codex rejected the call as unsupported.

The handler now keeps the client's original tools, hands the guardrail a
deep copy of the flattened ones, and rebuilds data["tools"] by matching
the guardrail's output to the originals by type and name. Unchanged
tools go back as the original objects, a dropped or edited namespace
member changes only that member, and tools the guardrail injects are
still appended.

Fixes #39183
@codspeed

codspeed Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_responses_guardrail_namespace_tools (2842e90) with litellm_internal_staging (8c58b93)

Open in CodSpeed

@codecov

codecov Bot commented Sep 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.62069% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...enai/responses/guardrail_translation/tool_merge.py 97.67% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR preserves original Responses API tool shapes while applying guardrail changes selectively.

  • Adds per-slot reconciliation for unchanged, edited, removed, and injected tools.
  • Retains namespace, custom, and Responses-only tools when guardrails leave them unchanged.
  • Refactors Responses-to-chat tool conversion into reusable structured forms.
  • Adds focused coverage for namespace members, Pydantic outputs, duplicate names, and mixed tool lists.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains, and the previously reported redundant source comment has been removed.

Important Files Changed

Filename Overview
litellm/llms/openai/responses/guardrail_translation/handler.py Deep-copies flattened tools for guardrail inspection and merges returned changes back into the original Responses tool shapes.
litellm/llms/openai/responses/guardrail_translation/tool_merge.py Implements identity-aware reconciliation of original, flattened, modified, removed, and injected tools.
litellm/responses/litellm_completion_transformation/transformation.py Refactors tool conversion into per-tool chat forms and removes the previously flagged redundant source comment.
tests/test_litellm/llms/openai/responses/test_openai_responses_guardrail_handler.py Extends handler coverage for passthrough, mutation, injection, and namespace-tool behavior.
tests/test_litellm/llms/openai/responses/test_openai_responses_guardrail_tool_merge.py Exercises reconciliation behavior across unchanged, edited, removed, duplicate, Pydantic, and unsupported tool shapes.
tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py Verifies the refactored conversion retains expected Responses-to-chat behavior.

Reviews (6): Last reviewed commit: "Merge remote-tracking branch 'origin/lit..." | Re-trigger Greptile

Comment thread litellm/responses/litellm_completion_transformation/transformation.py Outdated
Comment thread litellm/llms/openai/responses/guardrail_translation/tool_merge.py Outdated
@veria-ai

veria-ai Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 1 · PR risk: 0/10

Sort the chat-tool keys once and number duplicates with groupby instead of
rescanning every preceding key per position, so the guardrail merge stays
O(n log n) on client-supplied tool lists. Drop the comment that restated the
unsupported-tool warning in the Responses-to-chat transformation.
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Namespace drop removes custom members
    • Reordered _merged_original so the namespace rebuild path runs before the empty-guardrailed shortcut, letting _rebuilt_namespace preserve non-function members when every function is pruned, and added a regression test.

Create PR

Or push these changes by commenting:

@cursor push 23f3b9ab10
Preview (23f3b9ab10)
diff --git a/litellm/llms/openai/responses/guardrail_translation/tool_merge.py b/litellm/llms/openai/responses/guardrail_translation/tool_merge.py
--- a/litellm/llms/openai/responses/guardrail_translation/tool_merge.py
+++ b/litellm/llms/openai/responses/guardrail_translation/tool_merge.py
@@ -147,11 +147,11 @@
     guardrailed_group: Final = tuple(guardrailed_by_key[key] for key in group_keys if key in guardrailed_by_key)
     if guardrailed_group == tuple(flattened_group):
         return (original,)
-    if not guardrailed_group:
-        return ()
     members: Final = _namespace_members(original) if original.get("type") == "namespace" else ()
     if members and sum(map(_is_function, members)) == len(flattened_group):
         return _rebuilt_namespace(original, members, flattened_group, group_keys, guardrailed_by_key)
+    if not guardrailed_group:
+        return ()
     return tuple(
         LiteLLMCompletionResponsesConfig.transform_chat_completion_tool_params_to_responses_api_tools(guardrailed_group)
     )

diff --git a/tests/test_litellm/llms/openai/responses/test_openai_responses_guardrail_tool_merge.py b/tests/test_litellm/llms/openai/responses/test_openai_responses_guardrail_tool_merge.py
--- a/tests/test_litellm/llms/openai/responses/test_openai_responses_guardrail_tool_merge.py
+++ b/tests/test_litellm/llms/openai/responses/test_openai_responses_guardrail_tool_merge.py
@@ -132,6 +132,20 @@
     assert merged[0]["tools"][1] == custom_member
 
 
+def test_namespace_keeps_non_function_members_when_every_function_is_dropped():
+    custom_member = {"type": "custom", "name": "grep", "description": "Grep", "format": {"type": "text"}}
+    original = [
+        {"type": "namespace", "name": "ns", "description": "NS", "tools": [_function("read", "Read"), custom_member]}
+    ]
+    groups = _groups(original)
+
+    merged = merge_guardrailed_tools(original, groups, [])
+
+    assert len(merged) == 1
+    assert [member["name"] for member in merged[0]["tools"]] == ["grep"]
+    assert merged[0]["tools"][0] == custom_member
+
+
 def test_member_extras_edited_by_the_guardrail_land_on_that_member():
     original = [{"type": "namespace", "name": "ns", "tools": [_function("read")]}]
     groups = _groups(original)

You can send follow-ups to the cloud agent here.

Comment thread litellm/llms/openai/responses/guardrail_translation/tool_merge.py Outdated
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 7cbc743. Configure here.

…itellm_responses_guardrail_namespace_tools

# Conflicts:
#	basedpyright-code-budget.json
#	type-discipline-budget.json
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 1636fdd. Configure here.

…itellm_responses_guardrail_namespace_tools

# Conflicts:
#	type-discipline-budget.json
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 3f9e44f. Configure here.

…itellm_responses_guardrail_namespace_tools

# Conflicts:
#	type-discipline-budget.json
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 2842e90. Configure here.

@mateo-berri
mateo-berri merged commit 708c396 into litellm_internal_staging Sep 3, 2026
84 checks passed
@mateo-berri
mateo-berri deleted the litellm_responses_guardrail_namespace_tools branch September 3, 2026 00:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Codex CLI with Headroom on changes the name of MCP tools

2 participants