{"record":{"id":"e6f3844f8c32cb5f","repo":"BerriAI/litellm","slug":"mcpjwtsigner-guardrail-guardrail-name-has-mode","errorCode":null,"errorMessage":"MCPJWTSigner guardrail '{guardrail_name}' has mode='{mode}' but must use mode='pre_mcp_call'. JWT injection only fires for MCP tool calls.","messagePattern":"MCPJWTSigner guardrail '(.+?)' has mode='(.+?)' but must use mode='pre_mcp_call'\\. JWT injection only fires for MCP tool calls\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/__init__.py","lineNumber":22,"sourceCode":"\nfrom litellm.types.guardrails import SupportedGuardrailIntegrations\n\nfrom .mcp_jwt_signer import MCPJWTSigner, get_mcp_jwt_signer\n\nif TYPE_CHECKING:\n    from litellm.types.guardrails import Guardrail, LitellmParams\n\n\ndef initialize_guardrail(litellm_params: \"LitellmParams\", guardrail: \"Guardrail\") -> MCPJWTSigner:\n    import litellm\n\n    guardrail_name: Final = guardrail.get(\"guardrail_name\")\n    if not guardrail_name:\n        raise ValueError(\"MCPJWTSigner guardrail requires a guardrail_name\")\n\n    mode: Final = litellm_params.mode\n    if mode != \"pre_mcp_call\":\n        raise ValueError(\n            f\"MCPJWTSigner guardrail '{guardrail_name}' has mode='{mode}' but must use \"\n            \"mode='pre_mcp_call'. JWT injection only fires for MCP tool calls.\"\n        )\n\n    optional_params: Final = getattr(litellm_params, \"optional_params\", None)\n\n    def _get(key):\n        if optional_params is not None:\n            v: Final = getattr(optional_params, key, None)\n            if v is not None:\n                return v\n        return getattr(litellm_params, key, None)\n\n    signer: Final = MCPJWTSigner(\n        guardrail_name=guardrail_name,\n        event_hook=litellm_params.mode,\n        default_on=litellm_params.default_on,\n        # Core signing","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/__init__.py#L4-L40","documentation":"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.","triggerScenarios":"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.","commonSituations":"Configs copied from generic guardrail examples that use mode: pre_call; mode keys typo'd; guardrail entries reused across hooks during refactors.","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"],"exampleFix":"# before\n litellm_params:\n   mode: pre_call\n\n# after\n litellm_params:\n   mode: pre_mcp_call","handlingStrategy":"validation","validationCode":"lp = guardrail_entry[\"litellm_params\"]  \nassert lp.get(\"mode\") == \"pre_mcp_call\", (  \n    f\"mcp_jwt_signer requires mode='pre_mcp_call', got {lp.get('mode')!r}\"  \n)","typeGuard":"def is_pre_mcp_call_mode(lp: object) -> bool:  \n    return isinstance(lp, dict) and lp.get(\"mode\") == \"pre_mcp_call\"","tryCatchPattern":null,"preventionTips":["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"],"tags":["mcp","jwt","guardrail","config","mode-mismatch"],"backgroundTag":"config-validation-failed","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}