litellm/tests/test_litellm/proxy/_experimental/mcp_server
Tin Chi Lo 7041f5768f fix(mcp): never write discovery results to the row, heal rows a release already stamped, and retry failed discovery with backoff
An interactive oauth2 MCP server created with explicit endpoint URLs and no issuer served
400 "authorization url is not configured" from /authorize about a minute after creation,
with the admin's endpoints intact in the row the whole time (#34985). Discovery wrote its
trust-on-first-use issuer into the same column an admin writes, so the next registry build
read the gateway's own output back as an admin pin, anchored the server to RFC 8414
section 3.3, and discarded the stored endpoint columns; one transient metadata fetch
failure then had nothing to serve, and the reload fast path pinned the broken entry until
an unrelated config write

The core of the fix is a deletion. The gateway no longer writes discovery results anywhere:
the OAuth columns and credentials.scopes carry admin intent alone, and everything discovery
learns lives on the in-memory registry entry, as the existing carry-forward already
assumes. With no gateway write there is no value whose provenance a later build can
misread, so the accidental anchoring cannot be expressed

Deleting the write cannot fix a row a released version already stamped, which still reads
as pinned, so a one-time startup heal clears those stamps. The signal is necessarily a
heuristic: updated_by records only the most recent writer and no audit trail says which
field it touched. A row is therefore healed only on the full signature of the defect, which
is discovery as the last writer plus an issuer plus at least one configured endpoint column
that anchoring is actively discarding; rows with an issuer but no configured endpoints are
left alone, since for them both paths resolve from the same upstream document. Every heal
logs the cleared value so an admin who pinned deliberately can re-pin, and the heal records
its own actor, which makes it idempotent

The reload fast path exempts servers missing an endpoint their flow needs, so failed
discovery retries on the normal reload cadence rather than waiting for a config write. Flow
requirements are read through effective_oauth2_flow, the column-first shape-fallback judge
every flow decision uses, so a legacy null-flow M2M row is classified exactly as the
request path classifies it instead of re-discovering forever; a dcr_bridge server with no
configured client needs its registration endpoint for the relay arm, and an entra_obo
server needs a scope, both of which discovery can supply. Retries back off per server,
doubling from one reload cadence to a fifteen-minute cap, so a permanently unresolvable
server cannot re-run the RFC 9728 to 8414 chain and re-log its warning every cycle forever

Deployments with store_model_in_db unset or false loaded MCP servers exactly once at
startup, leaving that retry with no driver, so they now refresh the registry on the same
reload interval. That job deliberately calls a reload-only entry point rather than the
startup composite, keeping the one-time oauth2_flow backfill and issuer heal out of a
recurring path

Losing the persisted trust-on-first-use issuer also means the issuer column no longer
changes underneath the OAuth token identity, so user tokens are purged only when an admin
actually edits the server

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-29 17:51:22 -07:00
..
auth refactor(mcp): delete unreachable v1 OBO handler and gate REST OAuth on v2 resolver 2026-07-23 10:41:15 -07:00
faults Merge origin/litellm_internal_staging into litellm_mcp_walker_consolidation 2026-07-20 16:29:24 -07:00
guardrail_translation fix(tests): Add missing mocks for MCP IP filtering and updated APIs (#20652) 2026-02-07 11:30:49 -08:00
outbound_credentials feat(mcp): send RFC 8707 resource indicators on upstream OAuth legs 2026-07-24 15:01: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): send RFC 8707 resource indicators on upstream OAuth legs 2026-07-24 15:01:38 -07:00
test_gateway_dcr_flow.py feat(mcp): gateway DCR session admission at the aggregate /mcp endpoint (LIT-3637) 2026-07-23 00:24:28 -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): dcr_bridge discovery facade and register relay 2026-07-10 12:37:47 -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 Merge pull request #34340 from BerriAI/litellm_lit4703_mcp_403_leak 2026-07-25 15:03:08 -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): 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_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 test(mcp): add transport-level M2M regression tests for the preemptive-401 gate 2026-07-16 17:39:38 -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): attach resolved OAuth credentials to OpenAPI spec_path tool calls 2026-07-20 19:20:34 -07:00
test_rest_endpoints.py refactor(mcp): delete unreachable v1 OBO handler and gate REST OAuth on v2 resolver 2026-07-23 10:41:15 -07: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): resolve toolset tools by the server's known prefix (#31254) 2026-06-24 20:50:16 -07:00
test_ui_session_utils.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_utils.py fix(mcp): alias/display-name tool routing, REST filters, BYOK auth (#32320) 2026-07-07 20:50:21 +05:30