
impure0xntk/litellm-guardrail-codex-mcp
Developer toolsЭта страница переведена автоматически. Технические детали смотрите в оригинале. Открыть оригинал
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 →