fastmcp 2.8.0__py3-none-any.whl → 2.8.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastmcp/__init__.py +28 -2
- fastmcp/client/client.py +3 -4
- fastmcp/client/sampling.py +5 -9
- fastmcp/client/transports.py +7 -5
- fastmcp/prompts/prompt.py +3 -3
- fastmcp/prompts/prompt_manager.py +6 -5
- fastmcp/resources/resource_manager.py +12 -10
- fastmcp/server/auth/providers/in_memory.py +2 -2
- fastmcp/server/context.py +12 -10
- fastmcp/server/openapi.py +22 -19
- fastmcp/server/proxy.py +3 -7
- fastmcp/server/server.py +112 -85
- fastmcp/settings.py +20 -7
- fastmcp/tools/tool.py +11 -10
- fastmcp/tools/tool_manager.py +9 -9
- fastmcp/tools/tool_transform.py +9 -5
- fastmcp/utilities/types.py +82 -5
- {fastmcp-2.8.0.dist-info → fastmcp-2.8.1.dist-info}/METADATA +46 -26
- {fastmcp-2.8.0.dist-info → fastmcp-2.8.1.dist-info}/RECORD +22 -22
- {fastmcp-2.8.0.dist-info → fastmcp-2.8.1.dist-info}/WHEEL +0 -0
- {fastmcp-2.8.0.dist-info → fastmcp-2.8.1.dist-info}/entry_points.txt +0 -0
- {fastmcp-2.8.0.dist-info → fastmcp-2.8.1.dist-info}/licenses/LICENSE +0 -0
fastmcp/__init__.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""FastMCP - An ergonomic MCP interface."""
|
|
2
2
|
|
|
3
|
+
import warnings
|
|
3
4
|
from importlib.metadata import version
|
|
4
5
|
from fastmcp.settings import Settings
|
|
5
6
|
|
|
@@ -10,15 +11,40 @@ from fastmcp.server.context import Context
|
|
|
10
11
|
import fastmcp.server
|
|
11
12
|
|
|
12
13
|
from fastmcp.client import Client
|
|
13
|
-
from fastmcp.utilities.types import Image
|
|
14
14
|
from . import client
|
|
15
15
|
|
|
16
16
|
__version__ = version("fastmcp")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# ensure deprecation warnings are displayed by default
|
|
20
|
+
if settings.deprecation_warnings:
|
|
21
|
+
warnings.simplefilter("default", DeprecationWarning)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def __getattr__(name: str):
|
|
25
|
+
"""
|
|
26
|
+
Used to deprecate the module-level Image class; can be removed once it is no longer imported to root.
|
|
27
|
+
"""
|
|
28
|
+
if name == "Image":
|
|
29
|
+
# Deprecated in 2.8.1
|
|
30
|
+
if settings.deprecation_warnings:
|
|
31
|
+
warnings.warn(
|
|
32
|
+
"The top-level `fastmcp.Image` import is deprecated "
|
|
33
|
+
"and will be removed in a future version. "
|
|
34
|
+
"Please use `fastmcp.utilities.types.Image` instead.",
|
|
35
|
+
DeprecationWarning,
|
|
36
|
+
stacklevel=2,
|
|
37
|
+
)
|
|
38
|
+
from fastmcp.utilities.types import Image
|
|
39
|
+
|
|
40
|
+
return Image
|
|
41
|
+
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
42
|
+
|
|
43
|
+
|
|
17
44
|
__all__ = [
|
|
18
45
|
"FastMCP",
|
|
19
46
|
"Context",
|
|
20
47
|
"client",
|
|
21
48
|
"Client",
|
|
22
49
|
"settings",
|
|
23
|
-
"Image",
|
|
24
50
|
]
|
fastmcp/client/client.py
CHANGED
|
@@ -29,6 +29,7 @@ from fastmcp.exceptions import ToolError
|
|
|
29
29
|
from fastmcp.server import FastMCP
|
|
30
30
|
from fastmcp.utilities.exceptions import get_catch_handlers
|
|
31
31
|
from fastmcp.utilities.mcp_config import MCPConfig
|
|
32
|
+
from fastmcp.utilities.types import MCPContent
|
|
32
33
|
|
|
33
34
|
from .transports import (
|
|
34
35
|
ClientTransportT,
|
|
@@ -658,9 +659,7 @@ class Client(Generic[ClientTransportT]):
|
|
|
658
659
|
arguments: dict[str, Any] | None = None,
|
|
659
660
|
timeout: datetime.timedelta | float | int | None = None,
|
|
660
661
|
progress_handler: ProgressHandler | None = None,
|
|
661
|
-
) -> list[
|
|
662
|
-
mcp.types.TextContent | mcp.types.ImageContent | mcp.types.EmbeddedResource
|
|
663
|
-
]:
|
|
662
|
+
) -> list[MCPContent]:
|
|
664
663
|
"""Call a tool on the server.
|
|
665
664
|
|
|
666
665
|
Unlike call_tool_mcp, this method raises a ToolError if the tool call results in an error.
|
|
@@ -672,7 +671,7 @@ class Client(Generic[ClientTransportT]):
|
|
|
672
671
|
progress_handler (ProgressHandler | None, optional): The progress handler to use for the tool call. Defaults to None.
|
|
673
672
|
|
|
674
673
|
Returns:
|
|
675
|
-
list[mcp.types.TextContent | mcp.types.ImageContent | mcp.types.EmbeddedResource]:
|
|
674
|
+
list[mcp.types.TextContent | mcp.types.ImageContent | mcp.types.AudioContent | mcp.types.EmbeddedResource]:
|
|
676
675
|
The content returned by the tool.
|
|
677
676
|
|
|
678
677
|
Raises:
|
fastmcp/client/sampling.py
CHANGED
|
@@ -9,13 +9,7 @@ from mcp.shared.context import LifespanContextT, RequestContext
|
|
|
9
9
|
from mcp.types import CreateMessageRequestParams as SamplingParams
|
|
10
10
|
from mcp.types import SamplingMessage
|
|
11
11
|
|
|
12
|
-
__all__ = ["SamplingMessage", "SamplingParams", "
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class MessageResult(CreateMessageResult):
|
|
16
|
-
role: mcp.types.Role = "assistant"
|
|
17
|
-
content: mcp.types.TextContent | mcp.types.ImageContent
|
|
18
|
-
model: str = "client-model"
|
|
12
|
+
__all__ = ["SamplingMessage", "SamplingParams", "SamplingHandler"]
|
|
19
13
|
|
|
20
14
|
|
|
21
15
|
SamplingHandler: TypeAlias = Callable[
|
|
@@ -39,8 +33,10 @@ def create_sampling_callback(sampling_handler: SamplingHandler) -> SamplingFnT:
|
|
|
39
33
|
result = await result
|
|
40
34
|
|
|
41
35
|
if isinstance(result, str):
|
|
42
|
-
result =
|
|
43
|
-
|
|
36
|
+
result = CreateMessageResult(
|
|
37
|
+
role="assistant",
|
|
38
|
+
model="fastmcp-client",
|
|
39
|
+
content=mcp.types.TextContent(type="text", text=result),
|
|
44
40
|
)
|
|
45
41
|
return result
|
|
46
42
|
except Exception as e:
|
fastmcp/client/transports.py
CHANGED
|
@@ -20,6 +20,7 @@ from mcp.shared.memory import create_client_server_memory_streams
|
|
|
20
20
|
from pydantic import AnyUrl
|
|
21
21
|
from typing_extensions import Unpack
|
|
22
22
|
|
|
23
|
+
import fastmcp
|
|
23
24
|
from fastmcp.client.auth.bearer import BearerAuth
|
|
24
25
|
from fastmcp.client.auth.oauth import OAuth
|
|
25
26
|
from fastmcp.server.dependencies import get_http_headers
|
|
@@ -109,11 +110,12 @@ class WSTransport(ClientTransport):
|
|
|
109
110
|
|
|
110
111
|
def __init__(self, url: str | AnyUrl):
|
|
111
112
|
# we never really used this transport, so it can be removed at any time
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
+
)
|
|
117
119
|
if isinstance(url, AnyUrl):
|
|
118
120
|
url = str(url)
|
|
119
121
|
if not isinstance(url, str) or not url.startswith("ws"):
|
fastmcp/prompts/prompt.py
CHANGED
|
@@ -8,9 +8,9 @@ from collections.abc import Awaitable, Callable, Sequence
|
|
|
8
8
|
from typing import TYPE_CHECKING, Any
|
|
9
9
|
|
|
10
10
|
import pydantic_core
|
|
11
|
-
from mcp.types import EmbeddedResource, ImageContent, PromptMessage, Role, TextContent
|
|
12
11
|
from mcp.types import Prompt as MCPPrompt
|
|
13
12
|
from mcp.types import PromptArgument as MCPPromptArgument
|
|
13
|
+
from mcp.types import PromptMessage, Role, TextContent
|
|
14
14
|
from pydantic import Field, TypeAdapter, validate_call
|
|
15
15
|
|
|
16
16
|
from fastmcp.exceptions import PromptError
|
|
@@ -20,6 +20,7 @@ from fastmcp.utilities.json_schema import compress_schema
|
|
|
20
20
|
from fastmcp.utilities.logging import get_logger
|
|
21
21
|
from fastmcp.utilities.types import (
|
|
22
22
|
FastMCPBaseModel,
|
|
23
|
+
MCPContent,
|
|
23
24
|
find_kwarg_by_type,
|
|
24
25
|
get_cached_typeadapter,
|
|
25
26
|
)
|
|
@@ -27,13 +28,12 @@ from fastmcp.utilities.types import (
|
|
|
27
28
|
if TYPE_CHECKING:
|
|
28
29
|
pass
|
|
29
30
|
|
|
30
|
-
CONTENT_TYPES = TextContent | ImageContent | EmbeddedResource
|
|
31
31
|
|
|
32
32
|
logger = get_logger(__name__)
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
def Message(
|
|
36
|
-
content: str |
|
|
36
|
+
content: str | MCPContent, role: Role | None = None, **kwargs: Any
|
|
37
37
|
) -> PromptMessage:
|
|
38
38
|
"""A user-friendly constructor for PromptMessage."""
|
|
39
39
|
if isinstance(content, str):
|
|
@@ -60,11 +60,12 @@ class PromptManager:
|
|
|
60
60
|
) -> FunctionPrompt:
|
|
61
61
|
"""Create a prompt from a function."""
|
|
62
62
|
# deprecated in 2.7.0
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
+
)
|
|
68
69
|
prompt = FunctionPrompt.from_function(
|
|
69
70
|
fn, name=name, description=description, tags=tags
|
|
70
71
|
)
|
|
@@ -123,11 +123,12 @@ class ResourceManager:
|
|
|
123
123
|
returns the existing resource.
|
|
124
124
|
"""
|
|
125
125
|
# deprecated in 2.7.0
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
+
)
|
|
131
132
|
resource = Resource.from_function(
|
|
132
133
|
fn=fn,
|
|
133
134
|
uri=uri,
|
|
@@ -180,11 +181,12 @@ class ResourceManager:
|
|
|
180
181
|
) -> ResourceTemplate:
|
|
181
182
|
"""Create a template from a function."""
|
|
182
183
|
# deprecated in 2.7.0
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
+
)
|
|
188
190
|
template = ResourceTemplate.from_function(
|
|
189
191
|
fn,
|
|
190
192
|
uri_template=uri_template,
|
|
@@ -184,7 +184,7 @@ class InMemoryOAuthProvider(OAuthProvider):
|
|
|
184
184
|
|
|
185
185
|
return OAuthToken(
|
|
186
186
|
access_token=access_token_value,
|
|
187
|
-
token_type="
|
|
187
|
+
token_type="Bearer",
|
|
188
188
|
expires_in=DEFAULT_ACCESS_TOKEN_EXPIRY_SECONDS,
|
|
189
189
|
refresh_token=refresh_token_value,
|
|
190
190
|
scope=" ".join(authorization_code.scopes),
|
|
@@ -254,7 +254,7 @@ class InMemoryOAuthProvider(OAuthProvider):
|
|
|
254
254
|
|
|
255
255
|
return OAuthToken(
|
|
256
256
|
access_token=new_access_token_value,
|
|
257
|
-
token_type="
|
|
257
|
+
token_type="Bearer",
|
|
258
258
|
expires_in=DEFAULT_ACCESS_TOKEN_EXPIRY_SECONDS,
|
|
259
259
|
refresh_token=new_refresh_token_value,
|
|
260
260
|
scope=" ".join(scopes),
|
fastmcp/server/context.py
CHANGED
|
@@ -11,7 +11,6 @@ from mcp.server.lowlevel.helper_types import ReadResourceContents
|
|
|
11
11
|
from mcp.shared.context import RequestContext
|
|
12
12
|
from mcp.types import (
|
|
13
13
|
CreateMessageResult,
|
|
14
|
-
ImageContent,
|
|
15
14
|
ModelHint,
|
|
16
15
|
ModelPreferences,
|
|
17
16
|
Root,
|
|
@@ -22,8 +21,10 @@ from pydantic.networks import AnyUrl
|
|
|
22
21
|
from starlette.requests import Request
|
|
23
22
|
|
|
24
23
|
import fastmcp.server.dependencies
|
|
24
|
+
from fastmcp import settings
|
|
25
25
|
from fastmcp.server.server import FastMCP
|
|
26
26
|
from fastmcp.utilities.logging import get_logger
|
|
27
|
+
from fastmcp.utilities.types import MCPContent
|
|
27
28
|
|
|
28
29
|
logger = get_logger(__name__)
|
|
29
30
|
|
|
@@ -203,7 +204,7 @@ class Context:
|
|
|
203
204
|
temperature: float | None = None,
|
|
204
205
|
max_tokens: int | None = None,
|
|
205
206
|
model_preferences: ModelPreferences | str | list[str] | None = None,
|
|
206
|
-
) ->
|
|
207
|
+
) -> MCPContent:
|
|
207
208
|
"""
|
|
208
209
|
Send a sampling request to the client and await the response.
|
|
209
210
|
|
|
@@ -242,14 +243,15 @@ class Context:
|
|
|
242
243
|
def get_http_request(self) -> Request:
|
|
243
244
|
"""Get the active starlette request."""
|
|
244
245
|
|
|
245
|
-
#
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
+
)
|
|
253
255
|
|
|
254
256
|
return fastmcp.server.dependencies.get_http_request()
|
|
255
257
|
|
fastmcp/server/openapi.py
CHANGED
|
@@ -13,9 +13,10 @@ from re import Pattern
|
|
|
13
13
|
from typing import TYPE_CHECKING, Any, Literal
|
|
14
14
|
|
|
15
15
|
import httpx
|
|
16
|
-
from mcp.types import
|
|
16
|
+
from mcp.types import ToolAnnotations
|
|
17
17
|
from pydantic.networks import AnyUrl
|
|
18
18
|
|
|
19
|
+
import fastmcp
|
|
19
20
|
from fastmcp.exceptions import ToolError
|
|
20
21
|
from fastmcp.resources import Resource, ResourceTemplate
|
|
21
22
|
from fastmcp.server.dependencies import get_http_headers
|
|
@@ -28,6 +29,7 @@ from fastmcp.utilities.openapi import (
|
|
|
28
29
|
_combine_schemas,
|
|
29
30
|
format_description_with_responses,
|
|
30
31
|
)
|
|
32
|
+
from fastmcp.utilities.types import MCPContent
|
|
31
33
|
|
|
32
34
|
if TYPE_CHECKING:
|
|
33
35
|
from fastmcp.server import Context
|
|
@@ -129,27 +131,30 @@ class RouteMap:
|
|
|
129
131
|
"""Validate and process the route map after initialization."""
|
|
130
132
|
# Handle backward compatibility for route_type, deprecated in 2.5.0
|
|
131
133
|
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):
|
|
134
|
+
if fastmcp.settings.deprecation_warnings:
|
|
139
135
|
warnings.warn(
|
|
140
|
-
"The
|
|
141
|
-
"Use MCPType
|
|
136
|
+
"The 'route_type' parameter is deprecated and will be removed in a future version. "
|
|
137
|
+
"Use 'mcp_type' instead with the appropriate MCPType value.",
|
|
142
138
|
DeprecationWarning,
|
|
143
139
|
stacklevel=2,
|
|
144
140
|
)
|
|
141
|
+
if isinstance(self.route_type, RouteType):
|
|
142
|
+
if fastmcp.settings.deprecation_warnings:
|
|
143
|
+
warnings.warn(
|
|
144
|
+
"The RouteType class is deprecated and will be removed in a future version. "
|
|
145
|
+
"Use MCPType instead.",
|
|
146
|
+
DeprecationWarning,
|
|
147
|
+
stacklevel=2,
|
|
148
|
+
)
|
|
145
149
|
# Check for the deprecated IGNORE value
|
|
146
150
|
if self.route_type == RouteType.IGNORE:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
if fastmcp.settings.deprecation_warnings:
|
|
152
|
+
warnings.warn(
|
|
153
|
+
"RouteType.IGNORE is deprecated and will be removed in a future version. "
|
|
154
|
+
"Use MCPType.EXCLUDE instead.",
|
|
155
|
+
DeprecationWarning,
|
|
156
|
+
stacklevel=2,
|
|
157
|
+
)
|
|
153
158
|
|
|
154
159
|
# Convert from RouteType to MCPType if needed
|
|
155
160
|
if isinstance(self.route_type, RouteType):
|
|
@@ -250,9 +255,7 @@ class OpenAPITool(Tool):
|
|
|
250
255
|
"""Custom representation to prevent recursion errors when printing."""
|
|
251
256
|
return f"OpenAPITool(name={self.name!r}, method={self._route.method}, path={self._route.path})"
|
|
252
257
|
|
|
253
|
-
async def run(
|
|
254
|
-
self, arguments: dict[str, Any]
|
|
255
|
-
) -> list[TextContent | ImageContent | EmbeddedResource]:
|
|
258
|
+
async def run(self, arguments: dict[str, Any]) -> list[MCPContent]:
|
|
256
259
|
"""Execute the HTTP request based on the route configuration."""
|
|
257
260
|
|
|
258
261
|
# Prepare URL
|
fastmcp/server/proxy.py
CHANGED
|
@@ -9,10 +9,7 @@ from mcp.shared.exceptions import McpError
|
|
|
9
9
|
from mcp.types import (
|
|
10
10
|
METHOD_NOT_FOUND,
|
|
11
11
|
BlobResourceContents,
|
|
12
|
-
EmbeddedResource,
|
|
13
12
|
GetPromptResult,
|
|
14
|
-
ImageContent,
|
|
15
|
-
TextContent,
|
|
16
13
|
TextResourceContents,
|
|
17
14
|
)
|
|
18
15
|
from pydantic.networks import AnyUrl
|
|
@@ -25,6 +22,7 @@ from fastmcp.server.context import Context
|
|
|
25
22
|
from fastmcp.server.server import FastMCP
|
|
26
23
|
from fastmcp.tools.tool import Tool
|
|
27
24
|
from fastmcp.utilities.logging import get_logger
|
|
25
|
+
from fastmcp.utilities.types import MCPContent
|
|
28
26
|
|
|
29
27
|
if TYPE_CHECKING:
|
|
30
28
|
from fastmcp.server import Context
|
|
@@ -50,7 +48,7 @@ class ProxyTool(Tool):
|
|
|
50
48
|
self,
|
|
51
49
|
arguments: dict[str, Any],
|
|
52
50
|
context: Context | None = None,
|
|
53
|
-
) -> list[
|
|
51
|
+
) -> list[MCPContent]:
|
|
54
52
|
# the client context manager will swallow any exceptions inside a TaskGroup
|
|
55
53
|
# so we return the raw result and raise an exception ourselves
|
|
56
54
|
async with self._client:
|
|
@@ -254,9 +252,7 @@ class FastMCPProxy(FastMCP):
|
|
|
254
252
|
|
|
255
253
|
return prompts
|
|
256
254
|
|
|
257
|
-
async def _call_tool(
|
|
258
|
-
self, key: str, arguments: dict[str, Any]
|
|
259
|
-
) -> list[TextContent | ImageContent | EmbeddedResource]:
|
|
255
|
+
async def _call_tool(self, key: str, arguments: dict[str, Any]) -> list[MCPContent]:
|
|
260
256
|
try:
|
|
261
257
|
result = await super()._call_tool(key, arguments)
|
|
262
258
|
return result
|