-
Notifications
You must be signed in to change notification settings - Fork 78
Expand file tree
/
Copy path_compatibility.py
More file actions
69 lines (55 loc) · 2.59 KB
/
Copy path_compatibility.py
File metadata and controls
69 lines (55 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# Portions of this package are derived from MCPCat/mcpcat-typescript-sdk
# Copyright (c) 2025 MCPcat
# Licensed under the MIT License: https://github.com/MCPCat/mcpcat-typescript-sdk/blob/main/LICENSE
"""Detect which kind of MCP server was passed to ``instrument()``.
Every probe is import-tolerant: the classes live at different paths per MCP SDK
major (``mcp.server.fastmcp.FastMCP`` on 1.x, ``mcp.server.mcpserver.MCPServer``
on 2.x), so a probe whose class doesn't exist on the installed major answers
``False`` instead of raising — an unconditional import here is exactly what
would crash ``instrument()`` on the other major.
"""
from __future__ import annotations
from typing import Any
def is_fastmcp(server: Any) -> bool:
"""The MCP SDK 1.x high-level server (``mcp.server.fastmcp.FastMCP``).
The module was renamed in 2.x, so this is False whenever mcp>=2 is installed."""
try:
from mcp.server.fastmcp import FastMCP
except ImportError:
return False
return isinstance(server, FastMCP)
def is_mcpserver(server: Any) -> bool:
"""The MCP SDK 2.x high-level server (``mcp.server.mcpserver.MCPServer``,
the renamed FastMCP). False whenever mcp<2 is installed."""
try:
from mcp.server.mcpserver import MCPServer
except ImportError:
return False
return isinstance(server, MCPServer)
def is_fastmcp_v2(server: Any) -> bool:
"""jlowin's standalone FastMCP 2.0 (``fastmcp.FastMCP``), a separate package
from the official SDK. Returns False if ``fastmcp`` isn't installed."""
try:
from fastmcp import FastMCP as FastMCPv2
except ImportError:
return False
return isinstance(server, FastMCPv2)
def is_low_level_server(server: Any) -> bool:
"""The low-level ``mcp.server.lowlevel.Server`` — the import path is the
same on both majors; use :func:`uses_v2_handler_registry` to tell which
handler seam it carries."""
try:
from mcp.server.lowlevel import Server as LowLevelServer
except ImportError:
return False
return isinstance(server, LowLevelServer)
def uses_v2_handler_registry(server: Any) -> bool:
"""Which major's handler seam a low-level server carries, decided by shape
rather than package version (a la posthog-js ADR-0005): 1.x exposes the
public ``request_handlers`` dict keyed by request class; 2.x replaced it
with ``add_request_handler``/``get_request_handler`` keyed by method string."""
if hasattr(server, "add_request_handler") and hasattr(
server, "get_request_handler"
):
return True
return not hasattr(server, "request_handlers")