refactor(mcp): drop the experimental label from the MCP server and client paths (#48513)

* refactor(mcp): drop the experimental label from the MCP server and client paths

Move litellm/proxy/_experimental/mcp_server to litellm/proxy/mcp_server and litellm/experimental_mcp_client to litellm/mcp_client, with the mirrored tests moved under tests/unit/proxy/mcp_server and tests/unit/mcp_client. Both old packages stay as shims that warn with DeprecationWarning, re-export the new package's public names and alias every submodule in sys.modules so deep imports keep resolving to the same objects. The OpenAPI docs gate now puts the merge base's enterprise package on PYTHONPATH so its base counts do not mix the checked-out enterprise code with the base litellm tree

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ci(mcp): keep tests/unit/proxy/_experimental as a sharded root for the shim tests

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(mcp): alias namespace subpackages and bind attributes in the deprecated MCP shims

pkgutil.walk_packages skipped mcp_server/auth because it has no __init__.py, so old imports of litellm.proxy._experimental.mcp_server.auth.* failed, and sys.modules entries alone left litellm.experimental_mcp_client.tools unreachable as an attribute. Walk the package on disk and setattr each alias on its old parent.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Mateo Wang 2026-10-27 10:47:50 -07:00 • committed by GitHub
parent 0657ed46cf
commit 0a1dbc0fb4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
295 changed files with 4954 additions and 4799 deletions

View file

@ -579,13 +579,13 @@ jobs:
- shard: mcp-elicitation
test-path: |-
tests/unit/experimental_mcp_client/test_mcp_client.py
tests/unit/proxy/_experimental/mcp_server/test_capabilities.py
tests/unit/proxy/_experimental/mcp_server/test_interactions.py
tests/unit/proxy/_experimental/mcp_server/test_mcp_elicitation_handler.py
tests/unit/proxy/_experimental/mcp_server/test_mcp_server_manager.py
tests/unit/proxy/_experimental/mcp_server/test_mcp_server_tool_calls_and_headers.py
tests/unit/proxy/_experimental/mcp_server/test_operations.py
tests/unit/mcp_client/test_mcp_client.py
tests/unit/proxy/mcp_server/test_capabilities.py
tests/unit/proxy/mcp_server/test_interactions.py
tests/unit/proxy/mcp_server/test_mcp_elicitation_handler.py
tests/unit/proxy/mcp_server/test_mcp_server_manager.py
tests/unit/proxy/mcp_server/test_mcp_server_tool_calls_and_headers.py
tests/unit/proxy/mcp_server/test_operations.py
python-version: "3.12"
workers: 4
reruns: 0
@ -603,7 +603,7 @@ jobs:
tests/unit/proxy/spend_tracking
--ignore=tests/unit/proxy/spend_tracking/test_search_api_logging.py
tests/unit/proxy/pass_through_endpoints
tests/unit/proxy/experimental
tests/unit/proxy/mcp_server/test_tool_registry.py
tests/unit/proxy/common_utils
--ignore=tests/unit/proxy/common_utils/test_cache_aware_routing.py
--ignore=tests/unit/proxy/common_utils/test_check_batch_cost.py
@ -811,14 +811,14 @@ jobs:
- shard: mcp-oauth
test-path: |-
tests/unit/proxy/_experimental/mcp_server/test_discoverable_endpoints.py
tests/unit/proxy/_experimental/mcp_server/test_mcp_server_manager.py
tests/unit/proxy/_experimental/mcp_server/test_db_credentials.py
tests/unit/proxy/_experimental/mcp_server/test_gateway_dcr_flow.py
tests/unit/proxy/_experimental/mcp_server/test_mcp_oauth_passthrough_tools.py
tests/unit/proxy/_experimental/mcp_server/test_mcp_max_concurrent_requests.py
tests/unit/proxy/_experimental/mcp_server/faults/test_list_outcomes.py
tests/unit/proxy/_experimental/mcp_server/outbound_credentials
tests/unit/proxy/mcp_server/test_discoverable_endpoints.py
tests/unit/proxy/mcp_server/test_mcp_server_manager.py
tests/unit/proxy/mcp_server/test_db_credentials.py
tests/unit/proxy/mcp_server/test_gateway_dcr_flow.py
tests/unit/proxy/mcp_server/test_mcp_oauth_passthrough_tools.py
tests/unit/proxy/mcp_server/test_mcp_max_concurrent_requests.py
tests/unit/proxy/mcp_server/faults/test_list_outcomes.py
tests/unit/proxy/mcp_server/outbound_credentials
python-version: "3.12"
workers: 4
reruns: 2
@ -828,19 +828,21 @@ jobs:
- shard: mcp-server
test-path: |-
tests/unit/mcp_client
tests/unit/experimental_mcp_client
tests/unit/proxy/mcp_server
tests/unit/proxy/_experimental/mcp_server
tests/unit/responses/mcp
--ignore=tests/unit/experimental_mcp_client/test_mcp_client.py
--ignore=tests/unit/proxy/_experimental/mcp_server/test_capabilities.py
--ignore=tests/unit/proxy/_experimental/mcp_server/test_interactions.py
--ignore=tests/unit/proxy/_experimental/mcp_server/test_mcp_elicitation_handler.py
--ignore=tests/unit/proxy/_experimental/mcp_server/test_mcp_server_manager.py
--ignore=tests/unit/proxy/_experimental/mcp_server/test_mcp_server_tool_calls_and_headers.py
--ignore=tests/unit/proxy/_experimental/mcp_server/test_operations.py
--ignore=tests/unit/proxy/_experimental/mcp_server/test_discoverable_endpoints.py
--ignore=tests/unit/proxy/_experimental/mcp_server/test_db_credentials.py
--ignore=tests/unit/proxy/_experimental/mcp_server/outbound_credentials
--ignore=tests/unit/mcp_client/test_mcp_client.py
--ignore=tests/unit/proxy/mcp_server/test_capabilities.py
--ignore=tests/unit/proxy/mcp_server/test_interactions.py
--ignore=tests/unit/proxy/mcp_server/test_mcp_elicitation_handler.py
--ignore=tests/unit/proxy/mcp_server/test_mcp_server_manager.py
--ignore=tests/unit/proxy/mcp_server/test_mcp_server_tool_calls_and_headers.py
--ignore=tests/unit/proxy/mcp_server/test_operations.py
--ignore=tests/unit/proxy/mcp_server/test_discoverable_endpoints.py
--ignore=tests/unit/proxy/mcp_server/test_db_credentials.py
--ignore=tests/unit/proxy/mcp_server/outbound_credentials
python-version: "3.12"
workers: 4
reruns: 0

2
.gitignore vendored
View file

@ -105,7 +105,7 @@ litellm_config.yaml
.cursor
litellm/proxy/to_delete_loadtest_work/*
update_model_cost_map.py
tests/unit/proxy/_experimental/mcp_server/test_mcp_server_manager.py
tests/unit/proxy/mcp_server/test_mcp_server_manager.py
scripts/test_vertex_ai_search.py
LAZY_LOADING_IMPROVEMENTS.md
STABILIZATION_TODO.md

View file

@ -313,7 +313,7 @@ test-unit-proxy-core: install-test-deps
$(UV_RUN) pytest tests/unit/proxy/auth tests/unit/proxy/client tests/unit/proxy/db tests/unit/proxy/hooks tests/unit/proxy/policy_engine --ignore=tests/unit/proxy/db/db_transaction_queue/test_e2e_pod_lock_manager.py --ignore=tests/unit/proxy/db/test_update_daily_tag_spend.py --tb=short -vv -n 4 --durations=20
test-unit-proxy-misc: install-test-deps
$(UV_RUN) pytest tests/unit/proxy/agent_endpoints tests/unit/proxy/anthropic_endpoints tests/unit/proxy/common_utils --ignore=tests/unit/proxy/common_utils/test_cache_aware_routing.py --ignore=tests/unit/proxy/common_utils/test_check_batch_cost.py --ignore=tests/unit/proxy/common_utils/test_check_responses_cost.py --ignore=tests/unit/proxy/common_utils/test_proxy_encrypt_decrypt.py --ignore=tests/unit/proxy/common_utils/test_realtime_cache.py tests/unit/proxy/discovery_endpoints tests/unit/proxy/experimental tests/unit/proxy/google_endpoints tests/unit/proxy/health_endpoints tests/unit/proxy/image_endpoints tests/unit/proxy/middleware --ignore=tests/unit/proxy/middleware/test_request_size_limit_middleware.py tests/unit/proxy/openai_files_endpoint tests/unit/proxy/pass_through_endpoints tests/unit/proxy/prompts tests/unit/proxy/public_endpoints tests/unit/proxy/response_api_endpoints tests/unit/proxy/shutdown tests/unit/proxy/spend_tracking --ignore=tests/unit/proxy/spend_tracking/test_search_api_logging.py tests/unit/proxy/ui_crud_endpoints tests/unit/proxy/vector_store_endpoints tests/unit/proxy/_experimental/mcp_server/test_mcp_server_tool_calls_and_headers.py --ignore=tests/unit/proxy/google_endpoints/test_gemini_agents_endpoints.py --ignore=tests/unit/proxy/google_endpoints/test_google_endpoint_routing.py --ignore=tests/unit/proxy/google_endpoints/test_google_gemini_proxy_request.py --ignore=tests/unit/proxy/public_endpoints/test_blog_posts_endpoint.py --tb=short -vv -n 4 --durations=20
$(UV_RUN) pytest tests/unit/proxy/agent_endpoints tests/unit/proxy/anthropic_endpoints tests/unit/proxy/common_utils --ignore=tests/unit/proxy/common_utils/test_cache_aware_routing.py --ignore=tests/unit/proxy/common_utils/test_check_batch_cost.py --ignore=tests/unit/proxy/common_utils/test_check_responses_cost.py --ignore=tests/unit/proxy/common_utils/test_proxy_encrypt_decrypt.py --ignore=tests/unit/proxy/common_utils/test_realtime_cache.py tests/unit/proxy/discovery_endpoints tests/unit/proxy/mcp_server/test_tool_registry.py tests/unit/proxy/google_endpoints tests/unit/proxy/health_endpoints tests/unit/proxy/image_endpoints tests/unit/proxy/middleware --ignore=tests/unit/proxy/middleware/test_request_size_limit_middleware.py tests/unit/proxy/openai_files_endpoint tests/unit/proxy/pass_through_endpoints tests/unit/proxy/prompts tests/unit/proxy/public_endpoints tests/unit/proxy/response_api_endpoints tests/unit/proxy/shutdown tests/unit/proxy/spend_tracking --ignore=tests/unit/proxy/spend_tracking/test_search_api_logging.py tests/unit/proxy/ui_crud_endpoints tests/unit/proxy/vector_store_endpoints tests/unit/proxy/mcp_server/test_mcp_server_tool_calls_and_headers.py --ignore=tests/unit/proxy/google_endpoints/test_gemini_agents_endpoints.py --ignore=tests/unit/proxy/google_endpoints/test_google_endpoint_routing.py --ignore=tests/unit/proxy/google_endpoints/test_google_gemini_proxy_request.py --ignore=tests/unit/proxy/public_endpoints/test_blog_posts_endpoint.py --tb=short -vv -n 4 --durations=20
test-unit-proxy-root: install-test-deps
$(UV_RUN) pytest tests/unit/proxy/test_*.py --ignore=tests/unit/proxy/test_aproxy_startup.py --ignore=tests/unit/proxy/test_credential_slot_registry.py --ignore=tests/unit/proxy/test_custom_callback_input.py --ignore=tests/unit/proxy/test_custom_logger_s3_gcs.py --ignore=tests/unit/proxy/test_custom_tokenizer_bug.py --ignore=tests/unit/proxy/test_db_schema_changes.py --ignore=tests/unit/proxy/test_deprecated_key_grace_period.py --ignore=tests/unit/proxy/test_get_favicon.py --ignore=tests/unit/proxy/test_get_image.py --ignore=tests/unit/proxy/test_prisma_client_backoff_retry.py --ignore=tests/unit/proxy/test_prompt_test_endpoint.py --ignore=tests/unit/proxy/test_proxy_config_unit_test.py --ignore=tests/unit/proxy/test_proxy_custom_auth.py --ignore=tests/unit/proxy/test_proxy_reject_logging.py --ignore=tests/unit/proxy/test_proxy_server.py --ignore=tests/unit/proxy/test_proxy_setting_guardrails.py --ignore=tests/unit/proxy/test_proxy_token_counter.py --ignore=tests/unit/proxy/test_proxy_utils.py --ignore=tests/unit/proxy/test_reducto_ocr_route.py --ignore=tests/unit/proxy/test_response_polling_pre_call_checks.py --ignore=tests/unit/proxy/test_server_root_path.py --ignore=tests/unit/proxy/test_ui_path_detection.py --ignore=tests/unit/proxy/test_unit_test_proxy_hooks.py --ignore=tests/unit/proxy/test_update_spend.py --ignore=tests/unit/proxy/test_zero_cost_model_budget_bypass.py --tb=short -vv -n 4 --durations=20
@ -325,7 +325,7 @@ test-unit-core-utils: install-test-deps
$(UV_RUN) pytest tests/unit/litellm_core_utils --tb=short -vv -n 2 --durations=20
test-unit-other: install-test-deps
$(UV_RUN) pytest tests/unit/caching tests/unit/responses tests/unit/secret_managers tests/unit/vector_stores tests/unit/a2a_protocol tests/unit/completion_extras tests/unit/containers tests/unit/enterprise tests/unit/experimental_mcp_client tests/unit/google_genai tests/unit/images tests/unit/interactions tests/unit/router_strategy tests/unit/router_utils tests/unit/types --tb=short -vv -n 4 --durations=20
$(UV_RUN) pytest tests/unit/caching tests/unit/responses tests/unit/secret_managers tests/unit/vector_stores tests/unit/a2a_protocol tests/unit/completion_extras tests/unit/containers tests/unit/enterprise tests/unit/mcp_client tests/unit/google_genai tests/unit/images tests/unit/interactions tests/unit/router_strategy tests/unit/router_utils tests/unit/types --tb=short -vv -n 4 --durations=20
test-unit-root: install-test-deps
$(UV_RUN) pytest tests/unit/test_*.py --tb=short -vv -n 4 --durations=20

View file

@ -223,7 +223,7 @@ async with httpx.AsyncClient(headers=headers, timeout=60.0) as http_client:
```python
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from litellm import experimental_mcp_client
from litellm import mcp_client
import litellm
server_params = StdioServerParameters(command="python", args=["mcp_server.py"])
@ -233,7 +233,7 @@ async with stdio_client(server_params) as (read, write):
await session.initialize()
# Load MCP tools in OpenAI format
tools = await experimental_mcp_client.load_mcp_tools(session=session, format="openai")
tools = await mcp_client.load_mcp_tools(session=session, format="openai")
# Use with any LiteLLM model
response = await litellm.acompletion(

View file

@ -18,8 +18,8 @@ from fastapi.responses import HTMLResponse, RedirectResponse, Response
from pydantic import ConfigDict, Field, SecretStr, TypeAdapter, ValidationError
from litellm.llms.custom_httpx.http_handler import get_async_httpx_client
from litellm.proxy._experimental.mcp_server.oauth_utils import get_request_base_url
from litellm.proxy._types import LiteLLM_UserTable, LitellmUserRoles, UserAPIKeyAuth
from litellm.proxy.mcp_server.oauth_utils import get_request_base_url
from litellm.types.llms.base import LiteLLMBaseModel
from litellm.types.proxy.auth.auth_checks import UserNotFoundError
@ -122,7 +122,7 @@ def _cookie_name(token: str) -> str:
async def _session_user(request: Request) -> str | None:
from litellm.proxy._experimental.mcp_server.byok_oauth_endpoints import (
from litellm.proxy.mcp_server.byok_oauth_endpoints import (
get_authenticated_browser_user_id,
)

View file

@ -1980,7 +1980,7 @@ def completion_cost(
base_pricing_model=(selected_model if base_model is not None and not custom_pricing else None),
)
elif call_type == _MCP_CALL_TYPE:
from litellm.proxy._experimental.mcp_server.cost_calculator import (
from litellm.proxy.mcp_server.cost_calculator import (
MCPCostCalculator,
)

View file

@ -1,8 +1,7 @@
try:
from .tools import call_openai_tool, load_mcp_tools
except ModuleNotFoundError as exc:
if exc.name not in ("mcp", "httpx2"):
raise
raise ImportError("MCP client dependencies are missing. Install them with: pip install 'litellm[mcp]'") from exc
import litellm.mcp_client as _mcp_client
from litellm.litellm_core_utils.deprecated_package import alias_deprecated_package
from litellm.mcp_client import call_openai_tool, load_mcp_tools
alias_deprecated_package(__name__, _mcp_client)
__all__ = ["call_openai_tool", "load_mcp_tools"]

View file

@ -0,0 +1,53 @@
import importlib
import sys
import warnings
from itertools import chain
from pathlib import Path
from types import ModuleType
from typing import Final
def _dotted_name(root: Path, path: Path, package_name: str) -> str:
parts: Final = path.relative_to(root).with_suffix("").parts
return ".".join((package_name, *parts)).removesuffix(".__init__")
def _parents_and_self(dotted: str, package_name: str) -> tuple[str, ...]:
parts: Final = dotted.removeprefix(f"{package_name}.").split(".")
return tuple(f"{package_name}.{'.'.join(parts[:depth])}" for depth in range(1, len(parts) + 1))
def _module_names(package: ModuleType) -> tuple[str, ...]:
roots: Final = tuple(Path(root) for root in package.__path__)
files: Final = tuple(
(root, path) for root in roots for path in root.rglob("*.py")
) # comprehension-ok: nested walk over each package root
leaves: Final = tuple(
name
for name in (_dotted_name(root, path, package.__name__) for root, path in files)
if name != package.__name__
)
return tuple(
sorted(
set(chain.from_iterable(_parents_and_self(leaf, package.__name__) for leaf in leaves)) - {package.__name__}
)
)
def _alias(old_name: str, new_package_name: str, new_dotted: str) -> None:
module: Final = importlib.import_module(new_dotted)
old_dotted: Final = f"{old_name}{new_dotted.removeprefix(new_package_name)}"
old_parent, _, child = old_dotted.rpartition(".")
sys.modules[old_dotted] = module
setattr(sys.modules[old_parent], child, module)
def alias_deprecated_package(old_name: str, new_package: ModuleType) -> None:
"""Make every module under ``new_package`` importable and attribute-reachable under ``old_name`` and warn once."""
warnings.warn(
f"{old_name} is deprecated, import {new_package.__name__} instead",
DeprecationWarning,
stacklevel=3,
)
for new_dotted in _module_names(new_package):
_alias(old_name, new_package.__name__, new_dotted)

View file

@ -144,7 +144,7 @@ def discover_guardrail_translation_mappings() -> dict[CallTypes, type["BaseTrans
continue
try:
from litellm.proxy._experimental.mcp_server.guardrail_translation import (
from litellm.proxy.mcp_server.guardrail_translation import (
guardrail_translation_mappings as mcp_guardrail_translation_mappings,
)

View file

@ -76,12 +76,12 @@ async def anthropic_messages_with_mcp(
upstream provider as a url it cannot reach.
"""
import litellm
from litellm.experimental_mcp_client.tools import (
transform_mcp_tool_to_anthropic_tool,
)
from litellm.llms.anthropic.messages.adapters.handler import request_safeguards_evaluator
from litellm.llms.anthropic.messages.native.handler import proxy_classifies_tool_uses
from litellm.llms.anthropic.messages.safeguards import with_safeguard_results
from litellm.mcp_client.tools import (
transform_mcp_tool_to_anthropic_tool,
)
from litellm.responses.mcp.litellm_proxy_mcp_handler import (
LiteLLM_Proxy_MCP_Handler,
)

View file

@ -5,13 +5,13 @@ LiteLLM MCP Client allows you to use MCP tools with LiteLLM
Install the optional dependencies with `pip install 'litellm[mcp]'`, then use the existing public imports:
```python
from litellm.experimental_mcp_client import call_openai_tool, load_mcp_tools
from litellm.experimental_mcp_client.client import MCPClient
from litellm.mcp_client import call_openai_tool, load_mcp_tools
from litellm.mcp_client.client import MCPClient
client = MCPClient(server_url="https://mcp.example.com/mcp")
```
Core `import litellm` works without the MCP extra. Importing the experimental MCP client without its MCP or HTTPX2 dependency raises an error with this installation command
`litellm.experimental_mcp_client` is a deprecated alias of `litellm.mcp_client` that warns on import. Core `import litellm` works without the MCP extra. Importing the MCP client without its MCP or HTTPX2 dependency raises an error with this installation command
## MCP Python SDK compatibility

View file

@ -0,0 +1,8 @@
try:
from .tools import call_openai_tool, load_mcp_tools
except ModuleNotFoundError as exc:
if exc.name not in ("mcp", "httpx2"):
raise
raise ImportError("MCP client dependencies are missing. Install them with: pip install 'litellm[mcp]'") from exc
__all__ = ["call_openai_tool", "load_mcp_tools"]

View file

@ -100,11 +100,11 @@ from litellm.constants import (
MCP_TOOL_LISTING_MAX_PAGES,
MCP_TOOL_LISTING_TIMEOUT,
)
from litellm.experimental_mcp_client.tools import list_tools_with_pagination
from litellm.llms.custom_httpx.http_handler import get_ssl_configuration
from litellm.proxy._experimental.mcp_server.mcp_context import get_active_mcp_request_ctx
from litellm.proxy._experimental.mcp_server.mcp_debug import capture_upstream_error_response
from litellm.proxy._experimental.mcp_server.result_conversion import (
from litellm.mcp_client.tools import list_tools_with_pagination
from litellm.proxy.mcp_server.mcp_context import get_active_mcp_request_ctx
from litellm.proxy.mcp_server.mcp_debug import capture_upstream_error_response
from litellm.proxy.mcp_server.result_conversion import (
age_freshness,
aggregate_freshness,
error_text_result,
@ -125,14 +125,14 @@ from litellm.types.mcp import (
)
if TYPE_CHECKING:
from litellm.proxy._experimental.mcp_server.contracts import CatalogListRequest, CatalogListResult
from litellm.proxy._experimental.mcp_server.legacy_callbacks import ElicitationCallback
from litellm.proxy.mcp_server.contracts import CatalogListRequest, CatalogListResult
from litellm.proxy.mcp_server.legacy_callbacks import ElicitationCallback
def _mcp_response_hooks() -> tuple[Callable[[httpx2.Response], Awaitable[None]], ...]:
if get_active_mcp_request_ctx() is None:
return (capture_upstream_error_response,)
from litellm.proxy._experimental.mcp_server.legacy_callbacks import (
from litellm.proxy.mcp_server.legacy_callbacks import (
get_scope_response,
record_upstream_tool_authorization,
)
@ -564,7 +564,7 @@ class MCPClient:
return self._hash_discovery_auth(await self.prepare_request_auth(), self._aws_identity())
async def subscription_auth_fingerprint(self) -> str:
from litellm.proxy._experimental.mcp_server.outbound_credentials.client_credentials import (
from litellm.proxy.mcp_server.outbound_credentials.client_credentials import (
ClientCredentialsBearerAuth,
)
@ -1125,8 +1125,8 @@ class MCPClient:
request_state: str | None,
allow_input_required: bool,
) -> TSessionResult | InputRequiredResult:
from litellm.proxy._experimental.mcp_server.contracts import ClientInteraction
from litellm.proxy._experimental.mcp_server.interactions import LegacyClientInteraction, ModernClientInteraction
from litellm.proxy.mcp_server.contracts import ClientInteraction
from litellm.proxy.mcp_server.interactions import LegacyClientInteraction, ModernClientInteraction
with anyio.fail_after(self.timeout):
first: Final = await request(input_responses, request_state)

View file

@ -0,0 +1,4 @@
import litellm.proxy.mcp_server as _mcp_server
from litellm.litellm_core_utils.deprecated_package import alias_deprecated_package
alias_deprecated_package(__name__, _mcp_server)

View file

@ -163,7 +163,7 @@ LAZY_FEATURES: Final[tuple[LazyFeature, ...]] = (
# /.well-known/oauth-authorization-server: the root document is the
# gateway's own authorization server metadata (token endpoint /token).
name="mcp_discoverable",
module_path="litellm.proxy._experimental.mcp_server.discoverable_endpoints",
module_path="litellm.proxy.mcp_server.discoverable_endpoints",
path_prefixes=(
"/oauth/client-metadata.json",
"/.well-known/oauth-",
@ -185,19 +185,19 @@ LAZY_FEATURES: Final[tuple[LazyFeature, ...]] = (
# No /mcp/oauth prefix here: the mounted /mcp sub-app would
# shadow it, and there are no actual routes there anyway.
name="mcp_byok_oauth",
module_path="litellm.proxy._experimental.mcp_server.byok_oauth_endpoints",
module_path="litellm.proxy.mcp_server.byok_oauth_endpoints",
path_prefixes=("/v1/mcp/oauth", "/.well-known/oauth-"),
),
LazyFeature(
name="mcp_rest",
module_path="litellm.proxy._experimental.mcp_server.rest_endpoints",
module_path="litellm.proxy.mcp_server.rest_endpoints",
path_prefixes=("/mcp-rest",),
),
LazyFeature(
# Hardcoded /mcp matches BASE_MCP_ROUTE; importing the constant
# here would defeat lazy loading.
name="mcp_app",
module_path="litellm.proxy._experimental.mcp_server.server",
module_path="litellm.proxy.mcp_server.server",
path_prefixes=("/mcp",),
register_fn=_mount_app("/mcp", attr_name="app"),
persistent_swagger_stub=True,

View file

@ -37,7 +37,7 @@ from litellm.litellm_core_utils.initialize_dynamic_callback_params import (
validate_langfuse_span_scope_value,
validate_no_callback_env_reference,
)
from litellm.proxy._experimental.mcp_server.stdio_gate import MCP_STDIO_DISABLED_MESSAGE, is_mcp_stdio_enabled
from litellm.proxy.mcp_server.stdio_gate import MCP_STDIO_DISABLED_MESSAGE, is_mcp_stdio_enabled
from litellm.types.agents import (
AgentCaller as AgentCaller, # noqa: PLC0414 # public re-export
)

View file

@ -16,7 +16,6 @@ from fastapi import HTTPException
from pydantic import TypeAdapter, ValidationError
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.ui_session_utils import build_effective_auth_contexts
from litellm.proxy._types import (
UI_TEAM_ID,
LiteLLM_ObjectPermissionTable,
@ -30,6 +29,7 @@ from litellm.proxy.agent_endpoints.auth.agent_access_groups import (
)
from litellm.proxy.agent_endpoints.auth.agent_caller import agent_caller_auth
from litellm.proxy.agent_endpoints.auth.managed_authorization import managed_agent_policy
from litellm.proxy.mcp_server.ui_session_utils import build_effective_auth_contexts
from litellm.repositories.table_repositories import AgentsRepository
from litellm.types.agents import AgentResponse
@ -244,7 +244,7 @@ class AgentRequestHandler:
or user_api_key_auth is None
):
return False
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
key_hash: Final = user_api_key_auth.api_key or user_api_key_auth.token
authority: Final = (
@ -905,7 +905,7 @@ async def _managed_actor_agent_access(auth: UserAPIKeyAuth) -> AgentAccess:
async def _verified_human_agent_sources(
user_id: str | None, *, allowed_team_ids: frozenset[str] | None = None
) -> tuple[tuple[str | None, frozenset[str]], ...]:
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
if user_id is None:
return ()

View file

@ -37,18 +37,6 @@ from litellm.constants import (
CLI_SSO_SESSION_TTL_SECONDS,
LITELLM_CLI_SOURCE_IDENTIFIER,
)
from litellm.proxy._experimental.mcp_server.gateway_dcr_flow import (
PROXY_API_AUDIENCE,
MintedProxyCredential,
MintProxyCredential,
SessionSigning,
proxy_credential_response,
refresh_proxy_credential,
resolve_session_signing,
revoke_session_refresh_token,
)
from litellm.proxy._experimental.mcp_server.oauth_utils import TOKEN_NO_CACHE_HEADERS
from litellm.proxy._experimental.mcp_server.outbound_credentials.session_token import SessionPrincipal
from litellm.proxy._types import LiteLLM_UserTable, LitellmUserRoles
from litellm.proxy.anthropic_endpoints.endpoints import anthropic_response, count_tokens
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
@ -58,6 +46,18 @@ from litellm.proxy.common_utils.http_parsing_utils import ( # noqa: F401 # leg
)
from litellm.proxy.management_endpoints.sso_helper_utils import CLI_SSO_SESSIONS_TARGET
from litellm.proxy.management_endpoints.ui_sso import CliSsoTeamDetail
from litellm.proxy.mcp_server.gateway_dcr_flow import (
PROXY_API_AUDIENCE,
MintedProxyCredential,
MintProxyCredential,
SessionSigning,
proxy_credential_response,
refresh_proxy_credential,
resolve_session_signing,
revoke_session_refresh_token,
)
from litellm.proxy.mcp_server.oauth_utils import TOKEN_NO_CACHE_HEADERS
from litellm.proxy.mcp_server.outbound_credentials.session_token import SessionPrincipal
from litellm.proxy.proxy_server import model_list
from litellm.types.llms.base import LiteLLMBaseModel
@ -340,7 +340,7 @@ async def _claim_device_code(login_id: str, cache: DualCache) -> bool:
def _proxy_credential_minter() -> MintProxyCredential:
from litellm.proxy._experimental.mcp_server.proxy_api_credentials import mint_proxy_credential
from litellm.proxy.mcp_server.proxy_api_credentials import mint_proxy_credential
return mint_proxy_credential

View file

@ -4,8 +4,8 @@ from typing import Final
from fastapi import APIRouter
from litellm.proxy._experimental.mcp_server.stdio_gate import is_mcp_stdio_enabled
from litellm.proxy.common_utils.html_forms.default_credentials_hint import should_hide_default_credentials_hint
from litellm.proxy.mcp_server.stdio_gate import is_mcp_stdio_enabled
from litellm.types.proxy.discovery_endpoints.ui_discovery_endpoints import (
UiDiscoveryEndpoints,
)

View file

@ -38,9 +38,9 @@ from litellm.llms.custom_httpx.http_handler import (
get_async_httpx_client,
httpxSpecialProvider,
)
from litellm.proxy._experimental.mcp_server.utils import JSONLeafPath, json_string_leaves
from litellm.proxy._types import SpecialHeaders
from litellm.proxy.litellm_pre_call_utils import get_chain_id_from_headers
from litellm.proxy.mcp_server.utils import JSONLeafPath, json_string_leaves
from litellm.types.guardrails import GuardrailEventHooks, LitellmParams, Mode
from litellm.types.proxy.guardrails.guardrail_hooks.akto import AktoGuardrailConfigModelOptionalParams
from litellm.types.utils import CallTypes, GenericGuardrailAPIInputs

View file

@ -189,7 +189,7 @@ class MCPEndUserPermissionGuardrail(CustomGuardrail):
if not direct_mcp_servers and not mcp_access_groups:
return None # Both empty → no restrictions
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import (
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import (
MCPRequestHandler,
)

View file

@ -104,7 +104,7 @@ class MCPSecurityGuardrail(CustomGuardrail):
if not requested_servers:
return frozenset()
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)

View file

@ -577,7 +577,7 @@ class PanwPrismaAirsHandler(CustomGuardrail):
if request_data.get("server_name"):
return request_data["server_name"]
try:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)

View file

@ -18,16 +18,16 @@ from litellm.constants import (
DEFAULT_MCP_SEMANTIC_FILTER_TOP_K,
)
from litellm.integrations.custom_logger import CustomLogger
from litellm.proxy._experimental.mcp_server.semantic_tool_filter import (
from litellm.proxy.mcp_server.semantic_tool_filter import (
SemanticToolFilterContextWindowError,
)
if TYPE_CHECKING:
from litellm.caching.caching import DualCache
from litellm.proxy._experimental.mcp_server.semantic_tool_filter import (
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.mcp_server.semantic_tool_filter import (
SemanticMCPToolFilter,
)
from litellm.proxy._types import UserAPIKeyAuth
from litellm.router import Router
@ -487,7 +487,7 @@ class SemanticToolFilterHook(CustomLogger):
Returns:
SemanticToolFilterHook instance if enabled, None otherwise
"""
from litellm.proxy._experimental.mcp_server.semantic_tool_filter import (
from litellm.proxy.mcp_server.semantic_tool_filter import (
SemanticMCPToolFilter,
)

View file

@ -2525,7 +2525,7 @@ async def add_litellm_data_to_request(
_headers,
allow_client_message_redaction_opt_out=_allow_client_message_redaction_opt_out,
)
from litellm.proxy._experimental.mcp_server.utils import upstream_credential_headers
from litellm.proxy.mcp_server.utils import upstream_credential_headers
_mcp_credential_headers: Final = upstream_credential_headers(_headers)
_logging_safe_headers: Final = redact_credential_headers(

View file

@ -10,7 +10,6 @@ from typing_extensions import ReadOnly, TypedDict
from litellm._internal_context import with_service_target
from litellm._logging import verbose_proxy_logger
from litellm.litellm_core_utils.core_helpers import iter_items
from litellm.proxy._experimental.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy._types import (
CommonProxyErrors,
LiteLLM_AccessGroupTable,
@ -37,6 +36,7 @@ from litellm.proxy.management_helpers.resource_display_names import (
key_display_names,
mcp_server_display_names,
)
from litellm.proxy.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy.utils import PrismaClient, get_prisma_client_or_throw
from litellm.repositories.table_repositories import AccessGroupRepository, TeamRepository
from litellm.types.access_group import (

View file

@ -44,14 +44,6 @@ from litellm.litellm_core_utils.duration_parser import duration_in_seconds
from litellm.litellm_core_utils.safe_json_dumps import safe_dumps
from litellm.models.credentials import CredentialItem
from litellm.models.project import LiteLLM_ProjectTable
from litellm.proxy._experimental.mcp_server.db import (
rotate_mcp_server_credentials_master_key,
rotate_mcp_user_credentials_master_key,
rotate_mcp_user_env_vars_master_key,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_store import (
rotate_sso_identity_assertions_master_key,
)
from litellm.proxy._types import *
from litellm.proxy._types import Litellm_EntityType, LiteLLM_VerificationToken, hash_token
from litellm.proxy.auth.auth_checks import ( # noqa: F401 # legacy module exports
@ -153,6 +145,14 @@ from litellm.proxy.management_helpers.team_member_permission_checks import (
TeamMemberPermissionChecks,
)
from litellm.proxy.management_helpers.utils import management_endpoint_wrapper
from litellm.proxy.mcp_server.db import (
rotate_mcp_server_credentials_master_key,
rotate_mcp_user_credentials_master_key,
rotate_mcp_user_env_vars_master_key,
)
from litellm.proxy.mcp_server.outbound_credentials.sso_assertion_store import (
rotate_sso_identity_assertions_master_key,
)
from litellm.proxy.search_endpoints.search_tool_registry import rotate_search_tools_master_key
from litellm.proxy.spend_tracking.budget_reservation import get_budget_window_start
from litellm.proxy.spend_tracking.spend_counter_batch import SPEND_COUNTERS_TARGET

View file

@ -49,7 +49,7 @@ from fastapi.responses import JSONResponse
from pydantic import TypeAdapter
from typing_extensions import ReadOnly, TypedDict
from litellm.proxy._experimental.mcp_server.catalog import catalog_operation, public_catalog_operation
from litellm.proxy.mcp_server.catalog import catalog_operation, public_catalog_operation
try:
from prisma.errors import RecordNotFoundError, UniqueViolationError
@ -63,19 +63,6 @@ from litellm._logging import verbose_logger, verbose_proxy_logger
from litellm._uuid import uuid
from litellm.constants import LITELLM_PROXY_ADMIN_NAME, MCP_GATEWAY_SESSION_ID_PREFIX_LENGTH
from litellm.litellm_core_utils.core_helpers import as_str_mapping
from litellm.proxy._experimental.mcp_server.utils import (
LITELLM_MCP_SERVER_DESCRIPTION,
LITELLM_MCP_SERVER_NAME,
MCP_SERVERS_TARGET,
McpServerPayloadLike,
build_env_var_setup_url,
collect_env_var_references,
get_server_prefix,
parse_admin_env_vars,
)
from litellm.proxy._experimental.mcp_server.utils import (
validate_and_normalize_mcp_server_payload as _base_validate_and_normalize_mcp_server_payload,
)
from litellm.proxy.common_utils.encrypt_decrypt_utils import (
decrypt_value_helper,
encrypt_value_helper,
@ -87,6 +74,19 @@ from litellm.proxy.management_helpers.audit_logs import (
get_audit_log_changed_by,
is_audit_logging_enabled,
)
from litellm.proxy.mcp_server.utils import (
LITELLM_MCP_SERVER_DESCRIPTION,
LITELLM_MCP_SERVER_NAME,
MCP_SERVERS_TARGET,
McpServerPayloadLike,
build_env_var_setup_url,
collect_env_var_references,
get_server_prefix,
parse_admin_env_vars,
)
from litellm.proxy.mcp_server.utils import (
validate_and_normalize_mcp_server_payload as _base_validate_and_normalize_mcp_server_payload,
)
from litellm.repositories.table_repositories import (
MCPServerRepository,
MCPUserCredentialsRepository,
@ -159,63 +159,6 @@ if MCP_AVAILABLE:
def validate_tool_name(name: str) -> _ToolNameValidationResult:
return _ToolNameValidationResult()
from litellm.proxy._experimental.mcp_server.contracts import TargetCatalog
from litellm.proxy._experimental.mcp_server.db import (
McpIdentifierConflict,
approve_mcp_server,
create_draft_mcp_server,
create_mcp_server_if_identifier_free,
delete_mcp_server,
delete_user_credential,
delete_user_env_vars,
get_all_mcp_servers,
get_draft_mcp_server,
get_mcp_server,
get_mcp_servers,
get_mcp_submissions,
get_user_env_vars,
get_user_env_vars_bulk,
get_user_oauth_credential,
is_resubmitted_oauth_client,
list_server_user_credentials,
list_user_oauth_credentials,
mcp_oauth_token_identity,
merge_user_env_vars,
oauth_credentials_for_upstream_edit,
purge_user_oauth_credentials_for_server,
reject_mcp_server,
set_mcp_server_pinned_tools,
stale_mcp_auth_fields,
store_user_credential,
store_user_oauth_credential,
update_mcp_server,
)
from litellm.proxy._experimental.mcp_server.discoverable_endpoints import ( # noqa: F401 # legacy module exports
_raise_if_not_oauth2, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
authorize_with_server,
client_supplied_application_type,
client_supplied_redirect_uris,
exchange_token_with_server,
get_request_base_url,
raise_if_not_oauth2,
redeem_passthrough_authorization_code,
register_client_with_server,
resolve_ephemeral_dcr_client,
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.proxy._experimental.mcp_server.server_resolution import (
MCPServerTargetCatalog,
authorize_mcp_server,
resolve_mcp_server,
)
from litellm.proxy._experimental.mcp_server.ui_session_utils import (
admitted_user_context,
build_effective_auth_contexts,
granted_toolset_ids,
is_ui_session_credential,
)
from litellm.proxy._types import (
LiteLLM_MCPServerTable,
LiteLLM_ObjectPermissionTable,
@ -266,6 +209,63 @@ if MCP_AVAILABLE:
convert_connector_entries,
)
from litellm.proxy.management_helpers.utils import management_endpoint_wrapper
from litellm.proxy.mcp_server.contracts import TargetCatalog
from litellm.proxy.mcp_server.db import (
McpIdentifierConflict,
approve_mcp_server,
create_draft_mcp_server,
create_mcp_server_if_identifier_free,
delete_mcp_server,
delete_user_credential,
delete_user_env_vars,
get_all_mcp_servers,
get_draft_mcp_server,
get_mcp_server,
get_mcp_servers,
get_mcp_submissions,
get_user_env_vars,
get_user_env_vars_bulk,
get_user_oauth_credential,
is_resubmitted_oauth_client,
list_server_user_credentials,
list_user_oauth_credentials,
mcp_oauth_token_identity,
merge_user_env_vars,
oauth_credentials_for_upstream_edit,
purge_user_oauth_credentials_for_server,
reject_mcp_server,
set_mcp_server_pinned_tools,
stale_mcp_auth_fields,
store_user_credential,
store_user_oauth_credential,
update_mcp_server,
)
from litellm.proxy.mcp_server.discoverable_endpoints import ( # noqa: F401 # legacy module exports
_raise_if_not_oauth2, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
authorize_with_server,
client_supplied_application_type,
client_supplied_redirect_uris,
exchange_token_with_server,
get_request_base_url,
raise_if_not_oauth2,
redeem_passthrough_authorization_code,
register_client_with_server,
resolve_ephemeral_dcr_client,
)
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.proxy.mcp_server.server_resolution import (
MCPServerTargetCatalog,
authorize_mcp_server,
resolve_mcp_server,
)
from litellm.proxy.mcp_server.ui_session_utils import (
admitted_user_context,
build_effective_auth_contexts,
granted_toolset_ids,
is_ui_session_credential,
)
from litellm.types.mcp import (
MCP_ADMIN_CONFIG_CREDENTIAL_KEYS,
MCPAuth,
@ -1097,7 +1097,7 @@ if MCP_AVAILABLE:
"""
Get all MCP tools available for the current key, including those from access groups
"""
from litellm.proxy._experimental.mcp_server.server import _list_mcp_tools
from litellm.proxy.mcp_server.server import _list_mcp_tools
listing: Final = await _list_mcp_tools(
user_api_key_auth=user_api_key_dict,
@ -1122,7 +1122,7 @@ if MCP_AVAILABLE:
"""
Get all available MCP access groups from the database AND config
"""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.proxy.proxy_server import prisma_client
@ -1678,7 +1678,7 @@ if MCP_AVAILABLE:
status_code=status.HTTP_403_FORBIDDEN,
detail={"error": "Admin access required to view MCP gateway sessions."},
)
from litellm.proxy._experimental.mcp_server.server import (
from litellm.proxy.mcp_server.server import (
get_mcp_gateway_sessions_report,
)
@ -1713,7 +1713,7 @@ if MCP_AVAILABLE:
"error": "Provide session_id_prefix and/or user_id to select the sessions to terminate.",
},
)
from litellm.proxy._experimental.mcp_server.server import (
from litellm.proxy.mcp_server.server import (
terminate_mcp_gateway_sessions,
)
@ -1777,7 +1777,7 @@ if MCP_AVAILABLE:
status_code=status.HTTP_404_NOT_FOUND,
detail={"error": f"MCP server '{server_id}' not found in the database."},
)
from litellm.proxy._experimental.mcp_server.rest_endpoints import fetch_pinnable_tool_catalog
from litellm.proxy.mcp_server.rest_endpoints import fetch_pinnable_tool_catalog
snapshot: Final = await fetch_pinnable_tool_catalog(server, request, user_api_key_dict)
if not snapshot:
@ -2342,12 +2342,12 @@ if MCP_AVAILABLE:
# issued to this client could mint fresh upstream access tokens through
# us. Require normal LiteLLM auth for those.
if not api_key:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415
global_mcp_server_manager,
)
from litellm.proxy.auth.auth_utils import ( # noqa: PLC0415
get_request_route,
)
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415
global_mcp_server_manager,
)
server_id: Final[str] = request.path_params.get("server_id", "")
if server_id:
@ -2677,7 +2677,7 @@ if MCP_AVAILABLE:
)
if payload.save:
await store_user_credential(prisma_client, user_id, server_id, payload.credential)
from litellm.proxy._experimental.mcp_server.server import (
from litellm.proxy.mcp_server.server import (
_invalidate_byok_cred_cache,
)
@ -2708,7 +2708,7 @@ if MCP_AVAILABLE:
await delete_user_credential(prisma_client, target_user_id, server_id)
except RecordNotFoundError:
pass # Already deleted or didn't exist
from litellm.proxy._experimental.mcp_server.server import (
from litellm.proxy.mcp_server.server import (
_invalidate_byok_cred_cache,
)
@ -2732,7 +2732,7 @@ if MCP_AVAILABLE:
"""Persist the OAuth2 access token obtained by the calling user."""
prisma_client: Final = get_prisma_client_or_throw("Database not connected. Connect a database to your proxy")
await _authorize_and_fetch_mcp_server(prisma_client, user_api_key_dict, server_id)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # keep manager import lazy
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # keep manager import lazy
global_mcp_server_manager as _manager,
)
@ -2769,7 +2769,7 @@ if MCP_AVAILABLE:
expires_in=payload.expires_in,
scopes=payload.scopes,
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415
global_mcp_server_manager,
)
@ -2813,7 +2813,7 @@ if MCP_AVAILABLE:
await delete_user_credential(prisma_client, target_user_id, server_id)
except RecordNotFoundError:
pass # Already gone — treat as a successful delete
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415
global_mcp_server_manager,
)
@ -3107,7 +3107,7 @@ if MCP_AVAILABLE:
allowed_names: Final = {spec["name"] for spec in user_specs}
updates: Final = {k: v for k, v in payload.values.items() if k in allowed_names and v != ""}
merged: Final = await merge_user_env_vars(prisma_client, user_id, server_id, updates, allowed_names)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
invalidate_user_env_vars_cache,
)
@ -3134,7 +3134,7 @@ if MCP_AVAILABLE:
)
server: Final = await _authorize_and_fetch_mcp_server(prisma_client, user_api_key_dict, server_id)
await delete_user_env_vars(prisma_client, user_id, server_id)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
invalidate_user_env_vars_cache,
)
@ -3369,7 +3369,7 @@ if MCP_AVAILABLE:
try:
# Update the public model groups
import litellm
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.proxy.proxy_server import proxy_config
@ -3532,7 +3532,7 @@ if MCP_AVAILABLE:
# MCP Toolset endpoints
# ---------------------------------------------------------------------------
from litellm.proxy._experimental.mcp_server.toolset_db import (
from litellm.proxy.mcp_server.toolset_db import (
create_mcp_toolset,
delete_mcp_toolset,
get_mcp_toolset,
@ -3577,7 +3577,7 @@ if MCP_AVAILABLE:
status_code=status.HTTP_409_CONFLICT,
detail={"error": f"A toolset named '{payload.toolset_name}' already exists."},
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -3673,7 +3673,7 @@ if MCP_AVAILABLE:
status_code=status.HTTP_404_NOT_FOUND,
detail={"error": f"Toolset '{payload.toolset_id}' not found."},
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -3703,7 +3703,7 @@ if MCP_AVAILABLE:
status_code=status.HTTP_404_NOT_FOUND,
detail={"error": f"Toolset '{toolset_id}' not found."},
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)

View file

@ -38,13 +38,13 @@ from pydantic import ValidationError
from litellm._internal_context import with_service_target
from litellm._logging import verbose_proxy_logger
from litellm.caching.dual_cache import DualCache
from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_store import (
SSOIdentityAssertion,
assertion_from_saml_login,
)
from litellm.proxy.auth.ip_address_utils import IPAddressUtils
from litellm.proxy.management_endpoints.sso_helper_utils import SSO_SESSIONS_TARGET
from litellm.proxy.management_endpoints.types import CustomOpenID, get_litellm_user_role
from litellm.proxy.mcp_server.outbound_credentials.sso_assertion_store import (
SSOIdentityAssertion,
assertion_from_saml_login,
)
from litellm.proxy.utils import get_custom_url
try:

View file

@ -72,17 +72,6 @@ from litellm.llms.custom_httpx.http_handler import (
get_async_httpx_client,
httpxSpecialProvider,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.login_assertion_exchange import (
exchange_login_assertion_if_configured,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_store import (
GOOGLE_REFRESH_TOKEN_PARAMS,
MICROSOFT_REFRESH_TOKEN_SCOPE,
SSOIdentityAssertion,
assertion_from_sso_login,
ema_assertion_retention_enabled,
retain_sso_identity_assertion_for_ema,
)
from litellm.proxy._types import (
CommonProxyErrors,
LiteLLM_UserTable,
@ -143,6 +132,17 @@ from litellm.proxy.management_endpoints.types import (
get_litellm_user_role,
is_valid_litellm_user_role,
)
from litellm.proxy.mcp_server.outbound_credentials.login_assertion_exchange import (
exchange_login_assertion_if_configured,
)
from litellm.proxy.mcp_server.outbound_credentials.sso_assertion_store import (
GOOGLE_REFRESH_TOKEN_PARAMS,
MICROSOFT_REFRESH_TOKEN_SCOPE,
SSOIdentityAssertion,
assertion_from_sso_login,
ema_assertion_retention_enabled,
retain_sso_identity_assertion_for_ema,
)
from litellm.proxy.utils import (
PrismaClient,
ProxyLogging,

View file

@ -300,7 +300,7 @@ async def _resolve_mcp_server_identifiers_to_ids(
if not identifiers:
return {}
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -450,7 +450,7 @@ async def _resolve_team_allowed_mcp_servers(
- Servers from mcp_access_groups
- Server IDs referenced in mcp_tool_permissions keys
"""
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import (
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import (
MCPRequestHandler,
)
@ -475,7 +475,7 @@ async def _resolve_team_allowed_mcp_servers(
def get_allow_all_keys_server_ids() -> set[str]:
"""Return the set of MCP server IDs marked with allow_all_keys=True."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -487,7 +487,7 @@ _get_allow_all_keys_server_ids: Final = get_allow_all_keys_server_ids
def _get_all_mcp_server_ids() -> set[str]:
"""Return every MCP server id registered on the proxy (config + DB union)."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)

View file

@ -12,7 +12,7 @@ wiring must change with it.
Respect the current package boundaries:
```text
litellm/proxy/_experimental/mcp_server/
litellm/proxy/mcp_server/
AGENTS.md
server.py # ASGI/MCP route handling, sessions, tool calls [PR7: 7-arm only — move BYOK/OAuth pre-fetch into resolver]
mcp_server_manager.py # upstream server registry, clients, tool routing [PR7: _create_mcp_client swaps resolve_mcp_auth -> resolve_credentials]
@ -89,7 +89,7 @@ module materially harder to understand.
## Tests
Mirror this package under `tests/unit/proxy/_experimental/mcp_server/`.
Mirror this package under `tests/unit/proxy/mcp_server/`.
For regressions, extend the existing mapped test file instead of creating a new
one. Use subdirectories that match the implementation path, such as
`auth/test_token_endpoint_auth.py` for `auth/token_endpoint_auth.py` and

View file

@ -8,15 +8,15 @@ from litellm.types.proxy.agent_identity import AgentIdentityFailure
async def _delegated_resource_subject(user_id: str) -> UserAPIKeyAuth:
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
human: Final = await MCPRequestHandler.reload_admitted_user(user_id, requires_fresh_policy=True)
return human.model_copy(update=MappingProxyType({"mcp_explicit_grants_only": True}))
async def managed_agent_servers(auth: UserAPIKeyAuth) -> tuple[str, ...]:
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
from litellm.proxy._experimental.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
from litellm.proxy.mcp_server.mcp_server_manager import global_mcp_server_manager
agent: Final = auth.managed_agent_policy
if agent is None:
@ -49,7 +49,7 @@ async def managed_agent_servers(auth: UserAPIKeyAuth) -> tuple[str, ...]:
async def managed_agent_tools(server_id: str, auth: UserAPIKeyAuth) -> list[str] | None:
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
if server_id not in await managed_agent_servers(auth):
return []

View file

@ -21,33 +21,7 @@ import litellm
from litellm._internal_context import with_service_target
from litellm._logging import verbose_logger
from litellm.constants import MCP_ALL_TOOLS_WILDCARD, MCP_PEEKED_BODY_SCOPE_KEY
from litellm.experimental_mcp_client.client import strip_auth_scheme
from litellm.proxy._experimental.mcp_server.catalog import global_manager
from litellm.proxy._experimental.mcp_server.oauth_utils import (
get_passthrough_resource_metadata_url,
get_passthrough_www_authenticate,
get_request_base_url,
get_route_relative_request_path,
well_known_root_suffix,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.bridge_credentials import (
BridgeEnvelopeAdmitted,
BridgeEnvelopeInvalid,
NotBridgeEnvelope,
envelope_keys_from_master_key,
is_bridge_envelope_shaped,
resolve_bridge_envelope,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.envelope import (
EnvelopeIdentity,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.session_credentials import (
is_session_bearer_shaped,
)
from litellm.proxy._experimental.mcp_server.utils import (
asgi_scope_fields,
strip_known_server_prefix,
)
from litellm.mcp_client.client import strip_auth_scheme
from litellm.proxy._types import (
UI_TEAM_ID,
LiteLLM_AccessGroupTable,
@ -87,6 +61,32 @@ from litellm.proxy.common_utils.user_api_key_cache import (
get_management_object_ttl,
user_object_permission_id_cache_key,
)
from litellm.proxy.mcp_server.catalog import global_manager
from litellm.proxy.mcp_server.oauth_utils import (
get_passthrough_resource_metadata_url,
get_passthrough_www_authenticate,
get_request_base_url,
get_route_relative_request_path,
well_known_root_suffix,
)
from litellm.proxy.mcp_server.outbound_credentials.bridge_credentials import (
BridgeEnvelopeAdmitted,
BridgeEnvelopeInvalid,
NotBridgeEnvelope,
envelope_keys_from_master_key,
is_bridge_envelope_shaped,
resolve_bridge_envelope,
)
from litellm.proxy.mcp_server.outbound_credentials.envelope import (
EnvelopeIdentity,
)
from litellm.proxy.mcp_server.outbound_credentials.session_credentials import (
is_session_bearer_shaped,
)
from litellm.proxy.mcp_server.utils import (
asgi_scope_fields,
strip_known_server_prefix,
)
from litellm.repositories.table_repositories import (
AgentsRepository,
MCPServerRepository,
@ -201,7 +201,7 @@ def _is_mcp_passthrough_cold_start(mcp_servers: list[str] | None, client_ip: str
cannot be resolved."""
if not mcp_servers:
return False
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -216,7 +216,7 @@ def _is_legacy_delegate_cold_start(mcp_servers: list[str] | None, client_ip: str
"""Allow only credential-free legacy delegates to reach the route's OAuth challenge."""
if not mcp_servers:
return False
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
MCPServerManager,
global_mcp_server_manager,
)
@ -308,7 +308,7 @@ def _gateway_dcr_challenge_target(
client_ip: str | None,
) -> str | None:
"""Resolve a single path target whose sign-in metadata advertises the gateway."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -328,8 +328,8 @@ def gateway_dcr_challenge_scope(
) -> str | None:
if MCPRequestHandler.extract_target_server_names_from_path(route) or not mcp_servers:
return None
from litellm.proxy._experimental.mcp_server.gateway_dcr_flow import gateway_server_scope
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.gateway_dcr_flow import gateway_server_scope
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -919,7 +919,7 @@ class MCPRequestHandler:
transparent proxy and the caller's ``Authorization`` is an upstream token, never a LiteLLM key.
A mixed-target request keeps normal auth.
"""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.types.mcp import MCPAuth
@ -946,7 +946,7 @@ class MCPRequestHandler:
envelope admission arm never fires for an aggregate scope or a server that did not
opt into the bridge. Mirrors :meth:`_target_servers_are_true_passthrough`.
"""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -1163,7 +1163,7 @@ class MCPRequestHandler:
mint-time snapshot. Pre-DB gates (size, IP, route allowlist) run first, mirroring the standard
pipeline. Fails closed with the requested scope's ``invalid_token`` challenge on an expired,
tampered, foreign, or refresh token, or a missing/deactivated/policy-rejected user."""
from litellm.proxy._experimental.mcp_server.outbound_credentials.session_credentials import (
from litellm.proxy.mcp_server.outbound_credentials.session_credentials import (
NotSessionBearer,
SessionBearerAdmitted,
SessionBearerInvalid,
@ -1332,7 +1332,7 @@ class MCPRequestHandler:
so each is resolved to an id via ``expand_permission_list`` before the membership check. Returns
None (no descriptors) when nothing applies; a lookup failure narrows to None rather than raising,
since rate limiting must not deny a request authorization already allowed."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -1394,7 +1394,7 @@ class MCPRequestHandler:
else:
return refreshed
if refreshed.mcp_toolset_id is not None:
from litellm.proxy._experimental.mcp_server.server import apply_toolset_scope
from litellm.proxy.mcp_server.server import apply_toolset_scope
return await apply_toolset_scope(refreshed, refreshed.mcp_toolset_id)
return refreshed
@ -1416,10 +1416,10 @@ class MCPRequestHandler:
project, org, and budget state are NOT re-checked here; the caller runs the admitted
identity through ``_enforce_admitted_live_policy`` for those.
"""
from litellm.proxy._experimental.mcp_server.bridge_token_flow import (
from litellm.proxy.auth.auth_checks import get_key_object
from litellm.proxy.mcp_server.bridge_token_flow import (
master_key_admin_auth, # noqa: PLC0415 # inline import avoids a module-load circular import
)
from litellm.proxy.auth.auth_checks import get_key_object
from litellm.proxy.proxy_server import prisma_client, user_api_key_cache
admin: Final = master_key_admin_auth(key_hash)
@ -1661,7 +1661,7 @@ class MCPRequestHandler:
@staticmethod
def get_guardrail_bearer_token(headers: Headers, auth: UserAPIKeyAuth) -> SecretStr | None:
from litellm.proxy._experimental.mcp_server.utils import (
from litellm.proxy.mcp_server.utils import (
_custom_litellm_key_header_name, # pyright: ignore[reportPrivateUsage] # reuse the shared credential-header setting
)
@ -1884,7 +1884,7 @@ class MCPRequestHandler:
from litellm.proxy.proxy_server import general_settings
if managed_agent_policy(user_api_key_auth) is not None:
from litellm.proxy._experimental.mcp_server.auth.managed_agent_access import managed_agent_servers
from litellm.proxy.mcp_server.auth.managed_agent_access import managed_agent_servers
return MCPServerAccess(server_ids=await managed_agent_servers(user_api_key_auth), scope="scoped")
@ -2257,7 +2257,7 @@ class MCPRequestHandler:
intersected with it, so the route narrows a team grant exactly as it narrows the user's own."""
if auth.mcp_toolset_id is None:
return None
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -2308,8 +2308,8 @@ class MCPRequestHandler:
if not is_mcp_admitted_user_subject(auth) and not personal_key_inherits_team_grants(auth):
return auth
try:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy._experimental.mcp_server.operations import (
from litellm.proxy.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy.mcp_server.operations import (
_get_allowed_mcp_servers,
_resolve_display_name_to_original,
resolve_scoped_mcp_server,
@ -2473,7 +2473,7 @@ class MCPRequestHandler:
onto a server reached through a different source. A source that grants the server with no
tool restriction means the user can use every tool on it, so allow-all wins the union. When
no source grants the server the result is ``[]`` — deny all, fail closed."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -2620,8 +2620,8 @@ class MCPRequestHandler:
async def personal_key_team_rpm_limits(
auth: UserAPIKeyAuth, server: MCPServer, tool_name: str
) -> Mapping[str, Mapping[str, int]] | None:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy.auth.auth_checks import get_team_object
from litellm.proxy.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy.proxy_server import prisma_client, proxy_logging_obj, user_api_key_cache
try:
@ -2672,7 +2672,7 @@ class MCPRequestHandler:
then carries the key's OWN tool rules, never a team's; otherwise nothing is allowed. Each team
resolves through the raising ``_single_credential_tools`` so one team's fault reaches the
caller's fail-closed handler instead of becoming an allow-all ``None`` in the union."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -2773,7 +2773,7 @@ class MCPRequestHandler:
nothing (deleted or unknown ids, a swallowed DB fault, or a toolset with no tools): that is a
KNOWN restriction with unknown contents, and every caller already turns this error into deny
rather than letting the level read as unrestricted."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -2827,7 +2827,7 @@ class MCPRequestHandler:
``mcp_tool_permissions`` entry for it. A granting group with no entry grants every tool, so
``None`` wins. A group that does not grant the server contributes nothing, and an explicit
``[]`` entry on a granting group grants no tools. ``None`` when no group grants the server."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -2848,7 +2848,7 @@ class MCPRequestHandler:
@staticmethod
def _group_grants_server(group: LiteLLM_AccessGroupTable, server_id: str) -> bool:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -2892,7 +2892,7 @@ class MCPRequestHandler:
"""Servers the key's object permission grants on its own: ``mcp_servers`` by id, name or alias and
legacy ``mcp_access_groups`` by the tag the server carries, exactly as server admission resolves
them. A tag never doubles as a server name, so a tag that collides with one grants nothing by itself."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy.mcp_server.mcp_server_manager import global_mcp_server_manager
if key_obj_perm is None:
return frozenset()
@ -3054,7 +3054,7 @@ class MCPRequestHandler:
return None
if managed_agent_policy(user_api_key_auth) is not None:
from litellm.proxy._experimental.mcp_server.auth.managed_agent_access import managed_agent_tools
from litellm.proxy.mcp_server.auth.managed_agent_access import managed_agent_tools
return await managed_agent_tools(server_id, user_api_key_auth)
@ -3111,7 +3111,7 @@ class MCPRequestHandler:
# server_ids OR names/aliases; normalize to server_id-keyed form
# before lookup so a name-based key does not silently drop its
# tool restrictions when server_id is the resolved uuid.
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -3203,7 +3203,7 @@ class MCPRequestHandler:
fail-open (skip the org step, keep the key/team/agent restrictions; letting the raise escape
would collapse them to allow-all, WIDER than before the fault), while a keyless source re-raises
so the outer handler denies that one source (its only org bound is this ceiling)."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -3317,12 +3317,12 @@ class MCPRequestHandler:
if user_api_key_auth is None:
return []
try:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.proxy.auth.auth_checks import (
get_mcp_server_ids_from_access_groups,
)
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.proxy.proxy_server import (
prisma_client,
proxy_logging_obj,
@ -3374,12 +3374,12 @@ class MCPRequestHandler:
if user_api_key_auth is None:
return []
try:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.proxy.auth.auth_checks import (
get_object_permission,
)
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.proxy.proxy_server import (
prisma_client,
proxy_logging_obj,
@ -3538,7 +3538,7 @@ class MCPRequestHandler:
``mcp_servers``, the ``all_proxy_servers`` sentinel → the full registry, legacy access groups,
tool-perm-referenced servers, toolset-referenced servers) unioned with its unified
``access_group_ids`` servers."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -3750,7 +3750,7 @@ class MCPRequestHandler:
if object_permissions is None:
return []
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -3855,7 +3855,7 @@ class MCPRequestHandler:
try:
# Permission entries may be server_ids OR names/aliases — expand to ids.
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -3990,7 +3990,7 @@ class MCPRequestHandler:
``mcp_tool_permissions`` or reached through ``mcp_toolsets`` count as entitled, exactly as
they do for a key or a team, so granting one tool never requires naming its server twice.
"""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -4130,7 +4130,7 @@ class MCPRequestHandler:
restriction. Returns ``[]`` (deny every tool on this server) when the entitlement cannot be
resolved, because the caller's own except-handler treats a raise as allow-all for key auth.
"""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -4173,7 +4173,7 @@ class MCPRequestHandler:
axis twin of ``apply_agent_caller_ceiling``, so the headers only ever narrow. Denies every tool
on the server when the caller's team cannot be loaded, since a caller we cannot resolve must not
read as unrestricted."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -4217,7 +4217,7 @@ class MCPRequestHandler:
user_api_key_auth: UserAPIKeyAuth | None = None,
) -> Sequence[str] | None:
"""Narrow a key/team tool allowlist by the end user's (customer's) tool entitlement."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
from litellm.proxy.proxy_server import prisma_client
@ -4353,7 +4353,7 @@ class MCPRequestHandler:
return []
try:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -4390,7 +4390,7 @@ class MCPRequestHandler:
allow, or None when the agent has none attached. Unlike the object_permission path above, an
attached group set that names no servers is an empty ceiling and denies every server.
"""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -4469,7 +4469,7 @@ class MCPRequestHandler:
)
try:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -4545,7 +4545,7 @@ class MCPRequestHandler:
try:
# Import here to avoid circular import
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)

View file

@ -13,24 +13,24 @@ from pydantic import SecretStr
from typing_extensions import assert_never
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.oauth_utils import TOKEN_NO_CACHE_HEADERS
from litellm.proxy.common_utils.encrypt_decrypt_utils import ( # noqa: F401 # legacy module exports
_V2_GCM_PREFIX, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
V2_GCM_PREFIX, # pyright: ignore[reportPrivateUsage] # reuse the encrypted credential's format discriminator
)
from litellm.proxy.mcp_server.oauth_utils import TOKEN_NO_CACHE_HEADERS
from litellm.types.mcp_server.mcp_server_manager import MCPServer
if TYPE_CHECKING:
from litellm.models.user import LiteLLM_UserTable
from litellm.proxy._experimental.mcp_server.discoverable_endpoints import _BridgeAuthorizationCode
from litellm.proxy._experimental.mcp_server.outbound_credentials.envelope import (
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.auth.handle_jwt import JWTIdentity
from litellm.proxy.mcp_server.discoverable_endpoints import _BridgeAuthorizationCode
from litellm.proxy.mcp_server.outbound_credentials.envelope import (
EnvelopeIdentity,
EnvelopeKeys,
RefreshCredential,
UpstreamTokenGrant,
)
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.auth.handle_jwt import JWTIdentity
def _litellm_key_from_request(request: Request) -> str | None:
@ -87,14 +87,14 @@ async def oauth_authorization_uses_gateway_credential(request: Request) -> bool:
async def _opaque_bearer_is_gateway_credential(token: str) -> bool:
from litellm.proxy._experimental.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # envelope imports bridge types
is_envelope,
is_refresh_envelope,
)
from litellm.proxy._types import hash_token # noqa: PLC0415 # proxy import cycle
from litellm.proxy.auth.auth_checks import ExperimentalUIJWTToken # noqa: PLC0415 # proxy import cycle
from litellm.proxy.auth.resolvers.exceptions import KeyNotFoundError # noqa: PLC0415 # proxy import cycle
from litellm.proxy.auth.resolvers.store import IdentityStore # noqa: PLC0415 # proxy import cycle
from litellm.proxy.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # envelope imports bridge types
is_envelope,
is_refresh_envelope,
)
from litellm.proxy.proxy_server import ( # noqa: PLC0415 # startup owns the identity store dependencies
prisma_client,
user_api_key_cache,
@ -447,16 +447,16 @@ async def _resolve_request_auth(
async def can_store_oauth_credential(request: Request, auth: "UserAPIKeyAuth", server_id: str) -> bool:
"""Apply the same write policy to request credentials and verified signed-callback users."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # registry imports auth helpers
global_mcp_server_manager,
)
from litellm.proxy._experimental.mcp_server.ui_session_utils import (
can_access_mcp_server, # noqa: PLC0415 # proxy import cycle
)
from litellm.proxy.auth.route_checks import RouteChecks # noqa: PLC0415 # proxy import cycle
from litellm.proxy.auth.user_api_key_auth import ( # noqa: PLC0415 # proxy import cycle
run_centralized_common_checks, # pyright: ignore[reportPrivateUsage] # reuse admission policy for the credential-write action
)
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # registry imports auth helpers
global_mcp_server_manager,
)
from litellm.proxy.mcp_server.ui_session_utils import (
can_access_mcp_server, # noqa: PLC0415 # proxy import cycle
)
write_route: Final = f"/v1/mcp/server/{server_id}/oauth-user-credential"
try:
@ -584,7 +584,7 @@ def _bridge_grant_from_token_response(token_response: object) -> "UpstreamTokenG
lifetime leaves the grant ``expires_in`` ``None`` for the envelope fallback, a positive value is
honoured, and an explicit already-elapsed value is a rejection rather than a silent fall-through to
the cap."""
from litellm.proxy._experimental.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
UpstreamTokenGrant,
)
@ -790,18 +790,18 @@ async def prepare_bridge_mint(
presented key keeps its resolution origin so the mapper statuses it truthfully; neither source
present is ``no_identity``. The refresh_token grant has its own phase-1
(:func:`_prepare_bridge_refresh`), which recovers identity from the presented refresh envelope."""
from litellm.proxy._experimental.mcp_server.client_allowlist import ( # noqa: PLC0415 # keep mint policy dependencies local
from litellm.proxy._types import UserAPIKeyAuth # noqa: PLC0415 # proxy import cycle
from litellm.proxy.auth.handle_jwt import JWTHandler # noqa: PLC0415 # proxy import cycle
from litellm.proxy.mcp_server.client_allowlist import ( # noqa: PLC0415 # keep mint policy dependencies local
load_mcp_client_allowlist,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.bridge_credentials import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.outbound_credentials.bridge_credentials import ( # noqa: PLC0415 # inline import avoids a module-load circular import
envelope_keys_from_master_key,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
key_hash_identity,
user_identity,
)
from litellm.proxy._types import UserAPIKeyAuth # noqa: PLC0415 # proxy import cycle
from litellm.proxy.auth.handle_jwt import JWTHandler # noqa: PLC0415 # proxy import cycle
from litellm.proxy.proxy_server import ( # noqa: PLC0415 # inline import avoids a module-load circular import
general_settings,
master_key,
@ -877,7 +877,7 @@ async def prepare_bridge_refresh(
never a raw upstream refresh token, so a missing value, a non-envelope, an unopenable envelope, or one
minted for another server is ``invalid_grant``. Running before the exchange means a rejected refresh
never consumes or rotates the upstream refresh token."""
from litellm.proxy._experimental.mcp_server.outbound_credentials.bridge_credentials import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.outbound_credentials.bridge_credentials import ( # noqa: PLC0415 # inline import avoids a module-load circular import
BridgeRefreshOpened,
envelope_keys_from_master_key,
open_bridge_refresh_envelope,
@ -917,10 +917,10 @@ def finish_bridge_mint(
fresh refresh envelope. The only hard failures here are properties of the upstream access token (no
usable token, an already-expired lifetime, or a token too large to seal); a refresh token that cannot
be sealed degrades to an access-only response rather than failing the whole exchange."""
from litellm.proxy._experimental.mcp_server.outbound_credentials.bridge_credentials import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.outbound_credentials.bridge_credentials import ( # noqa: PLC0415 # inline import avoids a module-load circular import
build_bridge_token_response,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
EnvelopeLifetimeUnrepresentable,
SealedEnvelope,
UpstreamTokenGrant,
@ -961,7 +961,7 @@ def _upstream_refresh_credential(token_response: object) -> "RefreshCredential |
token would hand the client a full-TTL-capped envelope the IdP will reject, so the exchange degrades to
an access-only response (the client re-authenticates at access expiry), mirroring how
:func:`_bridge_grant_from_token_response` refuses an already-elapsed access token instead of capping it."""
from litellm.proxy._experimental.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
RefreshCredential,
)
@ -988,10 +988,10 @@ def _mint_refresh_envelope_value(
``None`` when the upstream returned no refresh token or the refresh token is too large to seal. A
too-large refresh token degrades to an access-only response (logged) rather than failing an exchange
that already succeeded upstream: the client simply re-authenticates when the access envelope expires."""
from litellm.proxy._experimental.mcp_server.outbound_credentials.bridge_credentials import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.outbound_credentials.bridge_credentials import ( # noqa: PLC0415 # inline import avoids a module-load circular import
build_bridge_refresh_token_response,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.outbound_credentials.envelope import ( # noqa: PLC0415 # inline import avoids a module-load circular import
SealedEnvelope,
)

View file

@ -25,16 +25,16 @@ from fastapi import APIRouter, Depends, Form, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
from litellm._logging import verbose_proxy_logger
from litellm.proxy._experimental.mcp_server.catalog import public_catalog_operation
from litellm.proxy._experimental.mcp_server.db import store_user_credential
from litellm.proxy._experimental.mcp_server.oauth_utils import (
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.mcp_server.catalog import public_catalog_operation
from litellm.proxy.mcp_server.db import store_user_credential
from litellm.proxy.mcp_server.oauth_utils import (
BYOK_RESOURCE_METADATA_PATH,
TOKEN_NO_CACHE_HEADERS,
get_request_base_url,
validate_loopback_redirect_uri,
well_known_root_suffix,
)
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.middleware.per_request_root_path_middleware import get_server_root_paths
# ---------------------------------------------------------------------------
@ -779,7 +779,7 @@ async def byok_authorize_get(
help_url = ""
if server_id:
try:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -955,7 +955,7 @@ async def byok_token(
)
# Invalidate any cached negative result so the user isn't blocked
# for up to the TTL period after completing the OAuth flow.
from litellm.proxy._experimental.mcp_server.server import (
from litellm.proxy.mcp_server.server import (
_invalidate_byok_cred_cache,
)

View file

@ -23,15 +23,15 @@ from pydantic import BaseModel, ConfigDict, JsonValue, TypeAdapter
from litellm._logging import verbose_logger
from litellm.caching.in_memory_cache import InMemoryCache
from litellm.proxy._experimental.mcp_server.result_conversion import age_freshness, aggregate_freshness
from litellm.proxy.mcp_server.result_conversion import age_freshness, aggregate_freshness
if TYPE_CHECKING:
from mcp.types import ListToolsResult, PaginatedRequestParams, PaginatedResult
from litellm.proxy._experimental.mcp_server.contracts import CatalogListRequest, CatalogListResult, OperationContext
from litellm.proxy._experimental.mcp_server.db import OAuthCredentialPayload
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import AggregateToolListing, ServerOutcome
from litellm.proxy._experimental.mcp_server.mcp_server_manager import MCPServerManager
from litellm.proxy.mcp_server.contracts import CatalogListRequest, CatalogListResult, OperationContext
from litellm.proxy.mcp_server.db import OAuthCredentialPayload
from litellm.proxy.mcp_server.faults.list_outcomes import AggregateToolListing, ServerOutcome
from litellm.proxy.mcp_server.mcp_server_manager import MCPServerManager
from litellm.types.mcp_server.mcp_server_manager import MCPServer
from litellm.types.mcp_server.tool_registry import MCPTool
@ -90,7 +90,7 @@ def _check_oauth_revision(selected: MCPServer, candidate: MCPServer | None) -> N
def _snapshot(manager: MCPServerManager, database_identity: str) -> CatalogSnapshot:
from litellm.proxy._experimental.mcp_server.tool_registry import global_mcp_tool_registry
from litellm.proxy.mcp_server.tool_registry import global_mcp_tool_registry
servers: Final = manager.config_mcp_servers | manager.registry
detached: Final = MappingProxyType({key: value.model_copy(deep=True) for key, value in servers.items()})
@ -154,7 +154,7 @@ class CatalogSnapshots:
if not should_load_db_object("mcp"):
return _snapshot(self.manager, self._database_identity)
from litellm.proxy._experimental.mcp_server.db import get_mcp_catalog_revision
from litellm.proxy.mcp_server.db import get_mcp_catalog_revision
try:
revision: Final = await get_mcp_catalog_revision(prisma_client)
@ -198,7 +198,7 @@ class CatalogSnapshots:
if current is not None:
yield current
return
from litellm.proxy._experimental.mcp_server.tool_registry import global_mcp_tool_registry
from litellm.proxy.mcp_server.tool_registry import global_mcp_tool_registry
shared: Final = await self._fresh_snapshot()
initial_routing: Final = self._unchanged_routing(shared.servers, self.manager.published_tool_routes)
@ -227,7 +227,7 @@ class CatalogSnapshots:
def _unchanged_routing(
self, servers: Mapping[str, MCPServer], routing: Mapping[str, str]
) -> MappingProxyType[str, str]:
from litellm.proxy._experimental.mcp_server.utils import normalize_server_name
from litellm.proxy.mcp_server.utils import normalize_server_name
current: Final = self.manager.config_mcp_servers | self.manager.registry
unchanged: Final = (
@ -252,7 +252,7 @@ class CatalogSnapshots:
server: MCPServer,
resolve: Callable[[MCPServer], Awaitable[MCPServer]],
) -> MCPServer:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import oauth_endpoints_unresolved
from litellm.proxy.mcp_server.mcp_server_manager import oauth_endpoints_unresolved
snapshot: Final = self.current()
selected: Final = snapshot.servers.get(server.server_id) if snapshot is not None else None
@ -270,7 +270,7 @@ class CatalogSnapshots:
return resolved
async def reload(self) -> None:
from litellm.proxy._experimental.mcp_server.db import get_mcp_catalog_revision
from litellm.proxy.mcp_server.db import get_mcp_catalog_revision
from litellm.proxy.proxy_server import prisma_client
revision: Final = await get_mcp_catalog_revision(prisma_client) if prisma_client is not None else None
@ -294,8 +294,8 @@ class CatalogSnapshots:
self._operation.reset(token)
async def _reload_and_publish(self, *, reuse_unchanged: bool) -> None:
from litellm.proxy._experimental.mcp_server.tool_registry import global_mcp_tool_registry
from litellm.proxy._experimental.mcp_server.utils import normalize_server_name
from litellm.proxy.mcp_server.tool_registry import global_mcp_tool_registry
from litellm.proxy.mcp_server.utils import normalize_server_name
previous_config: Final = MappingProxyType(
{key: value.model_copy(deep=True) for key, value in self.manager.config_mcp_servers.items()}
@ -399,8 +399,8 @@ class CatalogSnapshots:
async def _stage_servers(
self, rows: Sequence[BaseModel], *, reuse_unchanged: bool
) -> dict[str, MCPServer]: # mutable-ok: assign_unique_short_prefix requires a dict registry
from litellm.proxy._experimental.mcp_server.db import LiteLLM_MCPServerTable
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.db import LiteLLM_MCPServerTable
from litellm.proxy.mcp_server.mcp_server_manager import (
carry_forward_resolved_oauth_endpoints,
oauth_endpoints_unresolved,
warn_on_server_name_fields,
@ -464,20 +464,20 @@ class CatalogSnapshots:
return new_registry
async def _reload(self, *, reuse_unchanged: bool) -> None:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
config_ids_capturing_db_identifiers,
warn_on_shared_identifier_prefixes,
)
from litellm.proxy.management_endpoints.mcp_management_endpoints import (
get_prisma_client_or_throw,
)
from litellm.proxy.mcp_server.mcp_server_manager import (
config_ids_capturing_db_identifiers,
warn_on_shared_identifier_prefixes,
)
verbose_logger.debug("Loading MCP servers from database into registry...")
prisma_client: Final = get_prisma_client_or_throw("Database not connected. Connect a database to your proxy")
# Load only "active", legacy "approved", and NULL (no approval workflow) rows.
# Pending/rejected servers are excluded at the DB level so we never load them.
from litellm.proxy._experimental.mcp_server.db import get_runtime_mcp_server_rows
from litellm.proxy.mcp_server.db import get_runtime_mcp_server_rows
raw_rows: Final[Sequence[BaseModel]] = await get_runtime_mcp_server_rows(prisma_client)
database_identity: Final = hashlib.sha256(
@ -584,7 +584,7 @@ def catalog_operation(
def global_manager() -> MCPServerManager:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy.mcp_server.mcp_server_manager import global_mcp_server_manager
return global_mcp_server_manager
@ -608,8 +608,8 @@ async def paginate_catalog(
from pydantic import ValidationError
from litellm.constants import MCP_TOOL_LISTING_MAX_PAGES
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import Error
from litellm.proxy._experimental.mcp_server.state_tokens import open_state, seal_state
from litellm.proxy.mcp_server.outbound_credentials.result import Error
from litellm.proxy.mcp_server.state_tokens import open_state, seal_state
ordered: Final = tuple(sorted(server_ids))
purpose: Final = "mcp.catalog.list.v1:" + method
@ -673,7 +673,7 @@ async def paginate_catalog(
for task in tasks:
task.cancel()
await asyncio.gather(*tasks, return_exceptions=True)
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import SERVER_OUTCOMES_META_KEY
from litellm.proxy.mcp_server.faults.list_outcomes import SERVER_OUTCOMES_META_KEY
elapsed: Final = time.monotonic() - started
pages: Final = tuple(
@ -719,7 +719,7 @@ async def list_tools_page(
) -> ListToolsResult:
from mcp.types import ListToolsResult
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import SERVER_OUTCOMES_META_KEY
from litellm.proxy.mcp_server.faults.list_outcomes import SERVER_OUTCOMES_META_KEY
pages, next_cursor, outcomes = await paginate_catalog(
method="tools/list",
@ -773,9 +773,9 @@ async def get_filtered_server_tools(
) -> tuple[ListToolsResult, ServerOutcome]:
from mcp.types import ListToolsResult
from litellm.proxy._experimental.mcp_server.exceptions import MCPUpstreamAuthError
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import ServerListOk, classify_list_exception
from litellm.proxy._experimental.mcp_server.operations import (
from litellm.proxy.mcp_server.exceptions import MCPUpstreamAuthError
from litellm.proxy.mcp_server.faults.list_outcomes import ServerListOk, classify_list_exception
from litellm.proxy.mcp_server.operations import (
_get_byok_credential,
_get_user_oauth_extra_headers_from_db,
_prepare_mcp_server_headers,
@ -806,7 +806,7 @@ async def get_filtered_server_tools(
# Prefer server-stored per-user OAuth when configured, so a stale
# Authorization header from the MCP client cannot override Redis/DB
# (same issue as call_tool in mcp_server_manager: VS Code caches tokens).
from litellm.proxy._experimental.mcp_server.outbound_credentials.adapter import ( # noqa: PLC0415
from litellm.proxy.mcp_server.outbound_credentials.adapter import ( # noqa: PLC0415
to_server_spec,
)
@ -885,8 +885,8 @@ async def get_filtered_server_tools(
user_api_key_auth=user_api_key_auth,
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ListedToolsCaller
from litellm.proxy._experimental.mcp_server.utils import strip_known_server_prefix
from litellm.proxy.mcp_server.mcp_server_manager import ListedToolsCaller
from litellm.proxy.mcp_server.utils import strip_known_server_prefix
record: Final = partial(
global_mcp_server_manager.record_listed_tools,
@ -908,7 +908,7 @@ async def get_filtered_server_tools(
listing_updates.callback(record)
if mcp_proxy_mode:
from litellm.proxy._experimental.mcp_server.tool_search import with_mcp_proxy_identity
from litellm.proxy.mcp_server.tool_search import with_mcp_proxy_identity
filtered_tools = [with_mcp_proxy_identity(tool, server.server_id) for tool in filtered_tools]
else:
@ -936,7 +936,7 @@ async def get_filtered_server_tools(
def _caller_scope(context: OperationContext, servers: Sequence[MCPServer]) -> str:
from litellm.proxy._experimental.mcp_server.utils import upstream_credential_headers
from litellm.proxy.mcp_server.utils import upstream_credential_headers
caller: Final = context.user_api_key_auth
headers: Final = context.raw_headers or {}
@ -975,18 +975,18 @@ async def aggregate_gateway_tools(
from mcp.types import ListToolsResult, PaginatedRequestParams
from pydantic import TypeAdapter
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import (
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
from litellm.proxy.mcp_server.faults.list_outcomes import (
SERVER_OUTCOMES_META_KEY,
AggregateToolListing,
ServerOutcome,
classify_list_exception,
)
from litellm.proxy._experimental.mcp_server.operations import (
from litellm.proxy.mcp_server.operations import (
_aggregate_server_key,
_mcp_server_rate_limit_rejection,
global_mcp_server_manager,
)
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
async with global_mcp_server_manager.catalog.operation() as snapshot:
servers: Final = {server.server_id: server for server in allowed}
@ -1065,12 +1065,12 @@ async def list_gateway_tools(
) -> ListToolsResult:
from mcp.types import INTERNAL_ERROR, ListToolsResult
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import (
from litellm.proxy.mcp_server.faults.list_outcomes import (
SERVER_OUTCOMES_META_KEY,
listing_failed_outright,
outcome_wire_value,
)
from litellm.proxy._experimental.mcp_server.operations import _list_mcp_tools
from litellm.proxy.mcp_server.operations import _list_mcp_tools
caller, auth, servers, server_headers, oauth_headers, headers, client_ip = context.legacy_auth()
listing: Final = await _list_mcp_tools(
@ -1115,13 +1115,13 @@ async def list_gateway_catalog(
PaginatedRequestParams,
)
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
from litellm.proxy._experimental.mcp_server.operations import (
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
from litellm.proxy.mcp_server.operations import (
_get_allowed_mcp_servers,
global_mcp_server_manager,
raise_denied_scoped_mcp_access,
)
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
context = replace(context, _caller=await MCPRequestHandler.refresh_catalog_authority(context.user_api_key_auth))
params: Final = request.params or PaginatedRequestParams()
@ -1146,11 +1146,11 @@ async def list_gateway_catalog(
from mcp.shared.exceptions import MCPError
from mcp.types import INVALID_PARAMS
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import (
from litellm.proxy.mcp_server.faults.list_outcomes import (
SERVER_OUTCOMES_META_KEY,
classify_list_exception,
)
from litellm.proxy._experimental.mcp_server.operations import (
from litellm.proxy.mcp_server.operations import (
_aggregate_server_key,
_mcp_server_rate_limit_rejection,
)
@ -1204,7 +1204,7 @@ async def list_gateway_catalog(
)
if params.cursor is None and servers and len(rejections) == len(servers):
raise rejections[0]
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import (
from litellm.proxy.mcp_server.faults.list_outcomes import (
SERVER_OUTCOMES_META_KEY,
ServerOutcome,
outcome_wire_value,
@ -1232,7 +1232,7 @@ async def fetch_optional_catalog_page(
) -> CatalogListResult:
from mcp.types import PaginatedRequestParams
from litellm.proxy._experimental.mcp_server.operations import _prepare_mcp_server_headers, global_mcp_server_manager
from litellm.proxy.mcp_server.operations import _prepare_mcp_server_headers, global_mcp_server_manager
caller, auth, _, server_headers, oauth_headers, raw_headers, client_ip = context.legacy_auth()
auth_header, extra_headers = _prepare_mcp_server_headers(
@ -1269,7 +1269,7 @@ def combine_optional_catalog(
ListResourceTemplatesResult,
)
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import SERVER_OUTCOMES_META_KEY
from litellm.proxy.mcp_server.faults.list_outcomes import SERVER_OUTCOMES_META_KEY
outcomes: Final = (meta or {}).get(SERVER_OUTCOMES_META_KEY)
incomplete: Final = isinstance(outcomes, dict) and any(

View file

@ -10,8 +10,8 @@ from typing import TYPE_CHECKING, Final, Literal, Protocol, TypeAlias
from mcp.types import ErrorData, InputRequest, InputResponse, InputResponses
from pydantic import SecretStr
from litellm.proxy._experimental.mcp_server.tool_outcome import WireCompat
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.mcp_server.tool_outcome import WireCompat
from litellm.types.mcp_server.mcp_server_manager import MCPServer
if TYPE_CHECKING:
@ -33,7 +33,7 @@ if TYPE_CHECKING:
ListToolsResult | ListPromptsResult | ListResourcesResult | ListResourceTemplatesResult
)
from litellm.proxy._experimental.mcp_server.server_resolution import ResolvedMCPServer
from litellm.proxy.mcp_server.server_resolution import ResolvedMCPServer
class TargetCatalog(Protocol):

View file

@ -15,14 +15,6 @@ from litellm._logging import verbose_proxy_logger
from litellm._uuid import uuid
from litellm.constants import MCP_PER_USER_TOKEN_EXPIRY_BUFFER_SECONDS
from litellm.llms.custom_httpx.http_handler import get_async_httpx_client
from litellm.proxy._experimental.mcp_server.oauth_identity_binding import (
RefreshTokenPresented,
credential_binding_matches,
enforce_oauth_identity_binding,
)
from litellm.proxy._experimental.mcp_server.oauth_utils import (
build_upstream_oauth2_token_request,
)
from litellm.proxy._types import (
LiteLLM_MCPServerTable,
MCPApprovalStatus,
@ -42,6 +34,14 @@ from litellm.proxy.common_utils.encrypt_decrypt_utils import ( # noqa: F401 #
encrypt_value_helper,
get_salt_key,
)
from litellm.proxy.mcp_server.oauth_identity_binding import (
RefreshTokenPresented,
credential_binding_matches,
enforce_oauth_identity_binding,
)
from litellm.proxy.mcp_server.oauth_utils import (
build_upstream_oauth2_token_request,
)
from litellm.proxy.utils import PrismaClient
from litellm.repositories.config_repository import ConfigRepository
from litellm.repositories.object_permission_repository import ObjectPermissionRepository
@ -1066,7 +1066,7 @@ async def delete_mcp_server(
)
if credential_user_ids:
if invalidate_token_cache is None:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -2031,7 +2031,7 @@ async def purge_user_oauth_credentials_for_server(
where={"server_id": server_id, "user_id": {"in": [row.user_id for row in oauth_rows]}}
)
if invalidate_token_cache is None:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -2238,7 +2238,7 @@ async def resolve_user_oauth_access_token(
if not user_id or not server_id:
return None
try:
from litellm.proxy._experimental.mcp_server.oauth2_token_cache import (
from litellm.proxy.mcp_server.oauth2_token_cache import (
compute_per_user_token_ttl,
mcp_per_user_token_cache,
)

View file

@ -22,11 +22,21 @@ from litellm.llms.custom_httpx.http_handler import (
get_async_httpx_client,
httpxSpecialProvider,
)
from litellm.proxy._experimental.mcp_server.auth.token_endpoint_auth import (
from litellm.proxy.auth.ip_address_utils import IPAddressUtils
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
from litellm.proxy.common_utils.encrypt_decrypt_utils import (
decrypt_value_helper,
encrypt_value_helper,
)
from litellm.proxy.common_utils.http_parsing_utils import ( # noqa: F401 # legacy module exports
_read_request_body, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
read_request_body,
)
from litellm.proxy.mcp_server.auth.token_endpoint_auth import (
TokenEndpointAuthConfigError,
normalize_token_endpoint_auth_method,
)
from litellm.proxy._experimental.mcp_server.bridge_token_flow import ( # noqa: F401 # legacy module exports
from litellm.proxy.mcp_server.bridge_token_flow import ( # noqa: F401 # legacy module exports
_bridge_mint_error_response, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
_BridgeMintReady,
_BridgeRefreshReady,
@ -45,8 +55,8 @@ from litellm.proxy._experimental.mcp_server.bridge_token_flow import ( # noqa:
prepare_bridge_refresh,
reload_active_user_by_id,
)
from litellm.proxy._experimental.mcp_server.catalog import public_catalog_operation
from litellm.proxy._experimental.mcp_server.faults import (
from litellm.proxy.mcp_server.catalog import public_catalog_operation
from litellm.proxy.mcp_server.faults import (
CallerRejected,
CredentialSource,
UpstreamProtocolFault,
@ -55,7 +65,7 @@ from litellm.proxy._experimental.mcp_server.faults import (
dcr_fault_detail,
render_token_fault,
)
from litellm.proxy._experimental.mcp_server.gateway_dcr_flow import (
from litellm.proxy.mcp_server.gateway_dcr_flow import (
JWT_BEARER_GRANT_TYPE,
VendorCredentialState,
aggregate_authorize,
@ -72,21 +82,21 @@ from litellm.proxy._experimental.mcp_server.gateway_dcr_flow import (
revoke_refresh_token,
supported_grant_types,
)
from litellm.proxy._experimental.mcp_server.id_jag_grant import (
from litellm.proxy.mcp_server.id_jag_grant import (
basic_client_id,
jwt_bearer_available,
redeem_id_jag_assertion,
)
from litellm.proxy._experimental.mcp_server.idp_token_exchange import (
from litellm.proxy.mcp_server.idp_token_exchange import (
exchange_idp_subject_token,
token_exchange_available,
)
from litellm.proxy._experimental.mcp_server.oauth_identity_binding import (
from litellm.proxy.mcp_server.oauth_identity_binding import (
RefreshOwnershipProven,
RefreshTokenPresented,
enforce_oauth_identity_binding,
)
from litellm.proxy._experimental.mcp_server.oauth_utils import (
from litellm.proxy.mcp_server.oauth_utils import (
CIMD_METADATA_PATH,
TOKEN_NO_CACHE_HEADERS,
build_upstream_authorize_url,
@ -101,27 +111,17 @@ from litellm.proxy._experimental.mcp_server.oauth_utils import (
validate_trusted_redirect_uri,
well_known_root_suffix,
)
from litellm.proxy._experimental.mcp_server.proxy_api_credentials import (
from litellm.proxy.mcp_server.proxy_api_credentials import (
lookup_consent_teams,
mint_proxy_credential,
)
from litellm.proxy.auth.ip_address_utils import IPAddressUtils
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
from litellm.proxy.common_utils.encrypt_decrypt_utils import (
decrypt_value_helper,
encrypt_value_helper,
)
from litellm.proxy.common_utils.http_parsing_utils import ( # noqa: F401 # legacy module exports
_read_request_body, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
read_request_body,
)
from litellm.types.llms.base import LiteLLMBaseModel
from litellm.types.mcp import MCPAuth, MCPCredentials
from litellm.types.mcp_server.mcp_server_manager import MCPServer, MCPTokenEndpointAuthMethod
if TYPE_CHECKING:
from litellm.proxy._experimental.mcp_server.db import OAuthCredentialPayload
from litellm.proxy._types import LiteLLM_MCPServerTable
from litellm.proxy.mcp_server.db import OAuthCredentialPayload
# TTL cache for upstream OAuth metadata fetched from pass-through MCP servers.
# Keeps us from hammering the upstream IdP on each discovery request.
@ -476,7 +476,7 @@ async def _session_cookie_user_id(request: Request) -> str | None:
"""The signed-in litellm user for a browser request, or ``None``. Thin wrapper so the
aggregate DCR flow's verbs receive the identity as a plain value instead of parsing
cookies themselves."""
from litellm.proxy._experimental.mcp_server.byok_oauth_endpoints import ( # noqa: PLC0415 # circular import at module load
from litellm.proxy.mcp_server.byok_oauth_endpoints import ( # noqa: PLC0415 # circular import at module load
get_authenticated_browser_user_id,
)
@ -578,7 +578,7 @@ def _append_query_params(url: str, params: dict[str, str]) -> str:
def _resolve_mcp_server_by_name_or_id(lookup: str, client_ip: str | None) -> MCPServer | None:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -598,7 +598,7 @@ def _resolve_oauth2_server_for_root_endpoints(
without a server name prefix, we try to find the right server automatically.
Returns the server if exactly one OAuth2 server is configured, else None.
"""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -684,7 +684,7 @@ async def _store_per_user_token_server_side(
Errors are logged but NOT re-raised — the token is always returned to the
client even when server-side storage fails.
"""
from litellm.proxy._experimental.mcp_server.oauth2_token_cache import ( # noqa: PLC0415
from litellm.proxy.mcp_server.oauth2_token_cache import ( # noqa: PLC0415
compute_per_user_token_ttl,
mcp_per_user_token_cache,
)
@ -706,7 +706,7 @@ async def _store_per_user_token_server_side(
try:
prisma_client: Final = get_prisma_client_or_throw("Database not connected. Cannot store per-user OAuth token.")
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415
store_user_oauth_credential,
)
@ -735,7 +735,7 @@ async def _store_per_user_token_server_side(
)
return # Don't warm Redis if DB write failed
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415
global_mcp_server_manager,
)
@ -762,7 +762,7 @@ def raise_if_not_oauth2(mcp_server: MCPServer) -> None:
modes (``_persist_dcr_client_registration`` skips them unconditionally, so even the admin
Authorize path with ``replace_stale_client`` enabled writes nothing to the server row).
"""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # circular import with mcp_server_manager at module load
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # circular import with mcp_server_manager at module load
UPSTREAM_OAUTH_DISCOVERY_AUTH_TYPES,
)
@ -825,7 +825,7 @@ async def _server_with_oauth_endpoints(
"""
if needed_endpoint(mcp_server) is not None and not needs_cimd_discovery(mcp_server):
return mcp_server
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # circular import with mcp_server_manager at module load
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # circular import with mcp_server_manager at module load
global_mcp_server_manager,
)
@ -972,10 +972,10 @@ def _bridge_access_denied_redirect(redirect_uri: str, state: str, mcp_server: MC
async def _user_can_reach_mcp_server(user_id: str, server_id: str) -> bool:
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import (
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import (
MCPRequestHandler,
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
@ -1013,7 +1013,7 @@ async def _resolve_oauth_authorization_user(
async def _managed_authorization_scope(
request: Request, server: MCPServer, scope: str | None, authorized_user_id: str | None
) -> tuple[str | None, str | None]:
from litellm.proxy._experimental.mcp_server.db import get_user_oauth_credential
from litellm.proxy.mcp_server.db import get_user_oauth_credential
from litellm.proxy.proxy_server import prisma_client
gateway_credential: Final = authorized_user_id is None and await oauth_authorization_uses_gateway_credential(
@ -1214,7 +1214,7 @@ async def _saved_refresh_credential(
if not user_id or not refresh_token or not server.needs_user_oauth_token or server.auth_type != MCPAuth.oauth2:
return None
from litellm.proxy import proxy_server
from litellm.proxy._experimental.mcp_server.db import get_user_oauth_credential
from litellm.proxy.mcp_server.db import get_user_oauth_credential
if proxy_server.prisma_client is None:
return None
@ -1524,7 +1524,7 @@ async def exchange_token_with_server(
try:
# Identity binding above must retain the verified caller even when a write is
# denied. Authorize persistence separately, immediately before its side effect.
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import MCPRequestHandler
# A sealed code delegates a verified user for this authorized server. Raw
# request credentials retain their own JWT/key restrictions during resolution.
@ -1683,7 +1683,7 @@ async def _load_store_dcr_credentials(
(which has no LiteLLM_MCPServerTable row). Returns None when the store has no usable client_id
or the DB is unreachable. Registration writes request strict reads so a failed lookup cannot
be mistaken for an absent client."""
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415 # avoids circular import
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415 # avoids circular import
get_mcp_server_oauth_client_credentials,
)
from litellm.proxy.utils import get_prisma_client_or_throw # noqa: PLC0415 # avoids circular import
@ -1737,8 +1737,8 @@ async def _resolve_persisted_dcr_client(
the server-scoped store, while a rowless non-config server is a throwaway temp/session server with
no persisted client. Returns (row_or_None, credentials_or_None); the row is only needed by the
reuse path to refresh the registry for a DB-declared server."""
from litellm.proxy._experimental.mcp_server.db import get_mcp_server # noqa: PLC0415 # avoids circular import
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # avoids circular import
from litellm.proxy.mcp_server.db import get_mcp_server # noqa: PLC0415 # avoids circular import
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # avoids circular import
global_mcp_server_manager,
)
from litellm.proxy.utils import get_prisma_client_or_throw # noqa: PLC0415 # avoids circular import
@ -1793,7 +1793,7 @@ async def _reuse_persisted_dcr_client_if_available(
async def _refresh_persisted_dcr_server(persisted_server: Optional["LiteLLM_MCPServerTable"]) -> None:
if persisted_server is not None and persisted_server.approval_status != "draft":
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # avoids circular import
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # avoids circular import
global_mcp_server_manager,
)
@ -1910,16 +1910,16 @@ async def _persist_dcr_client_registration(
"dcr_server_url": mcp_server.url,
}
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415 # avoids circular import
from litellm.proxy._types import UpdateMCPServerRequest # noqa: PLC0415
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415 # avoids circular import
McpIdentifierConflict,
create_mcp_server_oauth_client_credentials_if_absent,
update_mcp_server,
upsert_mcp_server_oauth_client_credentials,
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415
global_mcp_server_manager,
)
from litellm.proxy._types import UpdateMCPServerRequest # noqa: PLC0415
from litellm.proxy.utils import get_prisma_client_or_throw # noqa: PLC0415
try:
@ -2403,7 +2403,7 @@ async def authorize(
scope=scope,
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy.mcp_server.mcp_server_manager import global_mcp_server_manager
lookup_name: Final[str | None] = mcp_server_name or client_id
client_ip: Final = IPAddressUtils.get_mcp_client_ip(request)
@ -2532,7 +2532,7 @@ async def _vendor_credential_state(
The one reading of "authorized" the connect page displays and the finish step enforces, so
the button a user sees and the grant they get cannot disagree. A read fault is neither, and
fails the scoped grant closed."""
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415 # circular import at module load
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415 # circular import at module load
get_user_oauth_credential,
oauth_grant_state,
)
@ -3184,7 +3184,7 @@ def _aggregate_header_scopes(request: Request) -> tuple[str, ...]:
discovery request, so a client that skips the 401 challenge (Claude Code re-authenticating
a server it already knows needs auth) still carries the selection to ``/authorize`` through
``scopes_supported``. Empty when the header is absent or any entry does not resolve."""
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import ( # noqa: PLC0415 # proxy import cycle
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import ( # noqa: PLC0415 # proxy import cycle
MCPRequestHandler,
gateway_dcr_challenge_scope,
)
@ -3489,7 +3489,7 @@ async def register_client(request: Request, mcp_server_name: str | None = None):
request=request, request_body=data, token_exchange_available=token_exchange_available()
)
client_application_type: Final = client_supplied_application_type(data.get("application_type"))
from litellm.proxy._experimental.mcp_server.mcp_server_manager import global_mcp_server_manager
from litellm.proxy.mcp_server.mcp_server_manager import global_mcp_server_manager
async with global_mcp_server_manager.catalog.operation():
dummy_return: Final = {

View file

@ -4,7 +4,7 @@ from typing import Final
from fastapi import HTTPException
from litellm.proxy._experimental.mcp_server.oauth_utils import encode_upstream_scope
from litellm.proxy.mcp_server.oauth_utils import encode_upstream_scope
TOKEN_EXCHANGE_SUBJECT_ERROR: Final = (
"Missing or invalid subject token. Authenticate with your identity provider and send its token "

View file

@ -7,16 +7,16 @@ a server-fault status) unrepresentable, and gives the trust-boundary rule one en
spec-defined machine fields may cross to callers, upstream prose and raw bodies go to server logs.
"""
from litellm.proxy._experimental.mcp_server.faults.classify import (
from litellm.proxy.mcp_server.faults.classify import (
classify_upstream_dcr_rejection,
classify_upstream_token_rejection,
)
from litellm.proxy._experimental.mcp_server.faults.render_oauth import (
from litellm.proxy.mcp_server.faults.render_oauth import (
dcr_fault_detail,
render_token_fault,
)
from litellm.proxy._experimental.mcp_server.faults.traversal import iter_exception_tree
from litellm.proxy._experimental.mcp_server.faults.types import (
from litellm.proxy.mcp_server.faults.traversal import iter_exception_tree
from litellm.proxy.mcp_server.faults.types import (
CallerRejected,
CredentialSource,
GatewayRejected,

View file

@ -13,7 +13,7 @@ import httpx
from pydantic import TypeAdapter
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.faults.types import (
from litellm.proxy.mcp_server.faults.types import (
GATEWAY_CAPABILITY_CODES,
GATEWAY_CREDENTIAL_CODES,
MAX_WIRE_FIELD_CHARS,

View file

@ -33,12 +33,12 @@ from litellm.constants import (
MCP_UPSTREAM_RATE_LIMIT_MAX_DELAY_SECONDS,
MCP_UPSTREAM_RATE_LIMIT_MAX_RETRIES,
)
from litellm.proxy._experimental.mcp_server.exceptions import (
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
from litellm.proxy.mcp_server.exceptions import (
MCPServerListError,
MCPUpstreamAuthError,
)
from litellm.proxy._experimental.mcp_server.faults.traversal import iter_exception_tree
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
from litellm.proxy.mcp_server.faults.traversal import iter_exception_tree
from litellm.types.llms.base import LiteLLMBaseModel
ListFaultCategory: TypeAlias = Literal[

View file

@ -11,8 +11,8 @@ from typing import Final
from fastapi.responses import JSONResponse
from typing_extensions import assert_never
from litellm.proxy._experimental.mcp_server.faults.types import CallerRejected, UpstreamOAuthFault
from litellm.proxy._experimental.mcp_server.oauth_utils import TOKEN_NO_CACHE_HEADERS
from litellm.proxy.mcp_server.faults.types import CallerRejected, UpstreamOAuthFault
from litellm.proxy.mcp_server.oauth_utils import TOKEN_NO_CACHE_HEADERS
def _gateway_rejected_description(code: str) -> str:

View file

@ -58,8 +58,15 @@ from typing_extensions import NotRequired, ReadOnly, TypedDict, assert_never
from litellm._internal_context import with_service_target
from litellm._logging import verbose_logger
from litellm.caching.caching import DualCache
from litellm.proxy._experimental.mcp_server.catalog import catalog_operation, global_manager
from litellm.proxy._experimental.mcp_server.oauth_utils import (
from litellm.proxy.common_utils.encrypt_decrypt_utils import (
decrypt_value_helper,
encrypt_value_helper,
)
from litellm.proxy.common_utils.html_forms.native_client_consent import (
render_native_client_consent_page,
)
from litellm.proxy.mcp_server.catalog import catalog_operation, global_manager
from litellm.proxy.mcp_server.oauth_utils import (
TOKEN_NO_CACHE_HEADERS,
UPSTREAM_SCOPE_PREFIX,
UpstreamScope,
@ -70,13 +77,13 @@ from litellm.proxy._experimental.mcp_server.oauth_utils import (
is_loopback_redirect_host,
validate_redirect_uri_shape,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.session_credentials import (
from litellm.proxy.mcp_server.outbound_credentials.session_credentials import (
SessionRefreshOpened,
SessionSigningConfigError,
active_session_signing_keys,
open_session_refresh_bearer,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.session_token import (
from litellm.proxy.mcp_server.outbound_credentials.session_token import (
SESSION_ISSUER,
SESSION_REFRESH_TTL_SECONDS,
MintedSessionToken,
@ -91,13 +98,6 @@ from litellm.proxy._experimental.mcp_server.outbound_credentials.session_token i
open_session_refresh_token,
open_session_token,
)
from litellm.proxy.common_utils.encrypt_decrypt_utils import (
decrypt_value_helper,
encrypt_value_helper,
)
from litellm.proxy.common_utils.html_forms.native_client_consent import (
render_native_client_consent_page,
)
from litellm.types.llms.base import LiteLLMBaseModel
from litellm.types.mcp_server.mcp_server_manager import MCPServer
@ -624,7 +624,7 @@ def _is_aggregate_resource(request: Request, resource: str) -> bool:
def _gateway_flow_server(name: str) -> MCPServer | None:
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # proxy import cycle
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # proxy import cycle
global_mcp_server_manager,
)
@ -656,7 +656,7 @@ def resolve_scoped_resource_server(request: Request, resource: str | None) -> MC
base: Final = canonicalize_url_identity(get_request_base_url(request))
if _is_aggregate_resource(request, resource) or not canonical.startswith(f"{base}/"):
return None
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import ( # noqa: PLC0415 # proxy import cycle
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import ( # noqa: PLC0415 # proxy import cycle
MCPRequestHandler,
)
@ -992,7 +992,7 @@ async def _flow_target(
) -> tuple[Literal["unscoped", "interactive", "m2m", "stale"], MCPServer | None]:
if server_id is None:
return "unscoped", None
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # import cycle
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # import cycle
MCPServerManager,
global_mcp_server_manager,
)

View file

@ -2,7 +2,7 @@
from typing import Final
from litellm.proxy._experimental.mcp_server.guardrail_translation.handler import (
from litellm.proxy.mcp_server.guardrail_translation.handler import (
MCPGuardrailTranslationHandler,
)
from litellm.types.utils import CallTypes

View file

@ -13,7 +13,7 @@ every ``description`` string in the schema lead ``texts``, so a guardrail that
blocks or masks them decides what the client gets to see in ``tools/list``.
Note: For MCP tool definitions (schema) -> OpenAI tools=[], see
litellm.experimental_mcp_client.tools.transform_mcp_tool_to_openai_tool
litellm.mcp_client.tools.transform_mcp_tool_to_openai_tool
when you have a full MCP Tool from list_tools. Here we only have the call
payload (name + arguments) so we just build the tool definition.
"""
@ -25,9 +25,9 @@ from fastapi import HTTPException
from mcp.types import Tool as MCPTool
from litellm._logging import verbose_proxy_logger
from litellm.experimental_mcp_client.tools import transform_mcp_tool_to_openai_tool
from litellm.llms.base_llm.guardrail_translation.base_translation import BaseTranslation
from litellm.proxy._experimental.mcp_server.utils import (
from litellm.mcp_client.tools import transform_mcp_tool_to_openai_tool
from litellm.proxy.mcp_server.utils import (
MAX_STRUCTURED_CONTENT_SCAN_DEPTH,
JSONLeafPath,
json_string_leaves,

View file

@ -27,20 +27,20 @@ from pydantic import TypeAdapter, ValidationError
from litellm._logging import verbose_proxy_logger
from litellm.models.user import LiteLLM_UserTable
from litellm.proxy._experimental.mcp_server.gateway_dcr_flow import (
from litellm.proxy._types import IdJagRequestingApp
from litellm.proxy.auth.handle_jwt import ID_JAG_TYP, AssertionRejection, JWTHandler
from litellm.proxy.mcp_server.gateway_dcr_flow import (
AssertionIdentity,
ConsentTeam,
SubjectIdentity,
SubjectTokenRefusal,
)
from litellm.proxy._experimental.mcp_server.idp_token_exchange import (
from litellm.proxy.mcp_server.idp_token_exchange import (
gateway_outage_refusal,
log_line,
read_token_exchange_prerequisites,
)
from litellm.proxy._experimental.mcp_server.oauth_utils import proxy_base_url_from_env
from litellm.proxy._types import IdJagRequestingApp
from litellm.proxy.auth.handle_jwt import ID_JAG_TYP, AssertionRejection, JWTHandler
from litellm.proxy.mcp_server.oauth_utils import proxy_base_url_from_env
ID_JAG_REQUIRED_CLAIMS: Final = ("iss", "sub", "aud", "exp", "iat", "jti", "client_id")
REJECTED_ASSERTION: Final = "assertion was rejected"
@ -395,10 +395,10 @@ class AssertionRedemption:
async def redeem_id_jag_assertion(
assertion: str, client_id: str, client_secret: str | None, request: Request
) -> AssertionIdentity | SubjectTokenRefusal:
from litellm.proxy._experimental.mcp_server.proxy_api_credentials import ( # noqa: PLC0415 # circular import at module load
from litellm.proxy.auth.auth_checks import get_user_object # noqa: PLC0415 # circular import at module load
from litellm.proxy.mcp_server.proxy_api_credentials import ( # noqa: PLC0415 # circular import at module load
lookup_consent_teams_from_database,
)
from litellm.proxy.auth.auth_checks import get_user_object # noqa: PLC0415 # circular import at module load
from litellm.proxy.proxy_server import ( # noqa: PLC0415 # rebound after startup, so read them per call
jwt_handler,
prisma_client,

View file

@ -13,10 +13,10 @@ from fastapi import HTTPException, Request
from typing_extensions import assert_never
from litellm._logging import verbose_proxy_logger
from litellm.proxy._experimental.mcp_server.gateway_dcr_flow import SubjectIdentity, SubjectTokenRefusal
from litellm.proxy._types import JWTAuthBuilderResult, ProxyException
from litellm.proxy.auth.handle_jwt import JWTAuthManager, JWTHandler
from litellm.proxy.db.exception_handler import PrismaDBExceptionHandler
from litellm.proxy.mcp_server.gateway_dcr_flow import SubjectIdentity, SubjectTokenRefusal
EXCHANGE_ROUTE: Final = "/token"
REJECTED_SUBJECT_TOKEN: Final = "subject_token was rejected by the gateway's JWT auth"

View file

@ -25,9 +25,9 @@ from mcp.types import (
)
from pydantic import BaseModel, ConfigDict, Field, JsonValue, TypeAdapter, ValidationError
from litellm.proxy._experimental.mcp_server.contracts import OperationContext
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import Error
from litellm.proxy._experimental.mcp_server.state_tokens import StateTokenError, open_state, seal_state
from litellm.proxy.mcp_server.contracts import OperationContext
from litellm.proxy.mcp_server.outbound_credentials.result import Error
from litellm.proxy.mcp_server.state_tokens import StateTokenError, open_state, seal_state
from litellm.types.mcp_server.mcp_server_manager import MCPServer

View file

@ -13,14 +13,14 @@ from mcp.types import (
)
from litellm.constants import MCP_CLIENT_TIMEOUT
from litellm.proxy._experimental.mcp_server.contracts import OperationContext
from litellm.proxy._experimental.mcp_server.mcp_context import get_active_mcp_request_ctx
from litellm.proxy._experimental.mcp_server.scope_challenge import (
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.mcp_server.contracts import OperationContext
from litellm.proxy.mcp_server.mcp_context import get_active_mcp_request_ctx
from litellm.proxy.mcp_server.scope_challenge import (
OAuthScopeResponse,
is_tool_call_request,
scope_response_from_request,
)
from litellm.proxy._types import UserAPIKeyAuth
class SamplingCallback(Protocol):
@ -43,7 +43,7 @@ def create_sampling_callback(
client_ip: str | None = None,
operation_context: OperationContext | None = None,
) -> SamplingCallback:
from litellm.proxy._experimental.mcp_server.server import get_active_auth_context
from litellm.proxy.mcp_server.server import get_active_auth_context
auth: Final = get_active_auth_context() if operation_context is None and user_api_key_auth is None else None
captured: Final = (
@ -60,7 +60,7 @@ def create_sampling_callback(
context: ClientRequestContext, params: CreateMessageRequestParams
) -> CreateMessageResult | CreateMessageResultWithTools | ErrorData:
import litellm
from litellm.proxy._experimental.mcp_server.sampling_handler import handle_sampling_create_message
from litellm.proxy.mcp_server.sampling_handler import handle_sampling_create_message
return await handle_sampling_create_message(
context=context,
@ -75,7 +75,7 @@ def create_sampling_callback(
def create_elicitation_callback(timeout: float | None = None) -> ElicitationCallback:
from litellm.proxy._experimental.mcp_server.server import get_active_mcp_session
from litellm.proxy.mcp_server.server import get_active_mcp_session
downstream_session: Final = get_active_mcp_session()
request: Final = get_active_mcp_request_ctx()
@ -94,7 +94,7 @@ def create_elicitation_callback(timeout: float | None = None) -> ElicitationCall
code=-32602,
message="A legacy upstream cannot resume input for a modern client; the operation may have partially completed",
)
from litellm.proxy._experimental.mcp_server.elicitation_handler import handle_elicitation_request
from litellm.proxy.mcp_server.elicitation_handler import handle_elicitation_request
return await handle_elicitation_request(
context=context,

View file

@ -124,7 +124,7 @@ from litellm.litellm_core_utils.secret_redaction import REDACTED, redact_string
from litellm.litellm_core_utils.sensitive_data_masker import SensitiveDataMasker
if TYPE_CHECKING:
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import AuthResolution
from litellm.proxy.mcp_server.outbound_credentials.types import AuthResolution
# Header the client sends to opt into debug mode
MCP_DEBUG_REQUEST_HEADER: Final = "x-litellm-mcp-debug"
@ -137,7 +137,7 @@ MCP_AUTH_DIAGNOSTICS_SCOPE_KEY: Final = "litellm.mcp.auth_diagnostics"
def record_auth_resolution(server_id: str, source: AuthResolution) -> None:
from litellm.proxy._experimental.mcp_server.mcp_context import get_active_mcp_request_ctx
from litellm.proxy.mcp_server.mcp_context import get_active_mcp_request_ctx
context: Final[object] = get_active_mcp_request_ctx()
request: Final[object] = getattr(context, "request", None)
@ -155,7 +155,7 @@ class MCPAuthDiagnostics:
self._outcomes = tuple(item for item in self._outcomes if item[0] != server_id) + ((server_id, resolution),)
def resolution(self) -> str:
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import AuthResolution
from litellm.proxy.mcp_server.outbound_credentials.types import AuthResolution
match self._outcomes:
case ():
@ -166,7 +166,7 @@ class MCPAuthDiagnostics:
return AuthResolution.multiple.value
def headers(self) -> Mapping[str, str]:
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import AuthResolution
from litellm.proxy.mcp_server.outbound_credentials.types import AuthResolution
if len(self._outcomes) <= 1:
return MappingProxyType({"x-mcp-debug-auth-resolution": self.resolution()})
@ -370,16 +370,16 @@ class MCPDebug:
if not raw_headers or not MCPDebug.is_debug_enabled(raw_headers):
return {}
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import (
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import (
MCPRequestHandler,
)
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
from litellm.proxy.mcp_server.mcp_server_manager import (
global_mcp_server_manager,
)
server_url: str | None = None
server_auth_type: str | None = None
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import AuthResolution
from litellm.proxy.mcp_server.outbound_credentials.types import AuthResolution
auth_resolution: Final = AuthResolution.unresolved.value
@ -471,7 +471,7 @@ def _body_secret_values(request: httpx.Request | httpx2.Request) -> tuple[str, .
body: Final = _JSON_BODY.validate_json(raw)
except ValueError:
return None
from litellm.proxy._experimental.mcp_server.utils import ( # noqa: PLC0415 # MCP utils imports clients; inspect bodies only after initialization
from litellm.proxy.mcp_server.utils import ( # noqa: PLC0415 # MCP utils imports clients; inspect bodies only after initialization
json_string_leaves,
)
@ -613,7 +613,7 @@ def describe_upstream_response(response: httpx.Response | httpx2.Response) -> st
def describe_upstream_http_failure(exc: BaseException) -> str | None:
from litellm.proxy._experimental.mcp_server.faults.traversal import ( # noqa: PLC0415 # fault package initialization imports the credential resolver
from litellm.proxy.mcp_server.faults.traversal import ( # noqa: PLC0415 # fault package initialization imports the credential resolver
iter_exception_tree,
)

View file

@ -73,7 +73,12 @@ from litellm.constants import (
MCP_UPSTREAM_SESSION_SHUTDOWN_TIMEOUT_SECONDS,
)
from litellm.exceptions import BlockedPiiEntityError, GuardrailRaisedException
from litellm.experimental_mcp_client.client import (
from litellm.integrations.custom_guardrail import (
_sync_guardrail_info_to_logging_obj, # pyright: ignore[reportPrivateUsage] - the same bridge @log_guardrail_information uses; reimplementing it here would fork the metadata-key logic
)
from litellm.litellm_core_utils.url_utils import SSRFError, async_safe_get
from litellm.llms.custom_httpx.http_handler import get_async_httpx_client
from litellm.mcp_client.client import (
SESSION_CLEANUP_TIMEOUT_MESSAGE,
MCPClient,
PersistentMCPSession,
@ -81,102 +86,114 @@ from litellm.experimental_mcp_client.client import (
strip_auth_scheme,
to_basic_credentials,
)
from litellm.integrations.custom_guardrail import (
_sync_guardrail_info_to_logging_obj, # pyright: ignore[reportPrivateUsage] - the same bridge @log_guardrail_information uses; reimplementing it here would fork the metadata-key logic
from litellm.proxy._types import (
LiteLLM_MCPServerTable,
MCPAuthType,
MCPEnvVar,
MCPTransport,
MCPTransportType,
SpecialMCPServerNames,
UserAPIKeyAuth,
is_per_server_oauth_discovery_eligible,
)
from litellm.litellm_core_utils.url_utils import SSRFError, async_safe_get
from litellm.llms.custom_httpx.http_handler import get_async_httpx_client
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import ( # noqa: F401 # legacy module exports
from litellm.proxy.agent_endpoints.auth.managed_authorization import managed_agent_policy
from litellm.proxy.auth.ip_address_utils import IPAddressUtils
from litellm.proxy.common_utils.encrypt_decrypt_utils import decrypt_value_helper
from litellm.proxy.common_utils.user_api_key_cache import get_management_object_ttl
from litellm.proxy.management_endpoints.sso.id_jag_assertion_capture import (
id_jag_assertion_capture_gap_at_startup,
)
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import ( # noqa: F401 # legacy module exports
MCPRequestHandler,
MCPServerAccess,
_is_mcp_admitted_user_subject, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
is_mcp_admitted_user_subject,
)
from litellm.proxy._experimental.mcp_server.catalog import _configuration_identity, _DiscoveryCache, _DiscoveryKey
from litellm.proxy._experimental.mcp_server.contracts import OperationContext
from litellm.proxy._experimental.mcp_server.elicitation_handler import (
from litellm.proxy.mcp_server.catalog import _configuration_identity, _DiscoveryCache, _DiscoveryKey
from litellm.proxy.mcp_server.contracts import OperationContext
from litellm.proxy.mcp_server.elicitation_handler import (
MCP_ELICITATION_AVAILABLE,
)
from litellm.proxy._experimental.mcp_server.exceptions import (
from litellm.proxy.mcp_server.exceptions import (
MCPServerListError,
MCPUpstreamAuthError,
)
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import (
from litellm.proxy.mcp_server.faults.list_outcomes import (
ServerListFault,
raise_classified_list_failure,
retry_upstream_rate_limit,
upstream_auth_challenge,
upstream_insufficient_scope,
)
from litellm.proxy._experimental.mcp_server.interactions import bind_target
from litellm.proxy._experimental.mcp_server.legacy_callbacks import get_scope_response, has_active_mcp_request_context
from litellm.proxy._experimental.mcp_server.mcp_debug import describe_upstream_http_failure, record_auth_resolution
from litellm.proxy._experimental.mcp_server.oauth2_token_cache import (
from litellm.proxy.mcp_server.interactions import bind_target
from litellm.proxy.mcp_server.legacy_callbacks import get_scope_response, has_active_mcp_request_context
from litellm.proxy.mcp_server.mcp_debug import describe_upstream_http_failure, record_auth_resolution
from litellm.proxy.mcp_server.oauth2_token_cache import (
MCPPerUserTokenCache,
mcp_per_user_token_cache,
)
from litellm.proxy._experimental.mcp_server.oauth_utils import ( # noqa: F401 # legacy module exports
from litellm.proxy.mcp_server.oauth_utils import ( # noqa: F401 # legacy module exports
_redact_mcp_resource_url, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
canonicalize_url_identity,
get_byok_www_authenticate,
needs_cimd_discovery,
redact_mcp_resource_url,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials import (
from litellm.proxy.mcp_server.outbound_credentials import (
Error,
Ok,
UpstreamCredentialProvider,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.adapter import (
from litellm.proxy.mcp_server.outbound_credentials.adapter import (
raise_public,
raise_token_exchange_challenge,
to_server_spec,
to_subject,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
InvalidatableOAuthTokenStore,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.per_user_oauth_store import (
from litellm.proxy.mcp_server.outbound_credentials.per_user_oauth_store import (
LazyPerUserOAuthTokenStore,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.token_exchange_provider import (
from litellm.proxy.mcp_server.outbound_credentials.token_exchange_provider import (
build_token_exchanger,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import (
from litellm.proxy.mcp_server.outbound_credentials.types import (
DEFAULT_CREDENTIAL_HEADER,
AuthResolution,
IdJagConfig,
PassthroughConfig,
TokenExchangeConfig,
)
from litellm.proxy._experimental.mcp_server.result_conversion import (
from litellm.proxy.mcp_server.result_conversion import (
WireCompat,
complete_call_tool_result,
handler_outcome,
to_gateway_tool,
)
from litellm.proxy._experimental.mcp_server.sampling_handler import (
from litellm.proxy.mcp_server.sampling_handler import (
MCP_SAMPLING_AVAILABLE,
)
from litellm.proxy._experimental.mcp_server.stdio_gate import (
from litellm.proxy.mcp_server.stdio_gate import (
MCP_STDIO_DISABLED_MESSAGE,
is_mcp_stdio_blocked,
warn_if_mcp_stdio_blocked,
)
from litellm.proxy._experimental.mcp_server.tool_catalog_guard import (
from litellm.proxy.mcp_server.tool_catalog_guard import (
CatalogAlert,
apply_description_overrides,
pin_tool_catalog,
scan_tool_descriptions,
)
from litellm.proxy._experimental.mcp_server.upstream import (
from litellm.proxy.mcp_server.upstream import (
passthrough_token_from_mcp_auth_header,
prepare_upstream_client,
resolve_upstream_auth,
take_forwarded_authorization,
to_server_spec_fail_closed,
)
from litellm.proxy._experimental.mcp_server.utils import (
from litellm.proxy.mcp_server.utils import (
MCP_SERVERS_TARGET,
MCP_TOOL_PREFIX_SEPARATOR,
MCPMissingUserEnvVarsError,
@ -201,23 +218,6 @@ from litellm.proxy._experimental.mcp_server.utils import (
strip_known_server_prefix,
validate_mcp_server_name,
)
from litellm.proxy._types import (
LiteLLM_MCPServerTable,
MCPAuthType,
MCPEnvVar,
MCPTransport,
MCPTransportType,
SpecialMCPServerNames,
UserAPIKeyAuth,
is_per_server_oauth_discovery_eligible,
)
from litellm.proxy.agent_endpoints.auth.managed_authorization import managed_agent_policy
from litellm.proxy.auth.ip_address_utils import IPAddressUtils
from litellm.proxy.common_utils.encrypt_decrypt_utils import decrypt_value_helper
from litellm.proxy.common_utils.user_api_key_cache import get_management_object_ttl
from litellm.proxy.management_endpoints.sso.id_jag_assertion_capture import (
id_jag_assertion_capture_gap_at_startup,
)
from litellm.proxy.middleware.per_request_root_path_middleware import (
get_request_root_path,
)
@ -242,7 +242,7 @@ from litellm.types.utils import CallTypes
if TYPE_CHECKING:
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
from litellm.proxy._experimental.mcp_server.contracts import CatalogListRequest, CatalogListResult
from litellm.proxy.mcp_server.contracts import CatalogListRequest, CatalogListResult
from litellm.types.mcp_server.mcp_toolset import MCPToolset
try:
@ -1032,7 +1032,7 @@ async def _openapi_spec_health(
) -> tuple[Literal["healthy", "unhealthy", "unknown"], str | None]:
"""Check specification availability, not upstream operations or user credentials."""
from litellm.llms.custom_httpx.http_handler import HTTPResponseLimitError
from litellm.proxy._experimental.mcp_server.openapi_to_mcp_generator import load_openapi_spec_async
from litellm.proxy.mcp_server.openapi_to_mcp_generator import load_openapi_spec_async
if not spec_path.startswith(("http://", "https://")):
return "unknown", "OpenAPI servers have no protocol-level health probe"
@ -1464,7 +1464,7 @@ async def _resolve_byok_mcp_auth_header(
if not mcp_server.is_byok:
return mcp_auth_header
from litellm.proxy._experimental.mcp_server.operations import (
from litellm.proxy.mcp_server.operations import (
_check_byok_credential,
_get_byok_credential,
)
@ -1835,7 +1835,7 @@ def _create_sampling_callback(
):
if not MCP_SAMPLING_AVAILABLE:
return None
from litellm.proxy._experimental.mcp_server.legacy_callbacks import create_sampling_callback
from litellm.proxy.mcp_server.legacy_callbacks import create_sampling_callback
return create_sampling_callback(user_api_key_auth, raw_headers, client_ip, operation_context)
@ -1843,7 +1843,7 @@ def _create_sampling_callback(
def _create_elicitation_callback(timeout: float | None = None):
if not MCP_ELICITATION_AVAILABLE:
return None
from litellm.proxy._experimental.mcp_server.legacy_callbacks import create_elicitation_callback
from litellm.proxy.mcp_server.legacy_callbacks import create_elicitation_callback
return create_elicitation_callback(timeout=timeout)
@ -2035,7 +2035,7 @@ class MCPServerManager:
self._template_discovery_cache = _DiscoveryCache[ListResourceTemplatesResult](
discovery_ttl, discovery_clock, TypeAdapter(ListResourceTemplatesResult)
)
from litellm.proxy._experimental.mcp_server.catalog import CatalogSnapshots
from litellm.proxy.mcp_server.catalog import CatalogSnapshots
self.catalog = CatalogSnapshots(self)
self.registry: dict[str, MCPServer] = {}
@ -2887,7 +2887,7 @@ class MCPServerManager:
"""Overlay each config-declared server's persisted DCR client (from the server-scoped
store) onto its in-memory object so token refresh authenticates after a restart. A
best-effort no-op when the DB is unreachable at config-load time."""
from litellm.proxy._experimental.mcp_server.discoverable_endpoints import ( # noqa: PLC0415 # circular import
from litellm.proxy.mcp_server.discoverable_endpoints import ( # noqa: PLC0415 # circular import
hydrate_config_server_dcr_client,
)
@ -2919,16 +2919,16 @@ class MCPServerManager:
server: The MCPServer instance to register tools for
base_url: Base URL for API calls
"""
from litellm.proxy._experimental.mcp_server.openapi_to_mcp_generator import (
from litellm.proxy.mcp_server.openapi_to_mcp_generator import (
build_input_schema,
create_tool_function,
load_openapi_spec_async,
resolve_operation_params,
)
from litellm.proxy._experimental.mcp_server.openapi_to_mcp_generator import (
from litellm.proxy.mcp_server.openapi_to_mcp_generator import (
get_base_url as get_openapi_base_url,
)
from litellm.proxy._experimental.mcp_server.tool_registry import (
from litellm.proxy.mcp_server.tool_registry import (
global_mcp_tool_registry,
)
@ -3061,7 +3061,7 @@ class MCPServerManager:
self.remove_server_tool_routing(server)
def remove_server_tool_routing(self, server: MCPServer) -> None:
from litellm.proxy._experimental.mcp_server.tool_registry import global_mcp_tool_registry
from litellm.proxy.mcp_server.tool_registry import global_mcp_tool_registry
prefix_root: Final = normalize_server_name(get_server_prefix(server))
if server.spec_path and prefix_root:
@ -3128,7 +3128,7 @@ class MCPServerManager:
) -> _EnvVarList | None:
env_vars_list: Final = _deserialize_json_list(getattr(mcp_server, "env_vars", None))
if env_vars_are_encrypted:
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415
decrypt_global_env_var_values,
)
@ -3578,7 +3578,7 @@ class MCPServerManager:
return []
try:
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415
get_active_submitted_mcp_server_ids_for_user,
)
from litellm.proxy.proxy_server import prisma_client, user_api_key_cache
@ -3835,7 +3835,7 @@ class MCPServerManager:
one silently renames the tool when a native name happens to begin with
it (``greyhound_internal_events`` on a server prefixed ``greyhound``).
"""
from litellm.proxy._experimental.mcp_server.toolset_db import list_mcp_toolsets
from litellm.proxy.mcp_server.toolset_db import list_mcp_toolsets
from litellm.proxy.proxy_server import prisma_client, user_api_key_cache
if not toolset_ids or prisma_client is None:
@ -3933,7 +3933,7 @@ class MCPServerManager:
return MCPToolset(**cached)
return cached
from litellm.proxy._experimental.mcp_server.toolset_db import (
from litellm.proxy.mcp_server.toolset_db import (
get_mcp_toolset_by_name,
)
@ -4291,7 +4291,7 @@ class MCPServerManager:
"is configured. Connect a database to your proxy to use per-user "
"MCP env vars."
)
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415
get_user_env_vars,
)
@ -4455,7 +4455,7 @@ class MCPServerManager:
record_listing: bool = False,
listing_updates: ExitStack | None = None,
) -> ListToolsResult:
from litellm.proxy._experimental.mcp_server.tool_registry import (
from litellm.proxy.mcp_server.tool_registry import (
global_mcp_tool_registry,
)
@ -4662,7 +4662,7 @@ class MCPServerManager:
self._template_discovery_cache.invalidate(server_id)
def invalidate_server_definition_caches(self, server_id: str) -> None:
from litellm.proxy._experimental.mcp_server.discoverable_endpoints import ( # noqa: PLC0415 # lazy: discoverable_endpoints lazily imports this module's manager singleton
from litellm.proxy.mcp_server.discoverable_endpoints import ( # noqa: PLC0415 # lazy: discoverable_endpoints lazily imports this module's manager singleton
invalidate_oauth_metadata_cache,
)
@ -5830,7 +5830,7 @@ class MCPServerManager:
Returns:
List of tools with prefixed names
"""
from litellm.proxy._experimental.mcp_server.tool_registry import global_mcp_tool_registry
from litellm.proxy.mcp_server.tool_registry import global_mcp_tool_registry
if register_bare_names and listing_updates is not None:
listing_updates.callback(self._create_prefixed_tools, tools, server, add_prefix=add_prefix)
@ -5942,7 +5942,7 @@ class MCPServerManager:
deriving the spellings routing accepts, never by stripping the entry, which would
cut a second boundary out of a native name that opens with the server prefix.
"""
from litellm.proxy._experimental.mcp_server.utils import (
from litellm.proxy.mcp_server.utils import (
server_applies_tool_allowlist,
)
@ -6005,7 +6005,7 @@ class MCPServerManager:
Raises:
HTTPException: If tool is not allowed for this key/team
"""
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import (
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import (
MCPRequestHandler,
)
@ -6050,7 +6050,7 @@ class MCPServerManager:
"""
from mcp.types import TextContent
from litellm.proxy._experimental.mcp_server.tool_registry import (
from litellm.proxy.mcp_server.tool_registry import (
global_mcp_tool_registry,
)
@ -6868,7 +6868,7 @@ class MCPServerManager:
return oauth2_headers
try:
from litellm.proxy._experimental.mcp_server.operations import ( # noqa: PLC0415
from litellm.proxy.mcp_server.operations import ( # noqa: PLC0415
_get_user_oauth_extra_headers_from_db,
)
@ -7108,7 +7108,7 @@ class MCPServerManager:
)
async def _call_openapi_via_handler():
from litellm.proxy._experimental.mcp_server.openapi_to_mcp_generator import (
from litellm.proxy.mcp_server.openapi_to_mcp_generator import (
request_auth_header,
request_extra_headers,
request_resolved_auth_headers,
@ -7207,7 +7207,7 @@ class MCPServerManager:
Returns:
MCPServer if found, None otherwise
"""
from litellm.proxy._experimental.mcp_server.tool_registry import global_mcp_tool_registry
from litellm.proxy.mcp_server.tool_registry import global_mcp_tool_registry
registered_tool: Final = global_mcp_tool_registry.get_tool(tool_name)
if registered_tool is not None:

View file

@ -42,7 +42,7 @@ from typing import Final, Literal, Protocol
from pydantic import JsonValue
from litellm._logging import verbose_proxy_logger
from litellm.proxy._experimental.mcp_server.db import ( # noqa: F401 # legacy module exports
from litellm.proxy.mcp_server.db import ( # noqa: F401 # legacy module exports
_decode_oauth_payload, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
decode_oauth_payload,
decrypt_credentials,

View file

@ -26,17 +26,17 @@ from litellm.constants import (
MCP_PER_USER_TOKEN_REDIS_KEY_PREFIX,
)
from litellm.llms.custom_httpx.http_handler import get_async_httpx_client
from litellm.proxy._experimental.mcp_server.oauth_utils import (
build_upstream_oauth2_token_request,
resolve_upstream_resource,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import OAuthToken
from litellm.proxy._experimental.mcp_server.outbound_credentials.token_cache_codec import OAuthTokenCacheCodec
from litellm.proxy._experimental.mcp_server.utils import MCP_OAUTH_TOKENS_TARGET
from litellm.proxy.common_utils.encrypt_decrypt_utils import (
decrypt_value_helper,
encrypt_value_helper,
)
from litellm.proxy.mcp_server.oauth_utils import (
build_upstream_oauth2_token_request,
resolve_upstream_resource,
)
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import OAuthToken
from litellm.proxy.mcp_server.outbound_credentials.token_cache_codec import OAuthTokenCacheCodec
from litellm.proxy.mcp_server.utils import MCP_OAUTH_TOKENS_TARGET
from litellm.types.llms.custom_http import httpxSpecialProvider
if TYPE_CHECKING:

View file

@ -184,7 +184,7 @@ def _upstream_principal(
async def _load_caller_principal(litellm_user_id: str, binding: MCPOAuthIdentityBinding) -> str | None:
if binding.caller_field == "user_id":
return litellm_user_id
from litellm.proxy._experimental.mcp_server.bridge_token_flow import ( # noqa: PLC0415 # inline import avoids a module-load circular import
from litellm.proxy.mcp_server.bridge_token_flow import ( # noqa: PLC0415 # inline import avoids a module-load circular import
load_active_user_by_id,
)
@ -198,7 +198,7 @@ async def _load_stored_refresh_token(
litellm_user_id: str, server_id: str, binding: MCPOAuthIdentityBinding
) -> VerifiedRefreshToken | None:
try:
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415 # keep database imports lazy
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415 # keep database imports lazy
get_user_oauth_credential,
)
from litellm.proxy.utils import get_prisma_client_or_throw # noqa: PLC0415 # keep database imports lazy

View file

@ -40,8 +40,8 @@ from typing import Final, Protocol
from urllib.parse import urlparse
from litellm._logging import verbose_proxy_logger
from litellm.proxy._experimental.mcp_server.oauth_utils import canonicalize_url_identity
from litellm.proxy.db.db_span import db_span
from litellm.proxy.mcp_server.oauth_utils import canonicalize_url_identity
from litellm.proxy.utils import PrismaClient
# The actor the removed discovery write-back stamped rows with.

View file

@ -14,15 +14,15 @@ from fastapi import HTTPException, Request
from starlette.types import Scope
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.auth.token_endpoint_auth import (
from litellm.proxy.auth.ip_address_utils import IPAddressUtils
from litellm.proxy.mcp_server.auth.token_endpoint_auth import (
TokenEndpointClientAuth,
build_token_endpoint_client_auth,
normalize_token_endpoint_auth_method,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_store import (
from litellm.proxy.mcp_server.outbound_credentials.sso_assertion_store import (
GOOGLE_REFRESH_TOKEN_PARAMS,
)
from litellm.proxy.auth.ip_address_utils import IPAddressUtils
from litellm.proxy.middleware.per_request_root_path_middleware import get_request_root_path
if TYPE_CHECKING:

View file

@ -16,7 +16,7 @@ import httpx
from typing_extensions import ReadOnly, Required
from litellm.llms.custom_httpx.http_handler import MaskedHTTPStatusError
from litellm.proxy._experimental.mcp_server.exceptions import (
from litellm.proxy.mcp_server.exceptions import (
MCPOpenApiUpstreamError,
MCPUpstreamAuthError,
)
@ -54,8 +54,8 @@ from litellm.llms.custom_httpx.http_handler import (
header_value,
httpxSpecialProvider,
)
from litellm.proxy._experimental.mcp_server.tool_outcome import JsonResult, TextResult, parse_http_body
from litellm.proxy._experimental.mcp_server.tool_registry import (
from litellm.proxy.mcp_server.tool_outcome import JsonResult, TextResult, parse_http_body
from litellm.proxy.mcp_server.tool_registry import (
global_mcp_tool_registry,
)
from litellm.types.mcp import MCPAuthType, credential_redirect_hook, custom_credential_slot
@ -442,7 +442,7 @@ def _merge_openapi_tool_request_headers(
the MCP caller (allowlisted by ``MCPServer.extra_headers``)
This matches the existing MCP invariant in
:func:`litellm.proxy._experimental.mcp_server.utils.merge_mcp_headers`
:func:`litellm.proxy.mcp_server.utils.merge_mcp_headers`
and the managed MCP path, where ``static_headers`` always wins over
caller-forwarded headers. Keeping the same precedence here prevents an
authenticated caller from overriding an operator-configured value
@ -542,11 +542,11 @@ def create_tool_function(
"""
effective_headers: Final = _merge_openapi_tool_request_headers(headers)
if auth_type is not None:
from litellm.proxy._experimental.mcp_server.outbound_credentials.adapter import (
from litellm.proxy.mcp_server.outbound_credentials.adapter import (
raise_public,
validate_static_credential,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import Error, Ok
from litellm.proxy.mcp_server.outbound_credentials.result import Error, Ok
match validate_static_credential(auth_type, effective_headers, upstream_token_header, headers or ()):
case Error(error):

View file

@ -56,40 +56,51 @@ from litellm.constants import (
MCP_TOOL_LISTING_TIMEOUT,
)
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import (
from litellm.proxy._types import (
UserAPIKeyAuth,
)
from litellm.proxy.common_utils.auth_cache_invalidation_pubsub import (
publish_auth_cache_invalidation,
)
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
from litellm.proxy.litellm_pre_call_utils import (
LiteLLMProxyRequestSetup,
get_chain_id_from_headers,
)
from litellm.proxy.mcp_server.auth.user_api_key_auth_mcp import (
MCPRequestHandler,
)
from litellm.proxy._experimental.mcp_server.byok_credential_cache import (
from litellm.proxy.mcp_server.byok_credential_cache import (
byok_credential_cache,
byok_credential_cache_key,
cache_byok_credential,
get_cached_byok_credential,
)
from litellm.proxy._experimental.mcp_server.capabilities import (
from litellm.proxy.mcp_server.capabilities import (
build_discovery,
configured_versions,
disabled_capabilities,
enabled_gateway_operations,
)
from litellm.proxy._experimental.mcp_server.catalog import catalog_operation, global_manager
from litellm.proxy._experimental.mcp_server.contracts import (
from litellm.proxy.mcp_server.catalog import catalog_operation, global_manager
from litellm.proxy.mcp_server.contracts import (
AuthorizedToolCall,
OperationContext,
ProgressCallback,
)
from litellm.proxy._experimental.mcp_server.db import OAuthCredentialPayload
from litellm.proxy._experimental.mcp_server.exceptions import (
from litellm.proxy.mcp_server.db import OAuthCredentialPayload
from litellm.proxy.mcp_server.exceptions import (
MCPToolResultError,
MCPUpstreamAuthError,
)
from litellm.proxy._experimental.mcp_server.faults.list_outcomes import (
from litellm.proxy.mcp_server.faults.list_outcomes import (
AggregateToolListing,
ServerListOk,
ServerOutcome,
classify_list_exception,
outcome_wire_value,
)
from litellm.proxy._experimental.mcp_server.interactions import (
from litellm.proxy.mcp_server.interactions import (
BoundInputRequiredResult,
ContinuationState,
InteractionOperation,
@ -97,8 +108,8 @@ from litellm.proxy._experimental.mcp_server.interactions import (
seal_continuation,
target_digest,
)
from litellm.proxy._experimental.mcp_server.legacy_callbacks import get_scope_response
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: F401 # legacy module exports
from litellm.proxy.mcp_server.legacy_callbacks import get_scope_response
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: F401 # legacy module exports
MCPServerManager,
_caller_authorization_fans_out, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
_client_forwarded_authorization_headers, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
@ -111,12 +122,12 @@ from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa:
resolve_openapi_tool_auth,
should_strip_caller_authorization,
)
from litellm.proxy._experimental.mcp_server.oauth_utils import ( # noqa: F401 # legacy module exports
from litellm.proxy.mcp_server.oauth_utils import ( # noqa: F401 # legacy module exports
_redact_mcp_resource_url, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
get_byok_www_authenticate,
redact_mcp_resource_url,
)
from litellm.proxy._experimental.mcp_server.openapi_to_mcp_generator import ( # noqa: F401 # legacy module exports
from litellm.proxy.mcp_server.openapi_to_mcp_generator import ( # noqa: F401 # legacy module exports
_request_auth_header, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
_request_extra_headers, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
_request_resolved_auth_headers, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
@ -124,16 +135,16 @@ from litellm.proxy._experimental.mcp_server.openapi_to_mcp_generator import ( #
request_extra_headers,
request_resolved_auth_headers,
)
from litellm.proxy._experimental.mcp_server.result_conversion import (
from litellm.proxy.mcp_server.result_conversion import (
WireCompat,
complete_call_tool_result,
handler_outcome,
to_call_tool_result,
)
from litellm.proxy._experimental.mcp_server.tool_registry import (
from litellm.proxy.mcp_server.tool_registry import (
global_mcp_tool_registry,
)
from litellm.proxy._experimental.mcp_server.utils import (
from litellm.proxy.mcp_server.utils import (
MCP_TOOL_PREFIX_SEPARATOR,
MCPMissingUserEnvVarsError,
add_server_prefix_to_name,
@ -148,20 +159,9 @@ from litellm.proxy._experimental.mcp_server.utils import (
split_server_prefix_from_name,
strip_known_server_prefix,
)
from litellm.proxy._experimental.mcp_server.utils import (
from litellm.proxy.mcp_server.utils import (
server_answers_to as _server_answers_to,
)
from litellm.proxy._types import (
UserAPIKeyAuth,
)
from litellm.proxy.common_utils.auth_cache_invalidation_pubsub import (
publish_auth_cache_invalidation,
)
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
from litellm.proxy.litellm_pre_call_utils import (
LiteLLMProxyRequestSetup,
get_chain_id_from_headers,
)
from litellm.types.mcp import (
DEFAULT_CREDENTIAL_HEADER,
MCP_LEGACY_VERSIONS,
@ -426,7 +426,7 @@ async def _dispatch_virtual_mcp_tool(
the caller falls through to normal tool routing.
"""
from litellm.llms.litellm_proxy.skills.skill_search import DEFAULT_SKILL_SEARCH_TOP_K
from litellm.proxy._experimental.mcp_server.tool_search import (
from litellm.proxy.mcp_server.tool_search import (
AGENT_SEARCH_TOOL_NAME,
DEFAULT_AGENT_SEARCH_TOP_K,
MCP_PROXY_CALL_TOOL_NAME,
@ -799,7 +799,7 @@ def filter_tools_by_allowed_tools(
Returns:
Filtered list of tools
"""
from litellm.proxy._experimental.mcp_server.utils import (
from litellm.proxy.mcp_server.utils import (
server_applies_tool_allowlist,
)
@ -911,7 +911,7 @@ def _client_has_per_server_auth_header(
"""
if not mcp_server_auth_headers:
return False
from litellm.proxy._experimental.mcp_server.utils import (
from litellm.proxy.mcp_server.utils import (
lookup_mcp_server_auth_in_headers,
)
@ -960,7 +960,7 @@ async def _get_user_oauth_extra_headers_from_db(
"""
if server.auth_type != MCPAuth.oauth2 or user_api_key_auth is None:
return None
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415
resolve_user_oauth_access_token,
)
@ -981,7 +981,7 @@ async def _prefetch_oauth_creds_for_user(
if not user_id:
return {}
try:
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415
list_user_oauth_credentials,
)
from litellm.proxy.utils import get_prisma_client_or_throw # noqa: PLC0415
@ -1015,7 +1015,7 @@ def _prepare_mcp_server_headers(
"""
server_auth_header: dict[str, str] | str | None = None
if mcp_server_auth_headers:
from litellm.proxy._experimental.mcp_server.utils import (
from litellm.proxy.mcp_server.utils import (
lookup_mcp_server_auth_in_headers,
)
@ -1182,8 +1182,8 @@ async def find_mcp_proxy_tool(
) -> MCPTool | None:
"""Resolve an /mcp/proxy tool_id against the caller's catalog, returning as soon as the
server that owns it has listed instead of waiting for every allowed server."""
from litellm.proxy._experimental.mcp_server.catalog import get_filtered_server_tools
from litellm.proxy._experimental.mcp_server.tool_search import mcp_proxy_tool_id
from litellm.proxy.mcp_server.catalog import get_filtered_server_tools
from litellm.proxy.mcp_server.tool_search import mcp_proxy_tool_id
allowed_mcp_servers: Final = await _get_allowed_mcp_servers(
user_api_key_auth=user_api_key_auth,
@ -1366,7 +1366,7 @@ async def _get_tools_from_mcp_servers(
await _prefetch_oauth_creds_for_user(user_api_key_auth) if _has_oauth2_server else {}
)
from litellm.proxy._experimental.mcp_server.catalog import get_filtered_server_tools
from litellm.proxy.mcp_server.catalog import get_filtered_server_tools
context: Final = OperationContext(
_caller=user_api_key_auth,
@ -1413,7 +1413,7 @@ async def _get_tools_from_mcp_servers(
},
)
else:
from litellm.proxy._experimental.mcp_server.catalog import aggregate_gateway_tools
from litellm.proxy.mcp_server.catalog import aggregate_gateway_tools
aggregated = await aggregate_gateway_tools(
context,
@ -1912,7 +1912,7 @@ async def _get_byok_credential(
if cached is not None:
return cached.credential
from litellm.proxy._experimental.mcp_server.db import get_user_credential
from litellm.proxy.mcp_server.db import get_user_credential
from litellm.proxy.proxy_server import prisma_client
if prisma_client is None:
@ -1970,7 +1970,7 @@ async def _check_byok_credential(
)
return
from litellm.proxy._experimental.mcp_server.db import get_user_credential
from litellm.proxy.mcp_server.db import get_user_credential
from litellm.proxy.proxy_server import prisma_client
if prisma_client is None:
@ -2032,7 +2032,7 @@ def _challenge_missing_token_exchange_subject(
return
if global_mcp_server_manager.extract_subject_token(oauth2_headers, raw_headers, user_api_key_auth) is not None:
return
from litellm.proxy._experimental.mcp_server.outbound_credentials.adapter import ( # noqa: PLC0415 # lazy: adapter pulls MCP subgraph
from litellm.proxy.mcp_server.outbound_credentials.adapter import ( # noqa: PLC0415 # lazy: adapter pulls MCP subgraph
raise_token_exchange_challenge,
)
from litellm.proxy.middleware.per_request_root_path_middleware import ( # noqa: PLC0415 # lazy: middleware imports proxy utils
@ -3262,7 +3262,7 @@ async def _execute_handle_list_tools(
)
from mcp.types import Tool
from litellm.proxy._experimental.mcp_server.tool_search import (
from litellm.proxy.mcp_server.tool_search import (
get_mcp_proxy_tool_definitions,
get_virtual_tool_definitions,
)
@ -3280,8 +3280,8 @@ async def _execute_handle_list_tools(
raise MCPError(code=INVALID_PARAMS, message="Invalid pagination cursor; start a fresh listing")
return ListToolsResult(tools=[Tool.model_validate(d) for d in get_virtual_tool_definitions()])
from litellm.proxy._experimental.mcp_server.catalog import list_gateway_catalog
from litellm.proxy._experimental.mcp_server.server_resolution import MCPServerTargetCatalog
from litellm.proxy.mcp_server.catalog import list_gateway_catalog
from litellm.proxy.mcp_server.server_resolution import MCPServerTargetCatalog
catalog: Final = MCPServerTargetCatalog(
global_mcp_server_manager,
@ -3310,7 +3310,7 @@ async def _execute_handle_list_tools(
async def _discover_tools_listing(
context: OperationContext, host_progress_callback: ProgressCallback | None
) -> ListToolsResult:
from litellm.proxy._experimental.mcp_server.catalog import ToolListingFailedOutright
from litellm.proxy.mcp_server.catalog import ToolListingFailedOutright
try:
return await _execute_handle_list_tools(
@ -3487,8 +3487,8 @@ async def _execute_list_prompts(
from mcp.shared.exceptions import MCPError
from mcp.types import INVALID_PARAMS, INVALID_REQUEST
from litellm.proxy._experimental.mcp_server.catalog import list_gateway_catalog
from litellm.proxy._experimental.mcp_server.server_resolution import MCPServerTargetCatalog
from litellm.proxy.mcp_server.catalog import list_gateway_catalog
from litellm.proxy.mcp_server.server_resolution import MCPServerTargetCatalog
if context.mcp_proxy_mode:
_reject_mcp_proxy_operation()
@ -3551,8 +3551,8 @@ async def _execute_list_resources(
from mcp.shared.exceptions import MCPError
from mcp.types import INVALID_PARAMS, INVALID_REQUEST
from litellm.proxy._experimental.mcp_server.catalog import list_gateway_catalog
from litellm.proxy._experimental.mcp_server.server_resolution import MCPServerTargetCatalog
from litellm.proxy.mcp_server.catalog import list_gateway_catalog
from litellm.proxy.mcp_server.server_resolution import MCPServerTargetCatalog
if context.mcp_proxy_mode:
_reject_mcp_proxy_operation()
@ -3581,8 +3581,8 @@ async def _execute_list_resource_templates(
from mcp.shared.exceptions import MCPError
from mcp.types import INVALID_PARAMS, INVALID_REQUEST
from litellm.proxy._experimental.mcp_server.catalog import list_gateway_catalog
from litellm.proxy._experimental.mcp_server.server_resolution import MCPServerTargetCatalog
from litellm.proxy.mcp_server.catalog import list_gateway_catalog
from litellm.proxy.mcp_server.server_resolution import MCPServerTargetCatalog
if context.mcp_proxy_mode:
_reject_mcp_proxy_operation()
@ -3809,7 +3809,7 @@ class GatewayOperations:
)
try:
results: Final = await asyncio.gather(*tasks)
from litellm.proxy._experimental.mcp_server.subscriptions import subscription_capabilities
from litellm.proxy.mcp_server.subscriptions import subscription_capabilities
async def discover_notifications() -> tuple[frozenset[str], ServerCapabilities]:
remaining: Final = deadline - time.monotonic()

View file

@ -8,19 +8,19 @@ CredError]``) rather than raised, so every seam is total. Nothing here is wired
request path yet.
"""
from litellm.proxy._experimental.mcp_server.outbound_credentials.httpx_auth import (
from litellm.proxy.mcp_server.outbound_credentials.httpx_auth import (
NoOpAuth,
StaticHeaderAuth,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.resolver import (
from litellm.proxy.mcp_server.outbound_credentials.resolver import (
UpstreamCredentialProvider,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import (
from litellm.proxy.mcp_server.outbound_credentials.result import (
Error,
Ok,
Result,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import (
from litellm.proxy.mcp_server.outbound_credentials.types import (
DEFAULT_CREDENTIAL_HEADER,
Ambient,
ApiKeyConfig,

View file

@ -20,11 +20,11 @@ from fastapi import HTTPException
from pydantic import SecretStr
from typing_extensions import assert_never
from litellm.experimental_mcp_client.client import MCPClient, strip_auth_scheme, to_basic_credentials
from litellm.proxy._experimental.mcp_server.exceptions import TOKEN_EXCHANGE_SUBJECT_ERROR, MCPServerURLCredentialsError
from litellm.proxy._experimental.mcp_server.oauth_utils import resolve_upstream_resource
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import Error, Ok, Result
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import (
from litellm.mcp_client.client import MCPClient, strip_auth_scheme, to_basic_credentials
from litellm.proxy.mcp_server.exceptions import TOKEN_EXCHANGE_SUBJECT_ERROR, MCPServerURLCredentialsError
from litellm.proxy.mcp_server.oauth_utils import resolve_upstream_resource
from litellm.proxy.mcp_server.outbound_credentials.result import Error, Ok, Result
from litellm.proxy.mcp_server.outbound_credentials.types import (
DEFAULT_CREDENTIAL_HEADER,
ApiKeyConfig,
AuthorizationCodeConfig,

View file

@ -17,16 +17,16 @@ from typing import TYPE_CHECKING, Final, Protocol
from fastapi import HTTPException
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.auth.token_endpoint_auth import (
from litellm.proxy.mcp_server.auth.token_endpoint_auth import (
TokenEndpointAuthConfigError,
)
from litellm.proxy._experimental.mcp_server.oauth_identity_binding import (
from litellm.proxy.mcp_server.oauth_identity_binding import (
BindingValidator,
RefreshTokenPresented,
enforce_oauth_identity_binding,
)
from litellm.proxy._experimental.mcp_server.oauth_utils import build_upstream_oauth2_token_request, get_cimd_client_id
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.oauth_utils import build_upstream_oauth2_token_request, get_cimd_client_id
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
OAuthToken,
)

View file

@ -16,7 +16,7 @@ from typing import Final, Literal, TypeAlias
from pydantic import ConfigDict, SecretStr
from litellm.proxy._experimental.mcp_server.outbound_credentials.envelope import (
from litellm.proxy.mcp_server.outbound_credentials.envelope import (
EnvelopeIdentity,
EnvelopeKeys,
EnvelopeMintError,

View file

@ -40,17 +40,17 @@ from pydantic import ConfigDict, Field, SecretStr, TypeAdapter, ValidationError
from typing_extensions import assert_never
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
InMemoryTokenCacheBackend,
OAuthToken,
TokenCacheBackend,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import (
from litellm.proxy.mcp_server.outbound_credentials.result import (
Error,
Ok,
Result,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import (
from litellm.proxy.mcp_server.outbound_credentials.types import (
ClientCredentialsConfig,
CredError,
HeaderCarrier,
@ -105,7 +105,7 @@ async def post_client_credentials_grant(
from litellm.llms.custom_httpx.http_handler import ( # noqa: PLC0415 # defer heavy handler import to call time
get_async_httpx_client, # pyright: ignore[reportUnknownVariableType] # handler factory params are coarsely typed
)
from litellm.proxy._experimental.mcp_server.mcp_debug import ( # noqa: PLC0415 # diagnostics import credential enums through this package
from litellm.proxy.mcp_server.mcp_debug import ( # noqa: PLC0415 # diagnostics import credential enums through this package
describe_upstream_http_failure,
describe_upstream_response,
safe_upstream_url,
@ -298,7 +298,7 @@ def _prepare_grant(config: ClientCredentialsConfig) -> Result[_PreparedGrant, Cr
)
return Error(CredError.of_misconfigured(f"client_credentials config is missing: {missing}"))
from litellm.proxy._experimental.mcp_server.auth.token_endpoint_auth import ( # noqa: PLC0415 # keep package v1-free at import time
from litellm.proxy.mcp_server.auth.token_endpoint_auth import ( # noqa: PLC0415 # keep package v1-free at import time
build_token_endpoint_client_auth,
)

View file

@ -14,13 +14,13 @@ from typing import Final, Protocol
from litellm._internal_context import with_service_target
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
OAuthToken,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.token_cache_codec import (
from litellm.proxy.mcp_server.outbound_credentials.token_cache_codec import (
OAuthTokenCacheCodec,
)
from litellm.proxy._experimental.mcp_server.utils import MCP_OAUTH_TOKENS_TARGET
from litellm.proxy.mcp_server.utils import MCP_OAUTH_TOKENS_TARGET
class AsyncCache(Protocol):

View file

@ -27,24 +27,24 @@ from datetime import datetime, timezone
from typing import Final, Protocol
from litellm._logging import verbose_proxy_logger
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import Error, Ok, Result
from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_refresher import (
from litellm.proxy._types import LiteLLM_MCPServerTable
from litellm.proxy.mcp_server.outbound_credentials.result import Error, Ok, Result
from litellm.proxy.mcp_server.outbound_credentials.sso_assertion_refresher import (
SSOClientConfig,
sso_client_config,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_store import (
from litellm.proxy.mcp_server.outbound_credentials.sso_assertion_store import (
SSOIdentityAssertion,
with_login_refresh_token,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.token_endpoint import ExchangedToken
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import (
from litellm.proxy.mcp_server.outbound_credentials.token_endpoint import ExchangedToken
from litellm.proxy.mcp_server.outbound_credentials.types import (
ClientAuth,
CredError,
IdJagConfig,
IdJagSubjectSource,
ServerSpec,
)
from litellm.proxy._types import LiteLLM_MCPServerTable
from litellm.types.mcp import MCPAuth
from litellm.types.mcp_server.mcp_server_manager import MCPServer
@ -236,14 +236,14 @@ async def exchange_login_assertion_if_configured(
exchange when one of them presents a login refresh token. Nothing here can fail the login."""
if assertion is None:
return None
from litellm.proxy._experimental.mcp_server.db import get_all_mcp_servers # noqa: PLC0415 # import cycle
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # avoids import cycle
from litellm.proxy.mcp_server.db import get_all_mcp_servers # noqa: PLC0415 # import cycle
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # avoids import cycle
global_mcp_server_manager,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.adapter import ( # noqa: PLC0415 # import cycle
from litellm.proxy.mcp_server.outbound_credentials.adapter import ( # noqa: PLC0415 # import cycle
to_server_spec,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.token_endpoint import ( # noqa: PLC0415 # cycle
from litellm.proxy.mcp_server.outbound_credentials.token_endpoint import ( # noqa: PLC0415 # cycle
TokenEndpointClient,
)
from litellm.proxy.proxy_server import prisma_client # noqa: PLC0415 # runtime global

View file

@ -16,15 +16,15 @@ from functools import partial
from typing import TYPE_CHECKING, Final
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.oauth_identity_binding import credential_binding_matches
from litellm.proxy._experimental.mcp_server.outbound_credentials.authz_code_refresher import (
from litellm.proxy.mcp_server.oauth_identity_binding import credential_binding_matches
from litellm.proxy.mcp_server.outbound_credentials.authz_code_refresher import (
AuthorizationCodeRefresher,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.dual_cache_token_backend import (
from litellm.proxy.mcp_server.outbound_credentials.dual_cache_token_backend import (
AsyncCache,
DualCacheTokenCacheBackend,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
CachedOAuthTokenStore,
InvalidatableOAuthTokenStore,
OAuthToken,
@ -33,13 +33,13 @@ from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_sto
TokenCacheBackend,
TokenStoreUnavailable,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.runtime_refresh_coordinator import (
from litellm.proxy.mcp_server.outbound_credentials.runtime_refresh_coordinator import (
runtime_refresh_coordinator,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.token_cache_codec import (
from litellm.proxy.mcp_server.outbound_credentials.token_cache_codec import (
OAuthTokenCacheCodec,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.v2_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.v2_token_store import (
V2PerUserTokenStore,
)
@ -54,7 +54,7 @@ StoreBuilder = Callable[[ServerLookup], tuple[InvalidatableOAuthTokenStore, bool
async def _read_credential(user_id: str, server_id: str) -> Mapping[str, object] | None:
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415
get_user_oauth_credential,
)
from litellm.proxy.proxy_server import prisma_client # noqa: PLC0415
@ -74,7 +74,7 @@ async def _persist_credential(
identity_binding_proof: str | None = None,
cimd_client_id: str | None = None,
) -> None:
from litellm.proxy._experimental.mcp_server.db import ( # noqa: PLC0415
from litellm.proxy.mcp_server.db import ( # noqa: PLC0415
store_user_oauth_credential,
)
from litellm.proxy.proxy_server import prisma_client # noqa: PLC0415

View file

@ -11,7 +11,7 @@ from __future__ import annotations
from dataclasses import dataclass
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
OAuthToken,
)

View file

@ -21,7 +21,7 @@ from dataclasses import KW_ONLY, dataclass
from typing import Final, Protocol
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.outbound_credentials.redis_refresh_coordinator import (
from litellm.proxy.mcp_server.outbound_credentials.redis_refresh_coordinator import (
LockAcquisition,
)

View file

@ -28,7 +28,7 @@ from dataclasses import KW_ONLY, dataclass
from enum import Enum
from typing import Final, Protocol
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
OAuthToken,
)

View file

@ -30,28 +30,28 @@ import httpx2
from typing_extensions import assert_never
from litellm._logging import verbose_proxy_logger
from litellm.proxy._experimental.mcp_server.outbound_credentials.client_credentials import (
from litellm.proxy.mcp_server.outbound_credentials.client_credentials import (
ClientCredentialsBearerAuth,
ClientCredentialsTokenSource,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.httpx_auth import (
from litellm.proxy.mcp_server.outbound_credentials.httpx_auth import (
NoOpAuth,
StaticHeaderAuth,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
OAuthToken,
OAuthTokenStore,
TokenStoreUnavailable,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import (
from litellm.proxy.mcp_server.outbound_credentials.result import (
Error,
Ok,
Result,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_refresher import (
from litellm.proxy.mcp_server.outbound_credentials.sso_assertion_refresher import (
default_sso_assertion_store,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_store import (
from litellm.proxy.mcp_server.outbound_credentials.sso_assertion_store import (
AssertionStoreUnavailable,
SSOAssertionStore,
SSOIdentityAssertion,
@ -59,15 +59,15 @@ from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_s
exchanged_refresh_token_issued_for,
login_refresh_token_expired,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.token_endpoint import (
from litellm.proxy.mcp_server.outbound_credentials.token_endpoint import (
ExchangedToken,
ExchangedTokenCache,
TokenEndpointClient,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.token_exchanger import (
from litellm.proxy.mcp_server.outbound_credentials.token_exchanger import (
TokenExchanger,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import (
from litellm.proxy.mcp_server.outbound_credentials.types import (
ApiKeyConfig,
AuthorizationCodeConfig,
AuthResolution,

View file

@ -14,13 +14,13 @@ from __future__ import annotations
from typing import Final
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
RefreshCoordinator,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.redis_distributed_lock import (
from litellm.proxy.mcp_server.outbound_credentials.redis_distributed_lock import (
RedisDistributedLock,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.redis_refresh_coordinator import (
from litellm.proxy.mcp_server.outbound_credentials.redis_refresh_coordinator import (
RedisRefreshCoordinator,
)

View file

@ -22,7 +22,7 @@ from typing import Final, Literal, TypeAlias
from pydantic import ConfigDict, Field, SecretStr, ValidationError
from litellm.proxy._experimental.mcp_server.outbound_credentials.session_token import (
from litellm.proxy.mcp_server.outbound_credentials.session_token import (
AsymmetricSessionKeys,
OpenedSessionToken,
SessionExpired,

View file

@ -58,22 +58,22 @@ from litellm.exceptions import Timeout
from litellm.llms.custom_httpx.http_handler import (
get_async_httpx_client, # pyright: ignore[reportUnknownVariableType] # litellm http handler is untyped
)
from litellm.proxy._experimental.mcp_server.auth.token_endpoint_auth import (
from litellm.proxy.mcp_server.auth.token_endpoint_auth import (
build_token_endpoint_client_auth,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
InProcessRefreshCoordinator,
RefreshCoordinator,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import (
from litellm.proxy.mcp_server.outbound_credentials.result import (
Error,
Ok,
Result,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.runtime_refresh_coordinator import (
from litellm.proxy.mcp_server.outbound_credentials.runtime_refresh_coordinator import (
runtime_refresh_coordinator,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.sso_assertion_store import (
from litellm.proxy.mcp_server.outbound_credentials.sso_assertion_store import (
AssertionStoreUnavailable,
DbSSOAssertionStore,
SSOAssertionStore,

View file

@ -294,7 +294,7 @@ async def ema_assertion_retention_enabled() -> bool:
snapshot of the DB state that can be stale both ways (a server added on another pod would
silently drop the write, one removed on another pod would keep retaining bearer material),
and a gate guarding a shared-DB write must judge against that storage's authority."""
from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # avoids import cycle
from litellm.proxy.mcp_server.mcp_server_manager import ( # noqa: PLC0415 # avoids import cycle
global_mcp_server_manager,
)
from litellm.proxy.proxy_server import prisma_client # noqa: PLC0415 # runtime global

View file

@ -14,7 +14,7 @@ from typing import Final
from pydantic import TypeAdapter, ValidationError
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
OAuthToken,
)

View file

@ -39,12 +39,12 @@ from litellm.exceptions import Timeout
from litellm.llms.custom_httpx.http_handler import (
get_async_httpx_client, # pyright: ignore[reportUnknownVariableType] # litellm http handler is untyped
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import (
from litellm.proxy.mcp_server.outbound_credentials.result import (
Error,
Ok,
Result,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import (
from litellm.proxy.mcp_server.outbound_credentials.types import (
ClientAuth,
ClientSecretAuth,
CredError,

View file

@ -21,10 +21,10 @@ from litellm.constants import (
MCP_OAUTH2_TOKEN_EXPIRY_BUFFER_SECONDS,
MCP_TOKEN_EXCHANGE_CACHE_MAX_SIZE,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
InMemoryTokenCacheBackend,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.token_exchanger import (
from litellm.proxy.mcp_server.outbound_credentials.token_exchanger import (
OboTokenExchanger,
SubjectTokenRejected,
TokenExchangeClientError,

View file

@ -27,22 +27,22 @@ from typing import Final, Literal, Protocol
from typing_extensions import assert_never
from litellm._logging import verbose_logger
from litellm.proxy._experimental.mcp_server.auth.token_endpoint_auth import (
from litellm.proxy.mcp_server.auth.token_endpoint_auth import (
build_token_endpoint_client_auth,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
InMemoryTokenCacheBackend,
InProcessRefreshCoordinator,
OAuthToken,
RefreshCoordinator,
TokenCacheBackend,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import (
from litellm.proxy.mcp_server.outbound_credentials.result import (
Error,
Ok,
Result,
)
from litellm.proxy._experimental.mcp_server.outbound_credentials.types import (
from litellm.proxy.mcp_server.outbound_credentials.types import (
CredError,
ServerSpec,
TokenExchangeConfig,

View file

@ -35,7 +35,7 @@ from expression import case, tag, tagged_union
from pydantic import ConfigDict, Field, SecretStr, field_validator
from typing_extensions import assert_never
from litellm.proxy._experimental.mcp_server.outbound_credentials.result import (
from litellm.proxy.mcp_server.outbound_credentials.result import (
Error,
Ok,
Result,

View file

@ -14,7 +14,7 @@ from collections.abc import Awaitable, Callable, Mapping
from datetime import datetime, timezone
from typing import Final
from litellm.proxy._experimental.mcp_server.outbound_credentials.oauth_token_store import (
from litellm.proxy.mcp_server.outbound_credentials.oauth_token_store import (
OAuthToken,
)

Some files were not shown because too many files have changed in this diff Show more