fix(mcp): alias/display-name tool routing, REST filters, BYOK auth - #32320
Conversation
…ing match When an MCP server's alias differs from its server_name, tool names are listed with the alias prefix but _execute_tool_calls compared that prefix against the server_name stored in tool_server_map. The mismatch silently skipped prefix stripping, forwarding the fully-prefixed tool name upstream and causing "Unknown tool" failures. Resolve the actual MCPServer object and strip using its known prefix forms (alias, server_name, server_id) instead.
Return saved tool display/description overrides from the server table API so the edit UI reloads them, resolve display names before prefix stripping on tool calls, and honor mcp_server_name and toolset_name filters on the REST tools list endpoint. Co-authored-by: Cursor <cursoragent@cursor.com>
Playground and Responses API route MCP execution through call_tool, which skipped BYOK lookup and never set the OpenAPI auth ContextVar, so upstream calls went out unauthenticated despite a stored user credential. Co-authored-by: Cursor <cursoragent@cursor.com>
…erse mapping Regression tests for _execute_tool_calls: an MCP server whose alias differs from its server_name must still have its tool-name prefix stripped correctly, and a tool called by its configured display name must resolve back to the original tool name before dispatch.
…tern A display name replaces the tool name sent to the LLM provider, so a value with spaces or other special characters saves successfully but fails every subsequent Bedrock tool call. Validate tool_name_to_display_name server-side (create/update payload) against Bedrock's [a-zA-Z0-9_-]+ constraint, and add matching inline validation plus a save-blocking guard in the Admin UI's create and edit MCP server forms.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Greptile SummaryThis PR fixes six MCP bugs related to alias/display-name tool routing, REST filter query parameters, and BYOK authentication injection. The changes span both the Python proxy backend and the React dashboard frontend.
Confidence Score: 5/5Safe to merge — all six bug fixes are narrowly scoped to their target code paths, and each is covered by new mock-only regression tests that pass. The alias/display-name routing fix in No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/proxy/_experimental/mcp_server/mcp_server_manager.py | Adds _resolve_byok_mcp_auth_header, _format_byok_openapi_auth_header, _openapi_forwarded_extra_headers helpers; injects BYOK credentials and forwarded headers via context vars into OpenAPI tool handlers; surfaces tool_name_to_display_name/tool_name_to_description in the server table API. All paths are well-guarded. |
| litellm/proxy/_experimental/mcp_server/rest_endpoints.py | Adds mcp_server_name and toolset_name query params to GET /tools/list; introduces _resolve_toolset_scope (cached DB lookup) and _as_query_str helpers; re-raises 404s from toolset resolution; condition-gates the tool-search branch only when no server/toolset filter is active. |
| litellm/proxy/_experimental/mcp_server/utils.py | Adds TOOL_DISPLAY_NAME_PATTERN regex and validate_tool_display_names (Bedrock-safe name check); calls it from validate_and_normalize_mcp_server_payload on create/update. FastAPI import is deferred inside the function (proxy/ folder, so allowed). |
| litellm/responses/mcp/litellm_proxy_mcp_handler.py | Replaces naive split_server_prefix_from_name comparison with get_mcp_server_by_name lookup + _resolve_display_name_to_original + strip_known_server_prefix; correctly handles alias ≠ server_name and display name overrides in the Responses API auto-execution path. |
| ui/litellm-dashboard/src/components/mcp_tools/utils.tsx | Adds TOOL_DISPLAY_NAME_PATTERN regex constant, validateToolDisplayName antd-validator, and normalizeToolOverrideMap (handles dict or legacy JSON-string from DB). All exported and tested. |
| ui/litellm-dashboard/src/components/mcp_tools/mcp_server_edit.tsx | Adds save-blocking guard for invalid display names; normalizes loaded overrides via normalizeToolOverrideMap on mount to fix Bug 12 (overrides never loading). |
| ui/litellm-dashboard/src/components/mcp_tools/mcp_tool_configuration.tsx | Refactors ToolRow from arrow-function to named function to support isDisplayNameInvalid state; shows inline error text and antd status="error" on the display name input. |
| ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx | Adds pre-save display name validation guard in handleCreate, mirroring the guard in MCPServerEdit. |
| tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_hook_extra_headers.py | Only formatting changes (line-length normalization); no logic changes, no test weakening. |
| tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py | Adds test_build_mcp_server_table_preserves_tool_overrides regression test for Bug 12 backend fix; no existing tests modified. |
| tests/test_litellm/proxy/_experimental/mcp_server/test_rest_endpoints.py | Adds four new tests for mcp_server_name/toolset_name query params and 404 behavior; all mock-only, no real network calls. |
| tests/test_litellm/proxy/_experimental/mcp_server/test_utils.py | New file; tests validate_tool_display_names (valid/invalid patterns) and validate_and_normalize_mcp_server_payload with tool display name payloads. |
| tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py | Adds get_mcp_server_by_name mock to existing fixture (required by new code path), and two new regression tests for alias prefix stripping (Bug 8) and display name reverse-mapping (Bug 11). |
Reviews (6): Last reviewed commit: "fix: correct mcp alias routing regressio..." | Re-trigger Greptile
No logic changes; satisfies the format checks flagged on PR #32320.
Extract toolset-scope resolution and query-param normalization out of list_tool_rest_api into helpers to bring it back under the C901 complexity budget (was 18, now within the 15 threshold). Add the missing get_mcp_server_by_name stub to the streaming iterator test's mock manager; the alias-fallback resolution added for tool-name-prefix stripping calls it unconditionally when _get_mcp_server_from_tool_name misses.
…tch gap _format_byok_openapi_auth_header, _openapi_forwarded_extra_headers, and _resolve_byok_mcp_auth_header were only exercised indirectly via a mocked call_tool test, leaving their branches (auth-type formatting, header forwarding/stripping, missing-credential 401) uncovered.
|
bugbot run |
_resolve_byok_mcp_auth_header can raise a 401 when no credential is stored. Resolving it after during_hook_task was already queued meant a hook's side effects (audit logging, rate-limit bookkeeping) could run and record success for a tool call that then fails on the missing credential.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
Bugbot Autofix prepared fixes for all 3 issues found in the latest run.
- ✅ Fixed: Global mapping breaks display reverse
- Responses auto-execution now prefers the server from tool_server_map before falling back to global tool-name lookup, with a collision regression test.
- ✅ Fixed: Toolset 404 returns HTTP 200
- The REST tool list endpoint now re-raises 404 HTTPExceptions so missing toolsets return a real 404.
- ✅ Fixed: REST filters skipped for tool search
- The virtual tool-search catalog shortcut now only applies to unscoped list requests, allowing server and toolset filters to return real scoped tools.
You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit 106ea4a. Configure here.
|
|

Relevant issues
Linear ticket
Summary
Fixes six MCP bugs found while testing servers whose
aliasdiffers fromserver_nameand whose tools carry admin-configured display name overrides:/mcp-rest/tools/listignores filter query parameters.mcp_server_nameandtoolset_nameare now real query parameters that scope the response the same wayPOST /mcp/<server_name>andPOST /toolset/<toolset_name>/mcpalready do.[a-zA-Z0-9_-]+pattern both server-side (create/update payload) and in the Admin UI (inline error + save-blocking guard).tools/listwas forwarded as-is to the upstream MCP server instead of being reverse-mapped back to the original tool name; it now resolves through the same lookup the direct/mcp/<server_name>endpoint already used.tool_name_to_display_name/tool_name_to_descriptionoverrides, and the edit form normalizes them (dict or legacy JSON-string shape) back into form state.call_tool, which skipped the BYOK credential lookup and never set the OpenAPI auth ContextVar; it now resolves and injects the stored per-user credential on that path too.Test plan
tests/test_litellm/proxy/_experimental/mcp_server/(full directory) andtests/test_litellm/responses/mcp/pass, aside from pre-existing unrelated failures (missing optionalsemantic_routerdependency, one order-dependent env-var test)npx vitest run src/components/mcp_tools/passes (160/160)mcp_server_name/toolset_nameREST filters, tool display name validation, BYOK credential injection, tool override persistenceScreenshots / Proof of Fix
Not captured in this environment (no live proxy/Bedrock credentials available here). To verify manually:
python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml --detailed_debug --reloadalias!=server_name, add a tool display name override (Admin UI → MCP Servers → server → Settings → Tool Configuration → Flat List)Type
🐛 Bug Fix
✅ Test
Note
Medium Risk
Touches authentication (BYOK credential resolution, header forwarding) and tool-name resolution on hot paths (Responses auto-exec,
call_tool); behavior changes are scoped but mistakes could cause wrong upstream tools or auth failures.Overview
Fixes MCP tool routing and auth when alias differs from server_name, when admins set tool display name overrides, and when Playground/Responses call tools without going through
execute_mcp_tool.Responses auto-execution now resolves the server from the namespaced tool, reverse-maps display names to upstream tool names, and strips prefixes via
strip_known_server_prefix(alias/server_name aware) instead of comparing onlyserver_name.GET /mcp-rest/tools/listacceptsmcp_server_nameandtoolset_namequery params (toolset scope via_apply_toolset_scope);tool_name_to_display_name/tool_name_to_descriptionare included in the server table API and normalized in the edit UI.Display names are validated against Bedrock’s
[a-zA-Z0-9_-]+on create/update (backend + dashboard inline/save guards).OpenAPI-backed MCP
call_toolresolves BYOK credentials (_resolve_byok_mcp_auth_header), formats auth for OpenAPI (ApiKey/Basic/Bearer), and forwards configuredextra_headersthrough request context vars for direct handler calls.Reviewed by Cursor Bugbot for commit 106ea4a. Bugbot is set up for automated code reviews on this repo. Configure here.