diff --git a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py index b66126490f5..6fd3e1786cb 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py @@ -321,7 +321,9 @@ _OAuthDiscoveryOutcome: TypeAlias = _OAuthDiscoveryResolved | _OAuthDiscoveryFai @dataclass(frozen=True, slots=True) class _ListHeaders: - upstream: dict[str, str] | None + upstream: ( + dict[str, str] | None + ) # mutable-ok: relayed into MCPClient.extra_headers (dict[str, str]); built fresh per request, never mutated after hand-off signed_for_user: bool minted: frozenset[str] = frozenset() @@ -4506,9 +4508,9 @@ class MCPServerManager: server: MCPServer, *, user_api_key_auth: UserAPIKeyAuth | None, - mcp_auth_header: str | dict[str, str] | None, - extra_headers: dict[str, str] | None, - raw_headers: dict[str, str] | None, + mcp_auth_header: str | Mapping[str, str] | None, + extra_headers: Mapping[str, str] | None, + raw_headers: Mapping[str, str] | None, ) -> _ListHeaders: """Listing stays best-effort on missing per-user env vars, and the JWT signer never overrides an Authorization already supplied by static headers, a per-user auth header, or extra_headers.""" diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index 1f7cc29e7e2..2e6124cfc8d 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -226,7 +226,7 @@ if MCP_AVAILABLE: component gets a name distinct from the prompt-management ``Prompt`` request model.""" class ListMCPPromptsRestAPIResponse(BaseModel): - prompts: list[MCPCatalogPrompt] + prompts: Sequence[MCPCatalogPrompt] @classmethod def from_prompts(cls, prompts: Sequence[Prompt]) -> "ListMCPPromptsRestAPIResponse": @@ -238,16 +238,20 @@ if MCP_AVAILABLE: ) class ListMCPResourcesRestAPIResponse(BaseModel): - resources: list[Resource] - resource_templates: list[ResourceTemplate] + resources: Sequence[Resource] + resource_templates: Sequence[ResourceTemplate] @dataclass(frozen=True, slots=True) class _CatalogServerContext: server: MCPServer user_api_key_dict: UserAPIKeyAuth - mcp_auth_header: dict[str, str] | str | None - extra_headers: dict[str, str] | None - raw_headers: dict[str, str] + mcp_auth_header: ( + dict[str, str] | str | None + ) # mutable-ok: relayed verbatim into dict-typed auth-resolution params on the manager + extra_headers: ( + dict[str, str] | None + ) # mutable-ok: relayed to dict-typed manager params; read-only on this object + raw_headers: dict[str, str] # mutable-ok: relayed to dict-typed manager params; read-only on this object ######################################################## ############ MCP Server REST API Routes ################# diff --git a/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py b/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py index a269ad31a6b..09dde1a3a45 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py +++ b/litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py @@ -911,7 +911,7 @@ class MCPJWTSigner(CustomGuardrail): async def inject_mcp_jwt_headers_for_upstream( user_api_key_dict: UserAPIKeyAuth | None, extra_headers: dict[str, str] | None = None, - raw_headers: dict[str, str] | None = None, + raw_headers: Mapping[str, str] | None = None, *, for_list_tools: bool = False, mcp_tool_name: str = "",