mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-16 23:41:43 +00:00
feat(mcp/v2): MCPServerManagerV2 skeleton + flag-gated injection
Step 6a of the egress cutover. MCPServerManagerV2 subclasses v1's MCPServerManager with no overrides yet, so behavior is identical. The composition root selects it via _make_global_mcp_server_manager() when LITELLM_USE_V2_MCP_EGRESS is set (lazy import avoids the subclass import cycle); flag-off stays v1 exactly. Verified at startup in both flag states. The per-server egress overrides (UpstreamConnection + resolve()) land in 6b/6c.
This commit is contained in:
parent
b7aa83140f
commit
6edba3f272
3 changed files with 63 additions and 1 deletions
|
|
@ -4513,4 +4513,19 @@ class MCPServerManager:
|
|||
return [server for server in results if server is not None]
|
||||
|
||||
|
||||
global_mcp_server_manager: MCPServerManager = MCPServerManager()
|
||||
def _make_global_mcp_server_manager() -> MCPServerManager:
|
||||
"""Pick the egress manager: v2 (UpstreamConnection-backed) when LITELLM_USE_V2_MCP_EGRESS is
|
||||
set, else v1. The v2 import is lazy so it can subclass MCPServerManager without an import
|
||||
cycle, and flag-off never touches the v2 module."""
|
||||
from litellm.proxy._experimental.mcp_server.v2_egress import v2_egress_enabled
|
||||
|
||||
if v2_egress_enabled():
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager_v2 import (
|
||||
MCPServerManagerV2,
|
||||
)
|
||||
|
||||
return MCPServerManagerV2()
|
||||
return MCPServerManager()
|
||||
|
||||
|
||||
global_mcp_server_manager: MCPServerManager = _make_global_mcp_server_manager()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
"""v2-owned MCP egress manager (the cutover seam).
|
||||
|
||||
``MCPServerManagerV2`` subclasses v1's ``MCPServerManager`` and, in later steps, overrides the
|
||||
per-server egress methods (``_get_tools_from_server``, ``call_tool``, the prompt/resource ops) to
|
||||
route through the v2 ``UpstreamConnection`` + ``resolve()`` instead of ``_create_mcp_client``.
|
||||
Registry, RBAC, cross-server aggregation, namespacing, and static-header resolution are inherited
|
||||
from v1 unchanged. It is injected at the composition root when ``LITELLM_USE_V2_MCP_EGRESS`` is set
|
||||
(see ``mcp_server_manager._make_global_mcp_server_manager``); flag-off keeps v1 exactly.
|
||||
|
||||
Step 6a lands the skeleton only: no overrides, so behavior is identical to v1. The egress overrides
|
||||
land in 6b/6c.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager import MCPServerManager
|
||||
|
||||
|
||||
class MCPServerManagerV2(MCPServerManager):
|
||||
"""v2 egress manager; see the module docstring. No overrides yet (step 6a)."""
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
"""Tests for the v2 egress manager factory + skeleton (step 6a)."""
|
||||
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
|
||||
MCPServerManager,
|
||||
_make_global_mcp_server_manager,
|
||||
)
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager_v2 import (
|
||||
MCPServerManagerV2,
|
||||
)
|
||||
|
||||
FLAG = "LITELLM_USE_V2_MCP_EGRESS"
|
||||
|
||||
|
||||
def test_v2_is_a_manager_subclass():
|
||||
assert issubclass(MCPServerManagerV2, MCPServerManager)
|
||||
|
||||
|
||||
def test_factory_returns_v2_when_egress_enabled(monkeypatch):
|
||||
monkeypatch.setenv(FLAG, "true")
|
||||
assert isinstance(_make_global_mcp_server_manager(), MCPServerManagerV2)
|
||||
|
||||
|
||||
def test_factory_returns_v1_when_egress_disabled(monkeypatch):
|
||||
monkeypatch.delenv(FLAG, raising=False)
|
||||
manager = _make_global_mcp_server_manager()
|
||||
assert isinstance(manager, MCPServerManager)
|
||||
assert not isinstance(manager, MCPServerManagerV2)
|
||||
Loading…
Add table
Reference in a new issue