mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
feat(proxy): allow llm_api_routes virtual keys to list MCP tools via /v1/mcp/tools (#31031)
* feat(proxy): allow llm_api_routes virtual keys to list MCP tools via /v1/mcp/tools GET /v1/mcp/tools returns the MCP tools available to the calling key, the same data already exposed through /mcp/tools/list and /mcp-rest/tools/list, both of which are in llm_api_routes. The /v1/mcp/tools path was in no route group, so virtual keys created from the UI (which default to allowed_routes=["llm_api_routes"]) got a 403 listing tools one way but not the other. Add it to mcp_inference_routes. Unlike /v1/mcp/server, this path has no management write counterpart, so it does not need the method-aware carve-out used for server discovery. * test(proxy): parametrize MCP inference route check over the full endpoint set
This commit is contained in:
parent
26da56fbb6
commit
3615049071
2 changed files with 43 additions and 0 deletions
|
|
@ -461,6 +461,7 @@ class LiteLLMRoutes(enum.Enum):
|
|||
"/mcp/tools/call",
|
||||
"/mcp-rest/tools/list",
|
||||
"/mcp-rest/tools/call",
|
||||
"/v1/mcp/tools",
|
||||
]
|
||||
|
||||
# MCP server CRUD routes — control-plane. Gated by DISABLE_ADMIN_ENDPOINTS.
|
||||
|
|
|
|||
|
|
@ -403,6 +403,48 @@ def test_virtual_key_llm_api_routes_rejects_mcp_multi_segment_admin_subpaths(
|
|||
assert exc_info.value.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"route, method",
|
||||
[
|
||||
("/mcp", "POST"),
|
||||
("/mcp/", "POST"),
|
||||
("/mcp/my-server", "POST"), # matches the /mcp/{subpath} pattern
|
||||
("/mcp/tools", "GET"),
|
||||
("/mcp/tools/list", "POST"),
|
||||
("/mcp/tools/call", "POST"),
|
||||
("/mcp-rest/tools/list", "GET"),
|
||||
("/mcp-rest/tools/call", "POST"),
|
||||
("/v1/mcp/tools", "GET"),
|
||||
],
|
||||
)
|
||||
def test_virtual_key_llm_api_routes_allows_mcp_inference_endpoints(route, method):
|
||||
"""Every MCP inference/discovery endpoint must be reachable by virtual keys
|
||||
scoped to allowed_routes=["llm_api_routes"], the default the Create Key UI
|
||||
applies.
|
||||
|
||||
/v1/mcp/tools is the most recent addition: before it joined this group a key
|
||||
could list tools via /mcp/tools/list and /mcp-rest/tools/list but got a 403
|
||||
on the equivalent /v1/mcp/tools. Unlike /v1/mcp/server, none of these paths
|
||||
have a management write counterpart, so they live directly in
|
||||
`mcp_inference_routes` rather than behind a method-aware carve-out.
|
||||
"""
|
||||
|
||||
assert RouteChecks.is_llm_api_route(route=route) is True
|
||||
|
||||
valid_token = UserAPIKeyAuth(
|
||||
user_id="test_user",
|
||||
allowed_routes=["llm_api_routes"],
|
||||
)
|
||||
|
||||
result = RouteChecks.is_virtual_key_allowed_to_call_route(
|
||||
route=route,
|
||||
valid_token=valid_token,
|
||||
request=_mock_request(method),
|
||||
)
|
||||
|
||||
assert result is True
|
||||
|
||||
|
||||
def test_spend_logs_v2_classified_as_management_not_llm_api():
|
||||
"""Paginated spend logs are a management/spend read route, not an LLM API."""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue