litellm/tests/test_litellm/proxy/_experimental/mcp_server
yucheng-berri fafd294878
fix(mcp): let config.yaml MCP servers pin server_id (#39286)
* fix(mcp): let config.yaml MCP servers pin server_id

A config-defined MCP server's id is a hash of server_name|url|transport|
auth_type|alias, recomputed on every config load, so editing any of those
fields mints a new id. Every key and team granted the old id via
object_permission.mcp_servers keeps pointing at an id that no longer exists,
and the server disappears from tools/list for them with nothing logged.

load_servers_from_config now uses an explicit server_id from the server's
config entry when present and falls back to the existing hash otherwise, so
grants survive url/name/alias edits. Rejected at config load: a blank or
non-string server_id, two entries claiming the same id, a pinned id already
held by a database-backed server, and a pinned id that is another entry's
server_name or alias (expand_permission_list matches ids before names, so
that one would capture the other server's grants). Because the database
registry loads after the config on startup, a database row that lands on a
pinned config id is reported as a warning from the database reload instead,
where it is decidable; the warning is latched on the shadowed set so the
config-reload timer does not reprint it every interval.

Deployments that do not set server_id keep the exact id they have today.

* fix(mcp): close two more pinned-id capture paths

A pinned server_id equal to an alias supplied through litellm_settings
mcp_aliases was accepted, because the collision index only held the entry's
own alias field. expand_permission_list matches ids before names, so grants
written for the aliased server resolved to the pinning one. mcp_aliases keys
whose target is a config server are now reserved the same way.

A pinned server_id equal to a database-backed server's name, server_name or
alias had the same effect against the database side, and could not be
rejected at config load because the database registry is not loaded yet. The
database reload now warns about it, latched like the existing shadow warning.

* fix(mcp): reserve only the aliases the loader actually assigns

Reserving every mcp_aliases key targeting a config server was too broad in
two ways: the mapping is ignored when the entry sets its own alias, and only
the first mapping for a server is ever applied. Both cases made a pinned
server_id that could never have collided abort proxy startup. Reserve only
the name load_servers_from_config will really assign.

The database capture warning also fired for a database server whose own id is
the config server_id. There the database row wins the id outright through
get_registry precedence, so the shadow warning above it is the accurate one
and the capture message contradicted it. Skip those rows.

Also mark the two litellm-internal patches in the reload test helper, which
the test-quality gate counts; the database reload has no other seam.

* fix(mcp): match the loader's alias check exactly, is None not falsiness

load_servers_from_config consults mcp_aliases only when the entry has no
alias key at all, so an entry setting alias: "" gets no mapped alias. The
collision index used falsiness and reserved the mapped name anyway, which
failed startup on a pinned server_id that could never have collided with it.

* fix(mcp): skip one identifier, not the whole database row

A database row can shadow one config server_id by id and capture another by
name at the same time. Skipping the entire row when its id shadowed a config
entry dropped the second warning, leaving the operator with half a diagnosis.
Skip only the identifier equal to the row's own id.

* fix(mcp): reject conflicting self-pinned server ids

* fix(mcp): validate config server names before building the identifier index

The collision check reads every entry's body up front, so a malformed
entry under an invalid name surfaced as an AttributeError instead of the
name validation error the loader gave before this change.
2026-09-04 23:52:33 -07:00
..
auth fix(mcp): scope allow-all servers to virtual keys (#39531) 2026-09-03 10:32:03 -07:00
faults ci: lint the test tree for undefined names and fix all 30 (#37671) 2026-08-20 13:30:34 -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 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_deflake_20260902 2026-09-04 09:20:07 +00:00
conftest.py test: trim mcp fixture docstring and reload comment 2026-09-01 11:06:08 +00: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 fix(mcp): token refresh and M2M egress honor the admin-entered token URL 2026-08-26 15:31:45 -07:00
test_discoverable_endpoints.py fix(mcp): resolve OAuth broker endpoints by server_id with IP access checks (#39432) 2026-09-03 15:04:45 -07:00
test_gateway_dcr_flow.py fix(proxy): word database 503s by whether the fault is transient (#39256) 2026-09-02 15:05:55 -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_block_recording.py fix(guardrails): record MCP tool guardrail evaluations and blocks in usage monitor 2026-08-14 17:52:36 -04:00
test_mcp_cost_calculator.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_mcp_custom_fields.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_mcp_debug.py chore: litellm oss staging (#30968) 2026-06-23 07:31:44 -07:00
test_mcp_discovery.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -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_guardrail_usage_monitor.py fix(guardrails): record MCP tool guardrail evaluations and blocks in usage monitor 2026-08-14 17:52:36 -04:00
test_mcp_header_alias_utils.py feat(mcp): use x-mcp-<access_group>-* headers as default upstream credentials for group members (#39717) 2026-09-04 12:45:24 -07:00
test_mcp_hook_extra_headers.py fix(mcp): keep upstream OAuth Authorization when jwt signer hook injects one on tools/call (#38555) 2026-08-27 12:44:36 -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 test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_mcp_oauth_passthrough.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_mcp_oauth_passthrough_cold_start.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_mcp_oauth_passthrough_tools.py fix: resolve Python 3.14 OCR annotations and remaining matrix failures 2026-09-02 14:35:38 -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 feat(mcp): use x-mcp-<access_group>-* headers as default upstream credentials for group members (#39717) 2026-09-04 12:45:24 -07:00
test_mcp_server_identity_env.py test: trim mcp fixture docstring and reload comment 2026-09-01 11:06:08 +00:00
test_mcp_server_manager.py fix(mcp): let config.yaml MCP servers pin server_id (#39286) 2026-09-04 23:52:33 -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 ci: lint the test tree for undefined names and fix all 30 (#37671) 2026-08-20 13:30:34 -07:00
test_mcp_tool_search.py feat(mcp): semantic tool search for the native MCP Gateway (#39404) 2026-09-02 15:09:44 -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): let a resolved OAuth token target a custom upstream header (#38456) 2026-08-27 14:32:01 -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): stop reporting failed OpenAPI tool calls as successes (#37496) 2026-08-19 14:26:02 -07:00
test_openapi_tool_auth.py feat(mcp): let a resolved OAuth token target a custom upstream header (#38456) 2026-08-27 14:32:01 -07:00
test_proxy_api_credentials.py fix(proxy): refuse a teamless native-client grant for a user who has teams 2026-08-20 05:37:35 -07:00
test_rest_endpoints.py feat(mcp): use x-mcp-<access_group>-* headers as default upstream credentials for group members (#39717) 2026-09-04 12:45:24 -07:00
test_semantic_tool_filter.py fix: resolve Python 3.14 OCR annotations and remaining matrix failures 2026-09-02 14:35:38 -07:00
test_short_mcp_tool_prefix.py test: require a match= on broad pytest.raises, and drop duplicate parametrize cases (#37769) 2026-08-20 20:24:49 -07:00
test_ui_session_utils.py fix(mcp): deny the interactive dcr_bridge authorize for a user without server access (#37865) 2026-08-21 12:27:00 -07:00
test_utils.py fix(mcp): drop caller host and configured upstream headers from logged metadata (#36901) 2026-08-14 17:21:07 -07:00