
impure0xntk/litellm-guardrail-codex-mcp
Developer tools이 페이지는 AI로 자동 번역되었습니다. 기술적인 세부 사항은 원문을 확인하세요. 원문 보기
A LiteLLM that lets OpenAI Codex CLI work with model providers that do not understand Codex's MCP tool format.
개요
A LiteLLM that lets OpenAI Codex CLI work with model providers that do not understand Codex's MCP tool format. Codex CLI sends its MCP (Model Context Protocol) servers to the model using a non-standard type: "namespace" tool object. OpenAI's /v1/responses endpoint understands it. Providers such as OpenRouter do not. The tools are silently dropped and never reach the model, so the assistant behaves as though it has no tools at all. This guardrail flattens each namespace into ordinary type: "function" tools named mcp__ before the request leaves the proxy: The model sees a standard tool it can call, and its tool call comes back under that same flattened name. Because a LiteLLM custom guardrail can rewrite the raw /v1/responses request body from inside the proxy you already run. Mutating data in async_pre_call_hook propagates all the way to the upstream request. This was verified empirically against litellm 1.105.
README
원문 README의 일부입니다. 원문 보기.
litellm-guardrail-codex-mcp
A LiteLLM Custom Guardrail that lets OpenAI Codex CLI work with model providers that do not understand Codex’s MCP tool format.
The problem
Codex CLI sends its MCP (Model Context Protocol) servers to the model using a non-standard type: "namespace" tool object. OpenAI’s /v1/responses endpoint understands it. Providers such as OpenRouter do not. The tools are silently dropped and never reach the model, so the assistant behaves as though it has no tools at all.
A Codex request looks like this:
{
"model": "claude-sonnet-4.5",
"tools": [
{
"type": "namespace",
"name": "mcp__filesystem",
"tools": [
{ "name": "read_file", "description": "Read a file", "parameters": { "...": "..." } }
]
}
]
}
The fix
This guardrail flattens each namespace into ordinary type: "function" tools named mcp____ before the request leaves the proxy:
{
"tools": [
{
"type": "function",
"name": "mcp__filesystem__read_file",
"description": "Read a file",
"parameters": { "...": "..." }
}
]
}
The model sees a standard tool it can call, and its tool call comes back under that same flattened name.
Why a guardrail and not a second proxy? Because a LiteLLM custom guardrail can rewrite the raw
/v1/responsesrequest body from inside the proxy you already run. Mutatingdatainasync_pre_call_hookpropagates all the way to the upstream request. This was verified empirically against litellm 1.105.1 for both streaming and non-streaming requests: the mock upstream receivedmcp__filesystem__read_fileas atype: "function"tool. No extra hop, no extra process, and/chat/completionstraffic stays untouched.
Installation
uv pip install litellm-guardrail-codex-mcp
The guardrail module path is litellm_guardrail_codex_mcp.CodexMCPNamespaceGuardrail.
Configuration
Merge this into your LiteLLM proxy config (see examples/config.example.yaml):
guardrails:
- guardrail_name: codex-mcp-namespace-compat
litellm_params:
guardrail: litellm_guardrail_codex_mcp.CodexMCPNamespaceGuardrail
mode: [pre_call, post_call]
default_on: true
Two settings here are mandatory:
| Setting | Why |
|---|---|
default_on: true |
Without it LiteLLM’s should_run_guardrail() returns False and the hook never runs. The guardrail silently does nothing. |
mode includes post_call |
The streaming iterator hook only fires when post_call is present. With mode: pre_call alone, has_iterator_override stays false and SSE responses are never observed. |
Optional settings
| Field | Default | Meaning |
|---|---|---|
enabled |
true |
Set false to install without rewriting anything. |
target_models |
null |
Restrict to matching models, e.g. ["openrouter/*"]. Null applies to every attached route. |
설치
This server does not publish a one-line install command.
Open the repository installation guide MCP 초보자라면? mcpskill.org 가이드부터 시작하세요 →