fastmcp 2.14.4__py3-none-any.whl → 3.0.0b1__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/_vendor/__init__.py +1 -0
- fastmcp/_vendor/docket_di/README.md +7 -0
- fastmcp/_vendor/docket_di/__init__.py +163 -0
- fastmcp/cli/cli.py +112 -28
- fastmcp/cli/install/claude_code.py +1 -5
- fastmcp/cli/install/claude_desktop.py +1 -5
- fastmcp/cli/install/cursor.py +1 -5
- fastmcp/cli/install/gemini_cli.py +1 -5
- fastmcp/cli/install/mcp_json.py +1 -6
- fastmcp/cli/run.py +146 -5
- fastmcp/client/__init__.py +7 -9
- fastmcp/client/auth/oauth.py +18 -17
- fastmcp/client/client.py +100 -870
- fastmcp/client/elicitation.py +1 -1
- fastmcp/client/mixins/__init__.py +13 -0
- fastmcp/client/mixins/prompts.py +295 -0
- fastmcp/client/mixins/resources.py +325 -0
- fastmcp/client/mixins/task_management.py +157 -0
- fastmcp/client/mixins/tools.py +397 -0
- fastmcp/client/sampling/handlers/anthropic.py +2 -2
- fastmcp/client/sampling/handlers/openai.py +1 -1
- fastmcp/client/tasks.py +3 -3
- fastmcp/client/telemetry.py +47 -0
- fastmcp/client/transports/__init__.py +38 -0
- fastmcp/client/transports/base.py +82 -0
- fastmcp/client/transports/config.py +170 -0
- fastmcp/client/transports/http.py +145 -0
- fastmcp/client/transports/inference.py +154 -0
- fastmcp/client/transports/memory.py +90 -0
- fastmcp/client/transports/sse.py +89 -0
- fastmcp/client/transports/stdio.py +543 -0
- fastmcp/contrib/component_manager/README.md +4 -10
- fastmcp/contrib/component_manager/__init__.py +1 -2
- fastmcp/contrib/component_manager/component_manager.py +95 -160
- fastmcp/contrib/component_manager/example.py +1 -1
- fastmcp/contrib/mcp_mixin/example.py +4 -4
- fastmcp/contrib/mcp_mixin/mcp_mixin.py +11 -4
- fastmcp/decorators.py +41 -0
- fastmcp/dependencies.py +12 -1
- fastmcp/exceptions.py +4 -0
- fastmcp/experimental/server/openapi/__init__.py +18 -15
- fastmcp/mcp_config.py +13 -4
- fastmcp/prompts/__init__.py +6 -3
- fastmcp/prompts/function_prompt.py +465 -0
- fastmcp/prompts/prompt.py +321 -271
- fastmcp/resources/__init__.py +5 -3
- fastmcp/resources/function_resource.py +335 -0
- fastmcp/resources/resource.py +325 -115
- fastmcp/resources/template.py +215 -43
- fastmcp/resources/types.py +27 -12
- fastmcp/server/__init__.py +2 -2
- fastmcp/server/auth/__init__.py +14 -0
- fastmcp/server/auth/auth.py +30 -10
- fastmcp/server/auth/authorization.py +190 -0
- fastmcp/server/auth/oauth_proxy/__init__.py +14 -0
- fastmcp/server/auth/oauth_proxy/consent.py +361 -0
- fastmcp/server/auth/oauth_proxy/models.py +178 -0
- fastmcp/server/auth/{oauth_proxy.py → oauth_proxy/proxy.py} +24 -778
- fastmcp/server/auth/oauth_proxy/ui.py +277 -0
- fastmcp/server/auth/oidc_proxy.py +2 -2
- fastmcp/server/auth/providers/auth0.py +24 -94
- fastmcp/server/auth/providers/aws.py +26 -95
- fastmcp/server/auth/providers/azure.py +41 -129
- fastmcp/server/auth/providers/descope.py +18 -49
- fastmcp/server/auth/providers/discord.py +25 -86
- fastmcp/server/auth/providers/github.py +23 -87
- fastmcp/server/auth/providers/google.py +24 -87
- fastmcp/server/auth/providers/introspection.py +60 -79
- fastmcp/server/auth/providers/jwt.py +30 -67
- fastmcp/server/auth/providers/oci.py +47 -110
- fastmcp/server/auth/providers/scalekit.py +23 -61
- fastmcp/server/auth/providers/supabase.py +18 -47
- fastmcp/server/auth/providers/workos.py +34 -127
- fastmcp/server/context.py +372 -419
- fastmcp/server/dependencies.py +541 -251
- fastmcp/server/elicitation.py +20 -18
- fastmcp/server/event_store.py +3 -3
- fastmcp/server/http.py +16 -6
- fastmcp/server/lifespan.py +198 -0
- fastmcp/server/low_level.py +92 -2
- fastmcp/server/middleware/__init__.py +5 -1
- fastmcp/server/middleware/authorization.py +312 -0
- fastmcp/server/middleware/caching.py +101 -54
- fastmcp/server/middleware/middleware.py +6 -9
- fastmcp/server/middleware/ping.py +70 -0
- fastmcp/server/middleware/tool_injection.py +2 -2
- fastmcp/server/mixins/__init__.py +7 -0
- fastmcp/server/mixins/lifespan.py +217 -0
- fastmcp/server/mixins/mcp_operations.py +392 -0
- fastmcp/server/mixins/transport.py +342 -0
- fastmcp/server/openapi/__init__.py +41 -21
- fastmcp/server/openapi/components.py +16 -339
- fastmcp/server/openapi/routing.py +34 -118
- fastmcp/server/openapi/server.py +67 -392
- fastmcp/server/providers/__init__.py +71 -0
- fastmcp/server/providers/aggregate.py +261 -0
- fastmcp/server/providers/base.py +578 -0
- fastmcp/server/providers/fastmcp_provider.py +674 -0
- fastmcp/server/providers/filesystem.py +226 -0
- fastmcp/server/providers/filesystem_discovery.py +327 -0
- fastmcp/server/providers/local_provider/__init__.py +11 -0
- fastmcp/server/providers/local_provider/decorators/__init__.py +15 -0
- fastmcp/server/providers/local_provider/decorators/prompts.py +256 -0
- fastmcp/server/providers/local_provider/decorators/resources.py +240 -0
- fastmcp/server/providers/local_provider/decorators/tools.py +315 -0
- fastmcp/server/providers/local_provider/local_provider.py +465 -0
- fastmcp/server/providers/openapi/__init__.py +39 -0
- fastmcp/server/providers/openapi/components.py +332 -0
- fastmcp/server/providers/openapi/provider.py +405 -0
- fastmcp/server/providers/openapi/routing.py +109 -0
- fastmcp/server/providers/proxy.py +867 -0
- fastmcp/server/providers/skills/__init__.py +59 -0
- fastmcp/server/providers/skills/_common.py +101 -0
- fastmcp/server/providers/skills/claude_provider.py +44 -0
- fastmcp/server/providers/skills/directory_provider.py +153 -0
- fastmcp/server/providers/skills/skill_provider.py +432 -0
- fastmcp/server/providers/skills/vendor_providers.py +142 -0
- fastmcp/server/providers/wrapped_provider.py +140 -0
- fastmcp/server/proxy.py +34 -700
- fastmcp/server/sampling/run.py +341 -2
- fastmcp/server/sampling/sampling_tool.py +4 -3
- fastmcp/server/server.py +1214 -2171
- fastmcp/server/tasks/__init__.py +2 -1
- fastmcp/server/tasks/capabilities.py +13 -1
- fastmcp/server/tasks/config.py +66 -3
- fastmcp/server/tasks/handlers.py +65 -273
- fastmcp/server/tasks/keys.py +4 -6
- fastmcp/server/tasks/requests.py +474 -0
- fastmcp/server/tasks/routing.py +76 -0
- fastmcp/server/tasks/subscriptions.py +20 -11
- fastmcp/server/telemetry.py +131 -0
- fastmcp/server/transforms/__init__.py +244 -0
- fastmcp/server/transforms/namespace.py +193 -0
- fastmcp/server/transforms/prompts_as_tools.py +175 -0
- fastmcp/server/transforms/resources_as_tools.py +190 -0
- fastmcp/server/transforms/tool_transform.py +96 -0
- fastmcp/server/transforms/version_filter.py +124 -0
- fastmcp/server/transforms/visibility.py +526 -0
- fastmcp/settings.py +34 -96
- fastmcp/telemetry.py +122 -0
- fastmcp/tools/__init__.py +10 -3
- fastmcp/tools/function_parsing.py +201 -0
- fastmcp/tools/function_tool.py +467 -0
- fastmcp/tools/tool.py +215 -362
- fastmcp/tools/tool_transform.py +38 -21
- fastmcp/utilities/async_utils.py +69 -0
- fastmcp/utilities/components.py +152 -91
- fastmcp/utilities/inspect.py +8 -20
- fastmcp/utilities/json_schema.py +12 -5
- fastmcp/utilities/json_schema_type.py +17 -15
- fastmcp/utilities/lifespan.py +56 -0
- fastmcp/utilities/logging.py +12 -4
- fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +3 -3
- fastmcp/utilities/openapi/parser.py +3 -3
- fastmcp/utilities/pagination.py +80 -0
- fastmcp/utilities/skills.py +253 -0
- fastmcp/utilities/tests.py +0 -16
- fastmcp/utilities/timeout.py +47 -0
- fastmcp/utilities/types.py +1 -1
- fastmcp/utilities/versions.py +285 -0
- {fastmcp-2.14.4.dist-info → fastmcp-3.0.0b1.dist-info}/METADATA +8 -5
- fastmcp-3.0.0b1.dist-info/RECORD +228 -0
- fastmcp/client/transports.py +0 -1170
- fastmcp/contrib/component_manager/component_service.py +0 -209
- fastmcp/prompts/prompt_manager.py +0 -117
- fastmcp/resources/resource_manager.py +0 -338
- fastmcp/server/tasks/converters.py +0 -206
- fastmcp/server/tasks/protocol.py +0 -359
- fastmcp/tools/tool_manager.py +0 -170
- fastmcp/utilities/mcp_config.py +0 -56
- fastmcp-2.14.4.dist-info/RECORD +0 -161
- /fastmcp/server/{openapi → providers/openapi}/README.md +0 -0
- {fastmcp-2.14.4.dist-info → fastmcp-3.0.0b1.dist-info}/WHEEL +0 -0
- {fastmcp-2.14.4.dist-info → fastmcp-3.0.0b1.dist-info}/entry_points.txt +0 -0
- {fastmcp-2.14.4.dist-info → fastmcp-3.0.0b1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"""Tool decorator mixin for LocalProvider.
|
|
2
|
+
|
|
3
|
+
This module provides the ToolDecoratorMixin class that adds tool
|
|
4
|
+
registration functionality to LocalProvider.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import inspect
|
|
10
|
+
import warnings
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from functools import partial
|
|
13
|
+
from typing import TYPE_CHECKING, Any, Literal, overload
|
|
14
|
+
|
|
15
|
+
import mcp.types
|
|
16
|
+
from mcp.types import AnyFunction, ToolAnnotations
|
|
17
|
+
|
|
18
|
+
import fastmcp
|
|
19
|
+
from fastmcp.server.tasks.config import TaskConfig
|
|
20
|
+
from fastmcp.tools.function_tool import FunctionTool
|
|
21
|
+
from fastmcp.tools.tool import AuthCheckCallable, Tool
|
|
22
|
+
from fastmcp.utilities.types import NotSet, NotSetT
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from fastmcp.server.providers.local_provider import LocalProvider
|
|
26
|
+
from fastmcp.tools.tool import ToolResultSerializerType
|
|
27
|
+
|
|
28
|
+
DuplicateBehavior = Literal["error", "warn", "replace", "ignore"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ToolDecoratorMixin:
|
|
32
|
+
"""Mixin class providing tool decorator functionality for LocalProvider.
|
|
33
|
+
|
|
34
|
+
This mixin contains all methods related to:
|
|
35
|
+
- Tool registration via add_tool()
|
|
36
|
+
- Tool decorator (@provider.tool)
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def add_tool(self: LocalProvider, tool: Tool | Callable[..., Any]) -> Tool:
|
|
40
|
+
"""Add a tool to this provider's storage.
|
|
41
|
+
|
|
42
|
+
Accepts either a Tool object or a decorated function with __fastmcp__ metadata.
|
|
43
|
+
"""
|
|
44
|
+
enabled = True
|
|
45
|
+
if not isinstance(tool, Tool):
|
|
46
|
+
from fastmcp.decorators import get_fastmcp_meta
|
|
47
|
+
from fastmcp.tools.function_tool import ToolMeta
|
|
48
|
+
|
|
49
|
+
meta = get_fastmcp_meta(tool)
|
|
50
|
+
if meta is not None and isinstance(meta, ToolMeta):
|
|
51
|
+
resolved_task = meta.task if meta.task is not None else False
|
|
52
|
+
enabled = meta.enabled
|
|
53
|
+
tool = Tool.from_function(
|
|
54
|
+
tool,
|
|
55
|
+
name=meta.name,
|
|
56
|
+
version=meta.version,
|
|
57
|
+
title=meta.title,
|
|
58
|
+
description=meta.description,
|
|
59
|
+
icons=meta.icons,
|
|
60
|
+
tags=meta.tags,
|
|
61
|
+
output_schema=meta.output_schema,
|
|
62
|
+
annotations=meta.annotations,
|
|
63
|
+
meta=meta.meta,
|
|
64
|
+
task=resolved_task,
|
|
65
|
+
exclude_args=meta.exclude_args,
|
|
66
|
+
serializer=meta.serializer,
|
|
67
|
+
timeout=meta.timeout,
|
|
68
|
+
auth=meta.auth,
|
|
69
|
+
)
|
|
70
|
+
else:
|
|
71
|
+
tool = Tool.from_function(tool)
|
|
72
|
+
self._add_component(tool)
|
|
73
|
+
if not enabled:
|
|
74
|
+
self.disable(keys={tool.key})
|
|
75
|
+
return tool
|
|
76
|
+
|
|
77
|
+
@overload
|
|
78
|
+
def tool(
|
|
79
|
+
self: LocalProvider,
|
|
80
|
+
name_or_fn: AnyFunction,
|
|
81
|
+
*,
|
|
82
|
+
name: str | None = None,
|
|
83
|
+
version: str | int | None = None,
|
|
84
|
+
title: str | None = None,
|
|
85
|
+
description: str | None = None,
|
|
86
|
+
icons: list[mcp.types.Icon] | None = None,
|
|
87
|
+
tags: set[str] | None = None,
|
|
88
|
+
output_schema: dict[str, Any] | NotSetT | None = NotSet,
|
|
89
|
+
annotations: ToolAnnotations | dict[str, Any] | None = None,
|
|
90
|
+
exclude_args: list[str] | None = None,
|
|
91
|
+
meta: dict[str, Any] | None = None,
|
|
92
|
+
enabled: bool = True,
|
|
93
|
+
task: bool | TaskConfig | None = None,
|
|
94
|
+
serializer: ToolResultSerializerType | None = None, # Deprecated
|
|
95
|
+
timeout: float | None = None,
|
|
96
|
+
auth: AuthCheckCallable | list[AuthCheckCallable] | None = None,
|
|
97
|
+
) -> FunctionTool: ...
|
|
98
|
+
|
|
99
|
+
@overload
|
|
100
|
+
def tool(
|
|
101
|
+
self: LocalProvider,
|
|
102
|
+
name_or_fn: str | None = None,
|
|
103
|
+
*,
|
|
104
|
+
name: str | None = None,
|
|
105
|
+
version: str | int | None = None,
|
|
106
|
+
title: str | None = None,
|
|
107
|
+
description: str | None = None,
|
|
108
|
+
icons: list[mcp.types.Icon] | None = None,
|
|
109
|
+
tags: set[str] | None = None,
|
|
110
|
+
output_schema: dict[str, Any] | NotSetT | None = NotSet,
|
|
111
|
+
annotations: ToolAnnotations | dict[str, Any] | None = None,
|
|
112
|
+
exclude_args: list[str] | None = None,
|
|
113
|
+
meta: dict[str, Any] | None = None,
|
|
114
|
+
enabled: bool = True,
|
|
115
|
+
task: bool | TaskConfig | None = None,
|
|
116
|
+
serializer: ToolResultSerializerType | None = None, # Deprecated
|
|
117
|
+
timeout: float | None = None,
|
|
118
|
+
auth: AuthCheckCallable | list[AuthCheckCallable] | None = None,
|
|
119
|
+
) -> Callable[[AnyFunction], FunctionTool]: ...
|
|
120
|
+
|
|
121
|
+
# NOTE: This method mirrors fastmcp.tools.tool() but adds registration,
|
|
122
|
+
# the `enabled` param, and supports deprecated params (serializer, exclude_args).
|
|
123
|
+
# When deprecated params are removed, this should delegate to the standalone
|
|
124
|
+
# decorator to reduce duplication.
|
|
125
|
+
def tool(
|
|
126
|
+
self: LocalProvider,
|
|
127
|
+
name_or_fn: str | AnyFunction | None = None,
|
|
128
|
+
*,
|
|
129
|
+
name: str | None = None,
|
|
130
|
+
version: str | int | None = None,
|
|
131
|
+
title: str | None = None,
|
|
132
|
+
description: str | None = None,
|
|
133
|
+
icons: list[mcp.types.Icon] | None = None,
|
|
134
|
+
tags: set[str] | None = None,
|
|
135
|
+
output_schema: dict[str, Any] | NotSetT | None = NotSet,
|
|
136
|
+
annotations: ToolAnnotations | dict[str, Any] | None = None,
|
|
137
|
+
exclude_args: list[str] | None = None,
|
|
138
|
+
meta: dict[str, Any] | None = None,
|
|
139
|
+
enabled: bool = True,
|
|
140
|
+
task: bool | TaskConfig | None = None,
|
|
141
|
+
serializer: ToolResultSerializerType | None = None, # Deprecated
|
|
142
|
+
timeout: float | None = None,
|
|
143
|
+
auth: AuthCheckCallable | list[AuthCheckCallable] | None = None,
|
|
144
|
+
) -> (
|
|
145
|
+
Callable[[AnyFunction], FunctionTool]
|
|
146
|
+
| FunctionTool
|
|
147
|
+
| partial[Callable[[AnyFunction], FunctionTool] | FunctionTool]
|
|
148
|
+
):
|
|
149
|
+
"""Decorator to register a tool.
|
|
150
|
+
|
|
151
|
+
This decorator supports multiple calling patterns:
|
|
152
|
+
- @provider.tool (without parentheses)
|
|
153
|
+
- @provider.tool() (with empty parentheses)
|
|
154
|
+
- @provider.tool("custom_name") (with name as first argument)
|
|
155
|
+
- @provider.tool(name="custom_name") (with name as keyword argument)
|
|
156
|
+
- provider.tool(function, name="custom_name") (direct function call)
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
name_or_fn: Either a function (when used as @tool), a string name, or None
|
|
160
|
+
name: Optional name for the tool (keyword-only, alternative to name_or_fn)
|
|
161
|
+
title: Optional title for the tool
|
|
162
|
+
description: Optional description of what the tool does
|
|
163
|
+
icons: Optional icons for the tool
|
|
164
|
+
tags: Optional set of tags for categorizing the tool
|
|
165
|
+
output_schema: Optional JSON schema for the tool's output
|
|
166
|
+
annotations: Optional annotations about the tool's behavior
|
|
167
|
+
exclude_args: Optional list of argument names to exclude from the tool schema
|
|
168
|
+
meta: Optional meta information about the tool
|
|
169
|
+
enabled: Whether the tool is enabled (default True). If False, adds to blocklist.
|
|
170
|
+
task: Optional task configuration for background execution
|
|
171
|
+
serializer: Deprecated. Return ToolResult from your tools for full control over serialization.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
The registered FunctionTool or a decorator function.
|
|
175
|
+
|
|
176
|
+
Example:
|
|
177
|
+
```python
|
|
178
|
+
provider = LocalProvider()
|
|
179
|
+
|
|
180
|
+
@provider.tool
|
|
181
|
+
def greet(name: str) -> str:
|
|
182
|
+
return f"Hello, {name}!"
|
|
183
|
+
|
|
184
|
+
@provider.tool("custom_name")
|
|
185
|
+
def my_tool(x: int) -> str:
|
|
186
|
+
return str(x)
|
|
187
|
+
```
|
|
188
|
+
"""
|
|
189
|
+
if serializer is not None and fastmcp.settings.deprecation_warnings:
|
|
190
|
+
warnings.warn(
|
|
191
|
+
"The `serializer` parameter is deprecated. "
|
|
192
|
+
"Return ToolResult from your tools for full control over serialization. "
|
|
193
|
+
"See https://gofastmcp.com/servers/tools#custom-serialization for migration examples.",
|
|
194
|
+
DeprecationWarning,
|
|
195
|
+
stacklevel=2,
|
|
196
|
+
)
|
|
197
|
+
if isinstance(annotations, dict):
|
|
198
|
+
annotations = ToolAnnotations(**annotations)
|
|
199
|
+
|
|
200
|
+
if isinstance(name_or_fn, classmethod):
|
|
201
|
+
raise TypeError(
|
|
202
|
+
"To decorate a classmethod, use @classmethod above @tool. "
|
|
203
|
+
"See https://gofastmcp.com/servers/tools#using-with-methods"
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
def decorate_and_register(
|
|
207
|
+
fn: AnyFunction, tool_name: str | None
|
|
208
|
+
) -> FunctionTool | AnyFunction:
|
|
209
|
+
# Check for unbound method
|
|
210
|
+
try:
|
|
211
|
+
params = list(inspect.signature(fn).parameters.keys())
|
|
212
|
+
except (ValueError, TypeError):
|
|
213
|
+
params = []
|
|
214
|
+
if params and params[0] in ("self", "cls"):
|
|
215
|
+
fn_name = getattr(fn, "__name__", "function")
|
|
216
|
+
raise TypeError(
|
|
217
|
+
f"The function '{fn_name}' has '{params[0]}' as its first parameter. "
|
|
218
|
+
f"Use the standalone @tool decorator and register the bound method:\n\n"
|
|
219
|
+
f" from fastmcp.tools import tool\n\n"
|
|
220
|
+
f" class MyClass:\n"
|
|
221
|
+
f" @tool\n"
|
|
222
|
+
f" def {fn_name}(...):\n"
|
|
223
|
+
f" ...\n\n"
|
|
224
|
+
f" obj = MyClass()\n"
|
|
225
|
+
f" mcp.add_tool(obj.{fn_name})\n\n"
|
|
226
|
+
f"See https://gofastmcp.com/servers/tools#using-with-methods"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
resolved_task: bool | TaskConfig = task if task is not None else False
|
|
230
|
+
|
|
231
|
+
if fastmcp.settings.decorator_mode == "object":
|
|
232
|
+
tool_obj = Tool.from_function(
|
|
233
|
+
fn,
|
|
234
|
+
name=tool_name,
|
|
235
|
+
version=version,
|
|
236
|
+
title=title,
|
|
237
|
+
description=description,
|
|
238
|
+
icons=icons,
|
|
239
|
+
tags=tags,
|
|
240
|
+
output_schema=output_schema,
|
|
241
|
+
annotations=annotations,
|
|
242
|
+
exclude_args=exclude_args,
|
|
243
|
+
meta=meta,
|
|
244
|
+
serializer=serializer,
|
|
245
|
+
task=resolved_task,
|
|
246
|
+
timeout=timeout,
|
|
247
|
+
auth=auth,
|
|
248
|
+
)
|
|
249
|
+
self._add_component(tool_obj)
|
|
250
|
+
if not enabled:
|
|
251
|
+
self.disable(keys={tool_obj.key})
|
|
252
|
+
return tool_obj
|
|
253
|
+
else:
|
|
254
|
+
from fastmcp.tools.function_tool import ToolMeta
|
|
255
|
+
|
|
256
|
+
metadata = ToolMeta(
|
|
257
|
+
name=tool_name,
|
|
258
|
+
version=version,
|
|
259
|
+
title=title,
|
|
260
|
+
description=description,
|
|
261
|
+
icons=icons,
|
|
262
|
+
tags=tags,
|
|
263
|
+
output_schema=output_schema,
|
|
264
|
+
annotations=annotations,
|
|
265
|
+
meta=meta,
|
|
266
|
+
task=task,
|
|
267
|
+
exclude_args=exclude_args,
|
|
268
|
+
serializer=serializer,
|
|
269
|
+
timeout=timeout,
|
|
270
|
+
auth=auth,
|
|
271
|
+
enabled=enabled,
|
|
272
|
+
)
|
|
273
|
+
target = fn.__func__ if hasattr(fn, "__func__") else fn
|
|
274
|
+
target.__fastmcp__ = metadata # type: ignore[attr-defined]
|
|
275
|
+
tool_obj = self.add_tool(fn)
|
|
276
|
+
return fn
|
|
277
|
+
|
|
278
|
+
if inspect.isroutine(name_or_fn):
|
|
279
|
+
return decorate_and_register(name_or_fn, name)
|
|
280
|
+
|
|
281
|
+
elif isinstance(name_or_fn, str):
|
|
282
|
+
# Case 3: @tool("custom_name") - name passed as first argument
|
|
283
|
+
if name is not None:
|
|
284
|
+
raise TypeError(
|
|
285
|
+
"Cannot specify both a name as first argument and as keyword argument. "
|
|
286
|
+
f"Use either @tool('{name_or_fn}') or @tool(name='{name}'), not both."
|
|
287
|
+
)
|
|
288
|
+
tool_name = name_or_fn
|
|
289
|
+
elif name_or_fn is None:
|
|
290
|
+
# Case 4: @tool() or @tool(name="something") - use keyword name
|
|
291
|
+
tool_name = name
|
|
292
|
+
else:
|
|
293
|
+
raise TypeError(
|
|
294
|
+
f"First argument to @tool must be a function, string, or None, got {type(name_or_fn)}"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# Return partial for cases where we need to wait for the function
|
|
298
|
+
return partial(
|
|
299
|
+
self.tool,
|
|
300
|
+
name=tool_name,
|
|
301
|
+
version=version,
|
|
302
|
+
title=title,
|
|
303
|
+
description=description,
|
|
304
|
+
icons=icons,
|
|
305
|
+
tags=tags,
|
|
306
|
+
output_schema=output_schema,
|
|
307
|
+
annotations=annotations,
|
|
308
|
+
exclude_args=exclude_args,
|
|
309
|
+
meta=meta,
|
|
310
|
+
enabled=enabled,
|
|
311
|
+
task=task,
|
|
312
|
+
serializer=serializer,
|
|
313
|
+
timeout=timeout,
|
|
314
|
+
auth=auth,
|
|
315
|
+
)
|