litellm/tests/test_litellm/proxy/_experimental/mcp_server
Yassin Kortam f8375780fe
fix(mcp): enforce tool entitlements on every MCP tool dispatch path (#35156)
Tool-level MCP entitlements are enforced in one place,
check_tool_permission_for_key_team, reached from pre_call_tool_check. Two
dispatch paths reached a tool handler without passing through it.

execute_mcp_tool's legacy fallback dispatched into the local tool registry
after retrying the unprefixed name, with no allowed/banned-tool check, no
key/team/org tool permissions and no parameter validation. It now runs the same
gate, and only when something can actually dispatch: when the unprefixed name is
absent from the local registry too, the existing 404 stands rather than becoming
a misleading "server unavailable".

The server the tool-level checks need is available even though the tool name is
not in the tool -> server mapping: a non-empty prefix has already been compared
against the caller's allowed_mcp_servers by exact name, so the named server is
in that list. It is resolved from allowed_mcp_servers rather than from the
manager's registry, because the registry can return a server the caller holds no
grant for, and matching on anything other than name would accept a server the
server-level check never validated. The remaining case is a prefix segment that
is empty, which the server-level check skips entirely because it is gated on a
non-empty server name; that now fails closed with 503 instead of dispatching for
a caller holding no server grant at all.

An entitled caller's legacy call therefore still dispatches, so a configuration
that worked before keeps working; only the unentitled call is refused, now with
the entitlement gate's own 403.

call_tool ran pre_call_tool_check inside `if proxy_logging_obj:`, so an absent
logging object would have skipped authorization silently. This half is defensive
with no live hole: all four call sites source the module-level ProxyLogging
singleton from proxy_server.py, which is never None. The shape was still wrong.
pre_call_tool_check now runs its three authorization checks unconditionally and
only the guardrail hooks, which are dispatched through the logger, depend on one
being present.

A third reported path, where allow_all_keys, BYOM-submitted and
upstream-delegated servers are unioned in after the resolver's ceilings, was
investigated and found not to be a defect. The widening is real, but a server's
tool surface is already boundable for every caller at registration through
MCPServer.allowed_tools / disallowed_tools, enforced by
check_allowed_or_banned_tools ahead of the entitlement check, and per-caller
narrowing plus the org tool ceiling remain available. Nothing here changes that
path.

Resolves LIT-4956
2026-07-31 16:47:01 -07:00
..
auth fix(mcp): deny MCP access when a named entitlement cannot be read (#35160) 2026-07-31 15:49:22 +00:00
faults Merge origin/litellm_internal_staging into litellm_mcp_walker_consolidation 2026-07-20 16:29:24 -07:00
guardrail_translation feat(guardrails): scan and mask MCP tool results via post_mcp_call (#35155) 2026-07-30 14:10:26 -07:00
outbound_credentials feat(mcp): source the ID-JAG subject from the user's stored SSO assertion (#35147) 2026-07-31 10:25:38 -07:00
conftest.py test(mcp): isolate MCP discovery tests from a leaked SERVER_ROOT_PATH 2026-07-18 18:45:18 -07:00
test_byok_oauth_endpoints.py feat(mcp): allow native MCP OAuth support for cursor (#28327) 2026-05-20 15:28:44 -07:00
test_callback_oauth_error_responses.py Litellm oss staging 250526 (#28770) 2026-05-26 11:57:39 -07:00
test_db_credentials.py feat(mcp): send RFC 8707 resource indicators on upstream OAuth legs 2026-07-24 15:01:38 -07:00
test_discoverable_endpoints.py feat(mcp): extend keyless gateway OAuth flow to per-server MCP URL paths (#34856) 2026-07-30 17:40:32 -07:00
test_gateway_dcr_flow.py feat(mcp): manual authorization-code delivery for headless MCP clients 2026-07-28 11:23:37 -07:00
test_is_tool_name_prefixed.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_jwt_mcp_enforcement.py fix(mcp): resolve team.access_group_ids → MCP servers (#28997) 2026-05-27 12:36:50 -07:00
test_jwt_mcp_simple.py fix(mcp): resolve team.access_group_ids → MCP servers (#28997) 2026-05-27 12:36:50 -07:00
test_mcp_cost_calculator.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_mcp_custom_fields.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_mcp_debug.py chore: litellm oss staging (#30968) 2026-06-23 07:31:44 -07:00
test_mcp_discovery.py fix(mcp): default Linear MCP registry entry to streamable HTTP (#30396) 2026-06-13 14:45:47 -07:00
test_mcp_elicitation_handler.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_mcp_env_vars.py fix(mcp): drop orphaned per-user credential rows when an MCP server is deleted (#30141) 2026-06-10 15:56:58 -07:00
test_mcp_header_alias_utils.py feat(mcp): Add tool call and tool list support via UI for Oauth mcps (#28454) 2026-05-22 09:04:04 -07:00
test_mcp_hook_extra_headers.py fix(mcp): never promote caller oauth2 headers to the resolved credential on the v1 arm 2026-07-20 19:33:46 -07:00
test_mcp_max_concurrent_requests.py feat(ui): expose MCP max_concurrent_requests in server create and edit forms (#32397) 2026-07-07 22:47:03 -07:00
test_mcp_metadata_preservation.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_mcp_oauth_passthrough.py feat(mcp): extend keyless gateway OAuth flow to per-server MCP URL paths (#34856) 2026-07-30 17:40:32 -07:00
test_mcp_oauth_passthrough_cold_start.py [internal copy of #28008] Support MCP OAuth passthrough and issuer-scoped JWT auth (#28356) 2026-06-02 12:22:04 -07:00
test_mcp_oauth_passthrough_tools.py Merge origin/litellm_internal_staging into litellm_mcp_walker_consolidation 2026-07-20 16:29:24 -07:00
test_mcp_partial_update.py fix(mcp): never write discovery results to the row, heal rows a release already stamped, and retry failed discovery with backoff 2026-07-29 17:51:22 -07:00
test_mcp_sampling_completion_flow.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_mcp_sampling_model_access.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_mcp_sampling_model_resolution.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_mcp_sampling_priority_selection.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_mcp_sampling_request_builder.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_mcp_sampling_response_conversion.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_mcp_sampling_tool_conversion.py Litellm oss staging 040626 (#29671) 2026-06-04 11:07:20 -07:00
test_mcp_server.py fix(mcp): keep tool identity exact, fold case only where registration does 2026-07-30 22:13:10 -07:00
test_mcp_server_identity_env.py chore: litellm oss 170626 (#30637) 2026-06-17 21:11:12 -07:00
test_mcp_server_manager.py fix(mcp): enforce tool entitlements on every MCP tool dispatch path (#35156) 2026-07-31 16:47:01 -07:00
test_mcp_session_logging.py Add MCP semantic conventions to otelv2 (#29468) 2026-06-02 11:45:36 -07:00
test_mcp_sigv4_auth.py fix(mcp): persist config.yaml DCR clients in a server-scoped store 2026-07-17 19:42:32 -07:00
test_mcp_stale_session.py feat(mcp): extend keyless gateway OAuth flow to per-server MCP URL paths (#34856) 2026-07-30 17:40:32 -07:00
test_mcp_tool_search.py refactor(mcp): delete unreachable v1 OBO handler and gate REST OAuth on v2 resolver 2026-07-23 10:41:15 -07:00
test_mcp_toolset_scope.py fix(mcp): use a toolset row's stored tool name as written 2026-07-24 17:06:08 -07:00
test_oauth2_flow_backfill.py feat(mcp): startup backfill stamping oauth2_flow on legacy null rows (#32290) 2026-07-06 18:42:08 -07:00
test_oauth2_token_cache.py feat(mcp): send RFC 8707 resource indicators on upstream OAuth legs 2026-07-24 15:01:38 -07:00
test_oauth_issuer_stamp_backfill.py fix(mcp): never write discovery results to the row, heal rows a release already stamped, and retry failed discovery with backoff 2026-07-29 17:51:22 -07:00
test_openapi_to_mcp_generator.py fix(mcp): attach resolved OAuth credentials to OpenAPI spec_path tool calls 2026-07-20 19:20:34 -07:00
test_openapi_tool_auth.py fix(mcp): enforce tool entitlements on every MCP tool dispatch path (#35156) 2026-07-31 16:47:01 -07:00
test_rest_endpoints.py fix(mcp): annotate connected-app reachability on the gateway connect page (#34867) 2026-07-31 05:38:54 +00:00
test_semantic_tool_filter.py Merge origin/litellm_internal_staging into litellm_mcp_walker_consolidation 2026-07-20 16:29:24 -07:00
test_short_mcp_tool_prefix.py fix(mcp): recover the tool-name prefix boundary from registered prefixes 2026-07-30 22:13:09 -07:00
test_ui_session_utils.py fix(mcp): annotate connected-app reachability on the gateway connect page (#34867) 2026-07-31 05:38:54 +00:00
test_utils.py fix(mcp): alias/display-name tool routing, REST filters, BYOK auth (#32320) 2026-07-07 20:50:21 +05:30