BerriAI/litellm · error · ValueError
MCPJWTSigner guardrail '{guardrail_name}' has mode='{mode}'
Error message
MCPJWTSigner guardrail '{guardrail_name}' has mode='{mode}' but must use mode='pre_mcp_call'. JWT injection only fires for MCP tool calls. What it means
The MCP JWT signer only makes sense in front of MCP tool calls, so initialize_guardrail() hard-requires litellm_params.mode == 'pre_mcp_call' and raises ValueError otherwise. mode selects the guardrail event hook, and JWT injection into MCP authorization headers only fires on that hook.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/__init__.py:22
from litellm.types.guardrails import SupportedGuardrailIntegrations
from .mcp_jwt_signer import MCPJWTSigner, get_mcp_jwt_signer
if TYPE_CHECKING:
from litellm.types.guardrails import Guardrail, LitellmParams
def initialize_guardrail(litellm_params: "LitellmParams", guardrail: "Guardrail") -> MCPJWTSigner:
import litellm
guardrail_name: Final = guardrail.get("guardrail_name")
if not guardrail_name:
raise ValueError("MCPJWTSigner guardrail requires a guardrail_name")
mode: Final = litellm_params.mode
if mode != "pre_mcp_call":
raise ValueError(
f"MCPJWTSigner guardrail '{guardrail_name}' has mode='{mode}' but must use "
"mode='pre_mcp_call'. JWT injection only fires for MCP tool calls."
)
optional_params: Final = getattr(litellm_params, "optional_params", None)
def _get(key):
if optional_params is not None:
v: Final = getattr(optional_params, key, None)
if v is not None:
return v
return getattr(litellm_params, key, None)
signer: Final = MCPJWTSigner(
guardrail_name=guardrail_name,
event_hook=litellm_params.mode,
default_on=litellm_params.default_on,
# Core signingView on GitHub (pinned to 77b7c6c40c)
Solutions
- Set mode: pre_mcp_call in the guardrail's litellm_params
- If you did not intend JWT injection for MCP calls, remove the guardrail instead of changing its mode
Example fix
# before litellm_params: mode: pre_call # after litellm_params: mode: pre_mcp_call
Defensive patterns
Strategy: validation
Validate before calling
lp = guardrail_entry["litellm_params"]
assert lp.get("mode") == "pre_mcp_call", (
f"mcp_jwt_signer requires mode='pre_mcp_call', got {lp.get('mode')!r}"
) Type guard
def is_pre_mcp_call_mode(lp: object) -> bool:
return isinstance(lp, dict) and lp.get("mode") == "pre_mcp_call" Prevention
- Do not copy mode from generic guardrail examples - this hook only supports pre_mcp_call
- If you don't need JWT injection on MCP tool calls, remove the guardrail rather than changing its mode
When it happens
Trigger: An mcp_jwt_signer guardrail entry with mode set to another hook such as pre_call, during_call, or post_call - or mode omitted so it resolves to a non-matching value.
Common situations: Configs copied from generic guardrail examples that use mode: pre_call; mode keys typo'd; guardrail entries reused across hooks during refactors.
Understand the failure class
Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.
Related errors
- MCPJWTSigner guardrail requires a guardrail_name
- MCPJWTSigner: ttl_seconds must be > 0, got {resolved_ttl}
- MCPJWTSigner: token_introspection_endpoint is required for o
- MCPJWTSigner: incoming token verification failed: {exc}
- MCP Security: guardrail_name is required
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/e6f3844f8c32cb5f.
Report an issue: GitHub.