Spaces:
Running
Running
Merge pull request #802 from jlowin/deprecation-setting
Browse files- src/fastmcp/__init__.py +6 -0
- src/fastmcp/client/transports.py +7 -5
- src/fastmcp/prompts/prompt_manager.py +6 -5
- src/fastmcp/resources/resource_manager.py +12 -10
- src/fastmcp/server/context.py +10 -8
- src/fastmcp/server/openapi.py +19 -15
- src/fastmcp/server/server.py +95 -80
- src/fastmcp/settings.py +20 -7
- src/fastmcp/tools/tool_manager.py +6 -5
- tests/deprecated/test_deprecated.py +23 -0
- tests/deprecated/test_settings.py +22 -14
src/fastmcp/__init__.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
"""FastMCP - An ergonomic MCP interface."""
|
| 2 |
|
|
|
|
| 3 |
from importlib.metadata import version
|
| 4 |
from fastmcp.settings import Settings
|
| 5 |
|
|
@@ -22,3 +23,8 @@ __all__ = [
|
|
| 22 |
"settings",
|
| 23 |
"Image",
|
| 24 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
"""FastMCP - An ergonomic MCP interface."""
|
| 2 |
|
| 3 |
+
import warnings
|
| 4 |
from importlib.metadata import version
|
| 5 |
from fastmcp.settings import Settings
|
| 6 |
|
|
|
|
| 23 |
"settings",
|
| 24 |
"Image",
|
| 25 |
]
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
# ensure deprecation warnings are displayedby default
|
| 29 |
+
if settings.deprecation_warnings:
|
| 30 |
+
warnings.simplefilter("default", DeprecationWarning)
|
src/fastmcp/client/transports.py
CHANGED
|
@@ -20,6 +20,7 @@ from mcp.shared.memory import create_client_server_memory_streams
|
|
| 20 |
from pydantic import AnyUrl
|
| 21 |
from typing_extensions import Unpack
|
| 22 |
|
|
|
|
| 23 |
from fastmcp.client.auth.bearer import BearerAuth
|
| 24 |
from fastmcp.client.auth.oauth import OAuth
|
| 25 |
from fastmcp.server.dependencies import get_http_headers
|
|
@@ -109,11 +110,12 @@ class WSTransport(ClientTransport):
|
|
| 109 |
|
| 110 |
def __init__(self, url: str | AnyUrl):
|
| 111 |
# we never really used this transport, so it can be removed at any time
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
|
|
|
| 117 |
if isinstance(url, AnyUrl):
|
| 118 |
url = str(url)
|
| 119 |
if not isinstance(url, str) or not url.startswith("ws"):
|
|
|
|
| 20 |
from pydantic import AnyUrl
|
| 21 |
from typing_extensions import Unpack
|
| 22 |
|
| 23 |
+
import fastmcp
|
| 24 |
from fastmcp.client.auth.bearer import BearerAuth
|
| 25 |
from fastmcp.client.auth.oauth import OAuth
|
| 26 |
from fastmcp.server.dependencies import get_http_headers
|
|
|
|
| 110 |
|
| 111 |
def __init__(self, url: str | AnyUrl):
|
| 112 |
# we never really used this transport, so it can be removed at any time
|
| 113 |
+
if fastmcp.settings.deprecation_warnings:
|
| 114 |
+
warnings.warn(
|
| 115 |
+
"WSTransport is a deprecated MCP transport and will be removed in a future version. Use StreamableHttpTransport instead.",
|
| 116 |
+
DeprecationWarning,
|
| 117 |
+
stacklevel=2,
|
| 118 |
+
)
|
| 119 |
if isinstance(url, AnyUrl):
|
| 120 |
url = str(url)
|
| 121 |
if not isinstance(url, str) or not url.startswith("ws"):
|
src/fastmcp/prompts/prompt_manager.py
CHANGED
|
@@ -60,11 +60,12 @@ class PromptManager:
|
|
| 60 |
) -> FunctionPrompt:
|
| 61 |
"""Create a prompt from a function."""
|
| 62 |
# deprecated in 2.7.0
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
|
|
|
| 68 |
prompt = FunctionPrompt.from_function(
|
| 69 |
fn, name=name, description=description, tags=tags
|
| 70 |
)
|
|
|
|
| 60 |
) -> FunctionPrompt:
|
| 61 |
"""Create a prompt from a function."""
|
| 62 |
# deprecated in 2.7.0
|
| 63 |
+
if settings.deprecation_warnings:
|
| 64 |
+
warnings.warn(
|
| 65 |
+
"PromptManager.add_prompt_from_fn() is deprecated. Use Prompt.from_function() and call add_prompt() instead.",
|
| 66 |
+
DeprecationWarning,
|
| 67 |
+
stacklevel=2,
|
| 68 |
+
)
|
| 69 |
prompt = FunctionPrompt.from_function(
|
| 70 |
fn, name=name, description=description, tags=tags
|
| 71 |
)
|
src/fastmcp/resources/resource_manager.py
CHANGED
|
@@ -123,11 +123,12 @@ class ResourceManager:
|
|
| 123 |
returns the existing resource.
|
| 124 |
"""
|
| 125 |
# deprecated in 2.7.0
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
|
|
|
| 131 |
resource = Resource.from_function(
|
| 132 |
fn=fn,
|
| 133 |
uri=uri,
|
|
@@ -180,11 +181,12 @@ class ResourceManager:
|
|
| 180 |
) -> ResourceTemplate:
|
| 181 |
"""Create a template from a function."""
|
| 182 |
# deprecated in 2.7.0
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
|
|
|
| 188 |
template = ResourceTemplate.from_function(
|
| 189 |
fn,
|
| 190 |
uri_template=uri_template,
|
|
|
|
| 123 |
returns the existing resource.
|
| 124 |
"""
|
| 125 |
# deprecated in 2.7.0
|
| 126 |
+
if settings.deprecation_warnings:
|
| 127 |
+
warnings.warn(
|
| 128 |
+
"add_resource_from_fn is deprecated. Use Resource.from_function() and call add_resource() instead.",
|
| 129 |
+
DeprecationWarning,
|
| 130 |
+
stacklevel=2,
|
| 131 |
+
)
|
| 132 |
resource = Resource.from_function(
|
| 133 |
fn=fn,
|
| 134 |
uri=uri,
|
|
|
|
| 181 |
) -> ResourceTemplate:
|
| 182 |
"""Create a template from a function."""
|
| 183 |
# deprecated in 2.7.0
|
| 184 |
+
if settings.deprecation_warnings:
|
| 185 |
+
warnings.warn(
|
| 186 |
+
"add_template_from_fn is deprecated. Use ResourceTemplate.from_function() and call add_template() instead.",
|
| 187 |
+
DeprecationWarning,
|
| 188 |
+
stacklevel=2,
|
| 189 |
+
)
|
| 190 |
template = ResourceTemplate.from_function(
|
| 191 |
fn,
|
| 192 |
uri_template=uri_template,
|
src/fastmcp/server/context.py
CHANGED
|
@@ -22,6 +22,7 @@ from pydantic.networks import AnyUrl
|
|
| 22 |
from starlette.requests import Request
|
| 23 |
|
| 24 |
import fastmcp.server.dependencies
|
|
|
|
| 25 |
from fastmcp.server.server import FastMCP
|
| 26 |
from fastmcp.utilities.logging import get_logger
|
| 27 |
|
|
@@ -242,14 +243,15 @@ class Context:
|
|
| 242 |
def get_http_request(self) -> Request:
|
| 243 |
"""Get the active starlette request."""
|
| 244 |
|
| 245 |
-
#
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
|
|
|
| 253 |
|
| 254 |
return fastmcp.server.dependencies.get_http_request()
|
| 255 |
|
|
|
|
| 22 |
from starlette.requests import Request
|
| 23 |
|
| 24 |
import fastmcp.server.dependencies
|
| 25 |
+
from fastmcp import settings
|
| 26 |
from fastmcp.server.server import FastMCP
|
| 27 |
from fastmcp.utilities.logging import get_logger
|
| 28 |
|
|
|
|
| 243 |
def get_http_request(self) -> Request:
|
| 244 |
"""Get the active starlette request."""
|
| 245 |
|
| 246 |
+
# Deprecated in 2.2.11
|
| 247 |
+
if settings.deprecation_warnings:
|
| 248 |
+
warnings.warn(
|
| 249 |
+
"Context.get_http_request() is deprecated and will be removed in a future version. "
|
| 250 |
+
"Use get_http_request() from fastmcp.server.dependencies instead. "
|
| 251 |
+
"See https://gofastmcp.com/patterns/http-requests for more details.",
|
| 252 |
+
DeprecationWarning,
|
| 253 |
+
stacklevel=2,
|
| 254 |
+
)
|
| 255 |
|
| 256 |
return fastmcp.server.dependencies.get_http_request()
|
| 257 |
|
src/fastmcp/server/openapi.py
CHANGED
|
@@ -16,6 +16,7 @@ import httpx
|
|
| 16 |
from mcp.types import EmbeddedResource, ImageContent, TextContent, ToolAnnotations
|
| 17 |
from pydantic.networks import AnyUrl
|
| 18 |
|
|
|
|
| 19 |
from fastmcp.exceptions import ToolError
|
| 20 |
from fastmcp.resources import Resource, ResourceTemplate
|
| 21 |
from fastmcp.server.dependencies import get_http_headers
|
|
@@ -129,27 +130,30 @@ class RouteMap:
|
|
| 129 |
"""Validate and process the route map after initialization."""
|
| 130 |
# Handle backward compatibility for route_type, deprecated in 2.5.0
|
| 131 |
if self.mcp_type is None and self.route_type is not None:
|
| 132 |
-
|
| 133 |
-
"The 'route_type' parameter is deprecated and will be removed in a future version. "
|
| 134 |
-
"Use 'mcp_type' instead with the appropriate MCPType value.",
|
| 135 |
-
DeprecationWarning,
|
| 136 |
-
stacklevel=2,
|
| 137 |
-
)
|
| 138 |
-
if isinstance(self.route_type, RouteType):
|
| 139 |
warnings.warn(
|
| 140 |
-
"The
|
| 141 |
-
"Use
|
| 142 |
DeprecationWarning,
|
| 143 |
stacklevel=2,
|
| 144 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
# Check for the deprecated IGNORE value
|
| 146 |
if self.route_type == RouteType.IGNORE:
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
|
|
|
| 153 |
|
| 154 |
# Convert from RouteType to MCPType if needed
|
| 155 |
if isinstance(self.route_type, RouteType):
|
|
|
|
| 16 |
from mcp.types import EmbeddedResource, ImageContent, TextContent, ToolAnnotations
|
| 17 |
from pydantic.networks import AnyUrl
|
| 18 |
|
| 19 |
+
import fastmcp
|
| 20 |
from fastmcp.exceptions import ToolError
|
| 21 |
from fastmcp.resources import Resource, ResourceTemplate
|
| 22 |
from fastmcp.server.dependencies import get_http_headers
|
|
|
|
| 130 |
"""Validate and process the route map after initialization."""
|
| 131 |
# Handle backward compatibility for route_type, deprecated in 2.5.0
|
| 132 |
if self.mcp_type is None and self.route_type is not None:
|
| 133 |
+
if fastmcp.settings.deprecation_warnings:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
warnings.warn(
|
| 135 |
+
"The 'route_type' parameter is deprecated and will be removed in a future version. "
|
| 136 |
+
"Use 'mcp_type' instead with the appropriate MCPType value.",
|
| 137 |
DeprecationWarning,
|
| 138 |
stacklevel=2,
|
| 139 |
)
|
| 140 |
+
if isinstance(self.route_type, RouteType):
|
| 141 |
+
if fastmcp.settings.deprecation_warnings:
|
| 142 |
+
warnings.warn(
|
| 143 |
+
"The RouteType class is deprecated and will be removed in a future version. "
|
| 144 |
+
"Use MCPType instead.",
|
| 145 |
+
DeprecationWarning,
|
| 146 |
+
stacklevel=2,
|
| 147 |
+
)
|
| 148 |
# Check for the deprecated IGNORE value
|
| 149 |
if self.route_type == RouteType.IGNORE:
|
| 150 |
+
if fastmcp.settings.deprecation_warnings:
|
| 151 |
+
warnings.warn(
|
| 152 |
+
"RouteType.IGNORE is deprecated and will be removed in a future version. "
|
| 153 |
+
"Use MCPType.EXCLUDE instead.",
|
| 154 |
+
DeprecationWarning,
|
| 155 |
+
stacklevel=2,
|
| 156 |
+
)
|
| 157 |
|
| 158 |
# Convert from RouteType to MCPType if needed
|
| 159 |
if isinstance(self.route_type, RouteType):
|
src/fastmcp/server/server.py
CHANGED
|
@@ -242,11 +242,12 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 242 |
]:
|
| 243 |
if arg is not None:
|
| 244 |
# Deprecated in 2.8.0
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
|
|
|
| 250 |
deprecated_settings[name] = arg
|
| 251 |
|
| 252 |
combined_settings = fastmcp.settings.model_dump() | deprecated_settings
|
|
@@ -254,11 +255,13 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 254 |
|
| 255 |
@property
|
| 256 |
def settings(self) -> Settings:
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
|
|
|
|
|
|
| 262 |
return self._deprecated_settings
|
| 263 |
|
| 264 |
@property
|
|
@@ -865,11 +868,12 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 865 |
tags: Optional set of tags for categorizing the resource
|
| 866 |
"""
|
| 867 |
# deprecated since 2.7.0
|
| 868 |
-
|
| 869 |
-
|
| 870 |
-
|
| 871 |
-
|
| 872 |
-
|
|
|
|
| 873 |
self._resource_manager.add_resource_or_template_from_fn(
|
| 874 |
fn=fn,
|
| 875 |
uri=uri,
|
|
@@ -1233,13 +1237,14 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 1233 |
"""Run the server using SSE transport."""
|
| 1234 |
|
| 1235 |
# Deprecated since 2.3.2
|
| 1236 |
-
|
| 1237 |
-
|
| 1238 |
-
|
| 1239 |
-
|
| 1240 |
-
|
| 1241 |
-
|
| 1242 |
-
|
|
|
|
| 1243 |
await self.run_http_async(
|
| 1244 |
transport="sse",
|
| 1245 |
host=host,
|
|
@@ -1264,12 +1269,13 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 1264 |
middleware: A list of middleware to apply to the app
|
| 1265 |
"""
|
| 1266 |
# Deprecated since 2.3.2
|
| 1267 |
-
|
| 1268 |
-
|
| 1269 |
-
|
| 1270 |
-
|
| 1271 |
-
|
| 1272 |
-
|
|
|
|
| 1273 |
return create_sse_app(
|
| 1274 |
server=self,
|
| 1275 |
message_path=message_path or self._deprecated_settings.message_path,
|
|
@@ -1292,11 +1298,12 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 1292 |
middleware: A list of middleware to apply to the app
|
| 1293 |
"""
|
| 1294 |
# Deprecated since 2.3.2
|
| 1295 |
-
|
| 1296 |
-
|
| 1297 |
-
|
| 1298 |
-
|
| 1299 |
-
|
|
|
|
| 1300 |
return self.http_app(path=path, middleware=middleware)
|
| 1301 |
|
| 1302 |
def http_app(
|
|
@@ -1349,12 +1356,13 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 1349 |
uvicorn_config: dict[str, Any] | None = None,
|
| 1350 |
) -> None:
|
| 1351 |
# Deprecated since 2.3.2
|
| 1352 |
-
|
| 1353 |
-
|
| 1354 |
-
|
| 1355 |
-
|
| 1356 |
-
|
| 1357 |
-
|
|
|
|
| 1358 |
await self.run_http_async(
|
| 1359 |
transport="streamable-http",
|
| 1360 |
host=host,
|
|
@@ -1422,30 +1430,33 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 1422 |
|
| 1423 |
if tool_separator is not None:
|
| 1424 |
# Deprecated since 2.4.0
|
| 1425 |
-
|
| 1426 |
-
|
| 1427 |
-
|
| 1428 |
-
|
| 1429 |
-
|
| 1430 |
-
|
|
|
|
| 1431 |
|
| 1432 |
if resource_separator is not None:
|
| 1433 |
# Deprecated since 2.4.0
|
| 1434 |
-
|
| 1435 |
-
|
| 1436 |
-
|
| 1437 |
-
|
| 1438 |
-
|
| 1439 |
-
|
|
|
|
| 1440 |
|
| 1441 |
if prompt_separator is not None:
|
| 1442 |
# Deprecated since 2.4.0
|
| 1443 |
-
|
| 1444 |
-
|
| 1445 |
-
|
| 1446 |
-
|
| 1447 |
-
|
| 1448 |
-
|
|
|
|
| 1449 |
|
| 1450 |
# if as_proxy is not specified and the server has a custom lifespan,
|
| 1451 |
# we should treat it as a proxy
|
|
@@ -1507,30 +1518,33 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 1507 |
"""
|
| 1508 |
if tool_separator is not None:
|
| 1509 |
# Deprecated since 2.4.0
|
| 1510 |
-
|
| 1511 |
-
|
| 1512 |
-
|
| 1513 |
-
|
| 1514 |
-
|
| 1515 |
-
|
|
|
|
| 1516 |
|
| 1517 |
if resource_separator is not None:
|
| 1518 |
# Deprecated since 2.4.0
|
| 1519 |
-
|
| 1520 |
-
|
| 1521 |
-
|
| 1522 |
-
|
| 1523 |
-
|
| 1524 |
-
|
|
|
|
| 1525 |
|
| 1526 |
if prompt_separator is not None:
|
| 1527 |
# Deprecated since 2.4.0
|
| 1528 |
-
|
| 1529 |
-
|
| 1530 |
-
|
| 1531 |
-
|
| 1532 |
-
|
| 1533 |
-
|
|
|
|
| 1534 |
|
| 1535 |
# Import tools from the mounted server
|
| 1536 |
tool_prefix = f"{prefix}_"
|
|
@@ -1666,11 +1680,12 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 1666 |
Create a FastMCP proxy server from a FastMCP client.
|
| 1667 |
"""
|
| 1668 |
# Deprecated since 2.3.5
|
| 1669 |
-
|
| 1670 |
-
|
| 1671 |
-
|
| 1672 |
-
|
| 1673 |
-
|
|
|
|
| 1674 |
|
| 1675 |
return cls.as_proxy(client, **settings)
|
| 1676 |
|
|
|
|
| 242 |
]:
|
| 243 |
if arg is not None:
|
| 244 |
# Deprecated in 2.8.0
|
| 245 |
+
if fastmcp.settings.deprecation_warnings:
|
| 246 |
+
warnings.warn(
|
| 247 |
+
f"Providing `{name}` when creating a server is deprecated. Provide it when calling `run` or as a global setting instead.",
|
| 248 |
+
DeprecationWarning,
|
| 249 |
+
stacklevel=2,
|
| 250 |
+
)
|
| 251 |
deprecated_settings[name] = arg
|
| 252 |
|
| 253 |
combined_settings = fastmcp.settings.model_dump() | deprecated_settings
|
|
|
|
| 255 |
|
| 256 |
@property
|
| 257 |
def settings(self) -> Settings:
|
| 258 |
+
# Deprecated in 2.8.0
|
| 259 |
+
if fastmcp.settings.deprecation_warnings:
|
| 260 |
+
warnings.warn(
|
| 261 |
+
"Accessing `.settings` on a FastMCP instance is deprecated. Use the global `fastmcp.settings` instead.",
|
| 262 |
+
DeprecationWarning,
|
| 263 |
+
stacklevel=2,
|
| 264 |
+
)
|
| 265 |
return self._deprecated_settings
|
| 266 |
|
| 267 |
@property
|
|
|
|
| 868 |
tags: Optional set of tags for categorizing the resource
|
| 869 |
"""
|
| 870 |
# deprecated since 2.7.0
|
| 871 |
+
if fastmcp.settings.deprecation_warnings:
|
| 872 |
+
warnings.warn(
|
| 873 |
+
"The add_resource_fn method is deprecated. Use the resource decorator instead.",
|
| 874 |
+
DeprecationWarning,
|
| 875 |
+
stacklevel=2,
|
| 876 |
+
)
|
| 877 |
self._resource_manager.add_resource_or_template_from_fn(
|
| 878 |
fn=fn,
|
| 879 |
uri=uri,
|
|
|
|
| 1237 |
"""Run the server using SSE transport."""
|
| 1238 |
|
| 1239 |
# Deprecated since 2.3.2
|
| 1240 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1241 |
+
warnings.warn(
|
| 1242 |
+
"The run_sse_async method is deprecated (as of 2.3.2). Use run_http_async for a "
|
| 1243 |
+
"modern (non-SSE) alternative, or create an SSE app with "
|
| 1244 |
+
"`fastmcp.server.http.create_sse_app` and run it directly.",
|
| 1245 |
+
DeprecationWarning,
|
| 1246 |
+
stacklevel=2,
|
| 1247 |
+
)
|
| 1248 |
await self.run_http_async(
|
| 1249 |
transport="sse",
|
| 1250 |
host=host,
|
|
|
|
| 1269 |
middleware: A list of middleware to apply to the app
|
| 1270 |
"""
|
| 1271 |
# Deprecated since 2.3.2
|
| 1272 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1273 |
+
warnings.warn(
|
| 1274 |
+
"The sse_app method is deprecated (as of 2.3.2). Use http_app as a modern (non-SSE) "
|
| 1275 |
+
"alternative, or call `fastmcp.server.http.create_sse_app` directly.",
|
| 1276 |
+
DeprecationWarning,
|
| 1277 |
+
stacklevel=2,
|
| 1278 |
+
)
|
| 1279 |
return create_sse_app(
|
| 1280 |
server=self,
|
| 1281 |
message_path=message_path or self._deprecated_settings.message_path,
|
|
|
|
| 1298 |
middleware: A list of middleware to apply to the app
|
| 1299 |
"""
|
| 1300 |
# Deprecated since 2.3.2
|
| 1301 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1302 |
+
warnings.warn(
|
| 1303 |
+
"The streamable_http_app method is deprecated (as of 2.3.2). Use http_app() instead.",
|
| 1304 |
+
DeprecationWarning,
|
| 1305 |
+
stacklevel=2,
|
| 1306 |
+
)
|
| 1307 |
return self.http_app(path=path, middleware=middleware)
|
| 1308 |
|
| 1309 |
def http_app(
|
|
|
|
| 1356 |
uvicorn_config: dict[str, Any] | None = None,
|
| 1357 |
) -> None:
|
| 1358 |
# Deprecated since 2.3.2
|
| 1359 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1360 |
+
warnings.warn(
|
| 1361 |
+
"The run_streamable_http_async method is deprecated (as of 2.3.2). "
|
| 1362 |
+
"Use run_http_async instead.",
|
| 1363 |
+
DeprecationWarning,
|
| 1364 |
+
stacklevel=2,
|
| 1365 |
+
)
|
| 1366 |
await self.run_http_async(
|
| 1367 |
transport="streamable-http",
|
| 1368 |
host=host,
|
|
|
|
| 1430 |
|
| 1431 |
if tool_separator is not None:
|
| 1432 |
# Deprecated since 2.4.0
|
| 1433 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1434 |
+
warnings.warn(
|
| 1435 |
+
"The tool_separator parameter is deprecated and will be removed in a future version. "
|
| 1436 |
+
"Tools are now prefixed using 'prefix_toolname' format.",
|
| 1437 |
+
DeprecationWarning,
|
| 1438 |
+
stacklevel=2,
|
| 1439 |
+
)
|
| 1440 |
|
| 1441 |
if resource_separator is not None:
|
| 1442 |
# Deprecated since 2.4.0
|
| 1443 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1444 |
+
warnings.warn(
|
| 1445 |
+
"The resource_separator parameter is deprecated and ignored. "
|
| 1446 |
+
"Resource prefixes are now added using the protocol://prefix/path format.",
|
| 1447 |
+
DeprecationWarning,
|
| 1448 |
+
stacklevel=2,
|
| 1449 |
+
)
|
| 1450 |
|
| 1451 |
if prompt_separator is not None:
|
| 1452 |
# Deprecated since 2.4.0
|
| 1453 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1454 |
+
warnings.warn(
|
| 1455 |
+
"The prompt_separator parameter is deprecated and will be removed in a future version. "
|
| 1456 |
+
"Prompts are now prefixed using 'prefix_promptname' format.",
|
| 1457 |
+
DeprecationWarning,
|
| 1458 |
+
stacklevel=2,
|
| 1459 |
+
)
|
| 1460 |
|
| 1461 |
# if as_proxy is not specified and the server has a custom lifespan,
|
| 1462 |
# we should treat it as a proxy
|
|
|
|
| 1518 |
"""
|
| 1519 |
if tool_separator is not None:
|
| 1520 |
# Deprecated since 2.4.0
|
| 1521 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1522 |
+
warnings.warn(
|
| 1523 |
+
"The tool_separator parameter is deprecated and will be removed in a future version. "
|
| 1524 |
+
"Tools are now prefixed using 'prefix_toolname' format.",
|
| 1525 |
+
DeprecationWarning,
|
| 1526 |
+
stacklevel=2,
|
| 1527 |
+
)
|
| 1528 |
|
| 1529 |
if resource_separator is not None:
|
| 1530 |
# Deprecated since 2.4.0
|
| 1531 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1532 |
+
warnings.warn(
|
| 1533 |
+
"The resource_separator parameter is deprecated and ignored. "
|
| 1534 |
+
"Resource prefixes are now added using the protocol://prefix/path format.",
|
| 1535 |
+
DeprecationWarning,
|
| 1536 |
+
stacklevel=2,
|
| 1537 |
+
)
|
| 1538 |
|
| 1539 |
if prompt_separator is not None:
|
| 1540 |
# Deprecated since 2.4.0
|
| 1541 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1542 |
+
warnings.warn(
|
| 1543 |
+
"The prompt_separator parameter is deprecated and will be removed in a future version. "
|
| 1544 |
+
"Prompts are now prefixed using 'prefix_promptname' format.",
|
| 1545 |
+
DeprecationWarning,
|
| 1546 |
+
stacklevel=2,
|
| 1547 |
+
)
|
| 1548 |
|
| 1549 |
# Import tools from the mounted server
|
| 1550 |
tool_prefix = f"{prefix}_"
|
|
|
|
| 1680 |
Create a FastMCP proxy server from a FastMCP client.
|
| 1681 |
"""
|
| 1682 |
# Deprecated since 2.3.5
|
| 1683 |
+
if fastmcp.settings.deprecation_warnings:
|
| 1684 |
+
warnings.warn(
|
| 1685 |
+
"FastMCP.from_client() is deprecated; use FastMCP.as_proxy() instead.",
|
| 1686 |
+
DeprecationWarning,
|
| 1687 |
+
stacklevel=2,
|
| 1688 |
+
)
|
| 1689 |
|
| 1690 |
return cls.as_proxy(client, **settings)
|
| 1691 |
|
src/fastmcp/settings.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
from __future__ import annotations as _annotations
|
| 2 |
|
| 3 |
import inspect
|
| 4 |
-
import warnings
|
| 5 |
from pathlib import Path
|
| 6 |
from typing import Annotated, Any, Literal
|
| 7 |
|
|
@@ -15,6 +14,10 @@ from pydantic_settings import (
|
|
| 15 |
)
|
| 16 |
from typing_extensions import Self
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
LOG_LEVEL = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
| 19 |
|
| 20 |
DuplicateBehavior = Literal["warn", "error", "replace", "ignore"]
|
|
@@ -39,10 +42,8 @@ class ExtendedEnvSettingsSource(EnvSettingsSource):
|
|
| 39 |
if env_val is not None:
|
| 40 |
if prefix == "FASTMCP_SERVER_":
|
| 41 |
# Deprecated in 2.8.0
|
| 42 |
-
|
| 43 |
"Using `FASTMCP_SERVER_` environment variables is deprecated. Use `FASTMCP_` instead.",
|
| 44 |
-
DeprecationWarning,
|
| 45 |
-
stacklevel=2,
|
| 46 |
)
|
| 47 |
return env_val, field_key, value_is_complex
|
| 48 |
|
|
@@ -89,10 +90,8 @@ class Settings(BaseSettings):
|
|
| 89 |
which accessed fastmcp.settings.settings
|
| 90 |
"""
|
| 91 |
# Deprecated in 2.8.0
|
| 92 |
-
|
| 93 |
"Using fastmcp.settings.settings is deprecated. Use fastmcp.settings instead.",
|
| 94 |
-
DeprecationWarning,
|
| 95 |
-
stacklevel=2,
|
| 96 |
)
|
| 97 |
return self
|
| 98 |
|
|
@@ -111,6 +110,20 @@ class Settings(BaseSettings):
|
|
| 111 |
),
|
| 112 |
] = True
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
client_raise_first_exceptiongroup_error: Annotated[
|
| 115 |
bool,
|
| 116 |
Field(
|
|
|
|
| 1 |
from __future__ import annotations as _annotations
|
| 2 |
|
| 3 |
import inspect
|
|
|
|
| 4 |
from pathlib import Path
|
| 5 |
from typing import Annotated, Any, Literal
|
| 6 |
|
|
|
|
| 14 |
)
|
| 15 |
from typing_extensions import Self
|
| 16 |
|
| 17 |
+
from fastmcp.utilities.logging import get_logger
|
| 18 |
+
|
| 19 |
+
logger = get_logger(__name__)
|
| 20 |
+
|
| 21 |
LOG_LEVEL = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
| 22 |
|
| 23 |
DuplicateBehavior = Literal["warn", "error", "replace", "ignore"]
|
|
|
|
| 42 |
if env_val is not None:
|
| 43 |
if prefix == "FASTMCP_SERVER_":
|
| 44 |
# Deprecated in 2.8.0
|
| 45 |
+
logger.warning(
|
| 46 |
"Using `FASTMCP_SERVER_` environment variables is deprecated. Use `FASTMCP_` instead.",
|
|
|
|
|
|
|
| 47 |
)
|
| 48 |
return env_val, field_key, value_is_complex
|
| 49 |
|
|
|
|
| 90 |
which accessed fastmcp.settings.settings
|
| 91 |
"""
|
| 92 |
# Deprecated in 2.8.0
|
| 93 |
+
logger.warning(
|
| 94 |
"Using fastmcp.settings.settings is deprecated. Use fastmcp.settings instead.",
|
|
|
|
|
|
|
| 95 |
)
|
| 96 |
return self
|
| 97 |
|
|
|
|
| 110 |
),
|
| 111 |
] = True
|
| 112 |
|
| 113 |
+
deprecation_warnings: Annotated[
|
| 114 |
+
bool,
|
| 115 |
+
Field(
|
| 116 |
+
description=inspect.cleandoc(
|
| 117 |
+
"""
|
| 118 |
+
Whether to show deprecation warnings. You can completely reset
|
| 119 |
+
Python's warning behavior by running `warnings.resetwarnings()`.
|
| 120 |
+
Note this will NOT apply to deprecation warnings from the
|
| 121 |
+
settings class itself.
|
| 122 |
+
""",
|
| 123 |
+
)
|
| 124 |
+
),
|
| 125 |
+
] = True
|
| 126 |
+
|
| 127 |
client_raise_first_exceptiongroup_error: Annotated[
|
| 128 |
bool,
|
| 129 |
Field(
|
src/fastmcp/tools/tool_manager.py
CHANGED
|
@@ -71,11 +71,12 @@ class ToolManager:
|
|
| 71 |
) -> Tool:
|
| 72 |
"""Add a tool to the server."""
|
| 73 |
# deprecated in 2.7.0
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
|
|
|
| 79 |
tool = Tool.from_function(
|
| 80 |
fn,
|
| 81 |
name=name,
|
|
|
|
| 71 |
) -> Tool:
|
| 72 |
"""Add a tool to the server."""
|
| 73 |
# deprecated in 2.7.0
|
| 74 |
+
if settings.deprecation_warnings:
|
| 75 |
+
warnings.warn(
|
| 76 |
+
"ToolManager.add_tool_from_fn() is deprecated. Use Tool.from_function() and call add_tool() instead.",
|
| 77 |
+
DeprecationWarning,
|
| 78 |
+
stacklevel=2,
|
| 79 |
+
)
|
| 80 |
tool = Tool.from_function(
|
| 81 |
fn,
|
| 82 |
name=name,
|
tests/deprecated/test_deprecated.py
CHANGED
|
@@ -5,11 +5,34 @@ import pytest
|
|
| 5 |
from starlette.applications import Starlette
|
| 6 |
|
| 7 |
from fastmcp import Client, FastMCP
|
|
|
|
| 8 |
|
| 9 |
# reset deprecation warnings for this module
|
| 10 |
pytestmark = pytest.mark.filterwarnings("default::DeprecationWarning")
|
| 11 |
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
def test_sse_app_deprecation_warning():
|
| 14 |
"""Test that sse_app raises a deprecation warning."""
|
| 15 |
server = FastMCP("TestServer")
|
|
|
|
| 5 |
from starlette.applications import Starlette
|
| 6 |
|
| 7 |
from fastmcp import Client, FastMCP
|
| 8 |
+
from fastmcp.utilities.tests import temporary_settings
|
| 9 |
|
| 10 |
# reset deprecation warnings for this module
|
| 11 |
pytestmark = pytest.mark.filterwarnings("default::DeprecationWarning")
|
| 12 |
|
| 13 |
|
| 14 |
+
class TestDeprecationWarningsSetting:
|
| 15 |
+
def test_deprecation_warnings_setting_true(self):
|
| 16 |
+
with temporary_settings(deprecation_warnings=True):
|
| 17 |
+
with pytest.warns(DeprecationWarning) as recorded_warnings:
|
| 18 |
+
# will warn once for providing deprecated arg
|
| 19 |
+
mcp = FastMCP(host="1.2.3.4")
|
| 20 |
+
# will warn once for accessing deprecated property
|
| 21 |
+
mcp.settings
|
| 22 |
+
|
| 23 |
+
assert len(recorded_warnings) == 2
|
| 24 |
+
|
| 25 |
+
def test_deprecation_warnings_setting_false(self):
|
| 26 |
+
with temporary_settings(deprecation_warnings=False):
|
| 27 |
+
# will error if a warning is raised
|
| 28 |
+
with warnings.catch_warnings():
|
| 29 |
+
warnings.simplefilter("error")
|
| 30 |
+
# will warn once for providing deprecated arg
|
| 31 |
+
mcp = FastMCP(host="1.2.3.4")
|
| 32 |
+
# will warn once for accessing deprecated property
|
| 33 |
+
mcp.settings
|
| 34 |
+
|
| 35 |
+
|
| 36 |
def test_sse_app_deprecation_warning():
|
| 37 |
"""Test that sse_app raises a deprecation warning."""
|
| 38 |
server = FastMCP("TestServer")
|
tests/deprecated/test_settings.py
CHANGED
|
@@ -305,7 +305,7 @@ class TestDeprecatedServerInitKwargs:
|
|
| 305 |
class TestDeprecatedEnvironmentVariables:
|
| 306 |
"""Test deprecated environment variable prefixes."""
|
| 307 |
|
| 308 |
-
def test_fastmcp_server_env_var_deprecation_warning(self):
|
| 309 |
"""Test that FASTMCP_SERVER_ environment variables emit deprecation warnings."""
|
| 310 |
env_var_name = "FASTMCP_SERVER_HOST"
|
| 311 |
original_value = os.environ.get(env_var_name)
|
|
@@ -313,11 +313,15 @@ class TestDeprecatedEnvironmentVariables:
|
|
| 313 |
try:
|
| 314 |
os.environ[env_var_name] = "192.168.1.1"
|
| 315 |
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
|
| 322 |
# Verify the setting is still applied
|
| 323 |
assert settings.host == "192.168.1.1"
|
|
@@ -333,16 +337,20 @@ class TestDeprecatedEnvironmentVariables:
|
|
| 333 |
class TestDeprecatedSettingsProperty:
|
| 334 |
"""Test deprecated settings property access."""
|
| 335 |
|
| 336 |
-
def test_settings_property_deprecation_warning(self):
|
| 337 |
-
"""Test that accessing fastmcp.settings.settings
|
| 338 |
from fastmcp import settings
|
| 339 |
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
|
| 347 |
# Verify it still returns the same settings object
|
| 348 |
assert deprecated_settings is settings
|
|
|
|
| 305 |
class TestDeprecatedEnvironmentVariables:
|
| 306 |
"""Test deprecated environment variable prefixes."""
|
| 307 |
|
| 308 |
+
def test_fastmcp_server_env_var_deprecation_warning(self, caplog):
|
| 309 |
"""Test that FASTMCP_SERVER_ environment variables emit deprecation warnings."""
|
| 310 |
env_var_name = "FASTMCP_SERVER_HOST"
|
| 311 |
original_value = os.environ.get(env_var_name)
|
|
|
|
| 313 |
try:
|
| 314 |
os.environ[env_var_name] = "192.168.1.1"
|
| 315 |
|
| 316 |
+
settings = Settings()
|
| 317 |
+
|
| 318 |
+
# Check that a warning was logged
|
| 319 |
+
assert any(
|
| 320 |
+
"Using `FASTMCP_SERVER_` environment variables is deprecated. Use `FASTMCP_` instead."
|
| 321 |
+
in record.message
|
| 322 |
+
for record in caplog.records
|
| 323 |
+
if record.levelname == "WARNING"
|
| 324 |
+
)
|
| 325 |
|
| 326 |
# Verify the setting is still applied
|
| 327 |
assert settings.host == "192.168.1.1"
|
|
|
|
| 337 |
class TestDeprecatedSettingsProperty:
|
| 338 |
"""Test deprecated settings property access."""
|
| 339 |
|
| 340 |
+
def test_settings_property_deprecation_warning(self, caplog):
|
| 341 |
+
"""Test that accessing fastmcp.settings.settings logs a deprecation warning."""
|
| 342 |
from fastmcp import settings
|
| 343 |
|
| 344 |
+
# Access the deprecated property
|
| 345 |
+
deprecated_settings = settings.settings
|
| 346 |
+
|
| 347 |
+
# Check that a warning was logged
|
| 348 |
+
assert any(
|
| 349 |
+
"Using fastmcp.settings.settings is deprecated. Use fastmcp.settings instead."
|
| 350 |
+
in record.message
|
| 351 |
+
for record in caplog.records
|
| 352 |
+
if record.levelname == "WARNING"
|
| 353 |
+
)
|
| 354 |
|
| 355 |
# Verify it still returns the same settings object
|
| 356 |
assert deprecated_settings is settings
|