mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-29 06:33:28 +00:00
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:
parent
0657ed46cf
commit
0a1dbc0fb4
295 changed files with 4954 additions and 4799 deletions
54
.github/workflows/test-unit.yml
vendored
54
.github/workflows/test-unit.yml
vendored
|
|
@ -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
2
.gitignore
vendored
|
|
@ -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
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
53
litellm/litellm_core_utils/deprecated_package.py
Normal file
53
litellm/litellm_core_utils/deprecated_package.py
Normal 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)
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
8
litellm/mcp_client/__init__.py
Normal file
8
litellm/mcp_client/__init__.py
Normal 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"]
|
||||
|
|
@ -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)
|
||||
4
litellm/proxy/_experimental/mcp_server/__init__.py
Normal file
4
litellm/proxy/_experimental/mcp_server/__init__.py
Normal 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)
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 []
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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(
|
||||
|
|
@ -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):
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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 = {
|
||||
|
|
@ -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 "
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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[
|
||||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -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:
|
||||
|
|
@ -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):
|
||||
|
|
@ -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()
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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):
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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
Loading…
Add table
Reference in a new issue