fastmcp 0.4.0__py3-none-any.whl → 0.4.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/py.typed ADDED
File without changes
fastmcp/server.py CHANGED
@@ -6,7 +6,7 @@ import inspect
6
6
  import json
7
7
  import re
8
8
  from itertools import chain
9
- from typing import Any, Callable, Dict, Literal, Sequence
9
+ from typing import Any, Callable, Dict, Literal, Sequence, TypeVar, ParamSpec
10
10
 
11
11
  import pydantic_core
12
12
  from pydantic import Field
@@ -40,6 +40,7 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
40
40
 
41
41
  from fastmcp.exceptions import ResourceError
42
42
  from fastmcp.prompts import Prompt, PromptManager
43
+ from fastmcp.prompts.base import PromptResult
43
44
  from fastmcp.resources import FunctionResource, Resource, ResourceManager
44
45
  from fastmcp.tools import ToolManager
45
46
  from fastmcp.utilities.logging import configure_logging, get_logger
@@ -47,6 +48,10 @@ from fastmcp.utilities.types import Image
47
48
 
48
49
  logger = get_logger(__name__)
49
50
 
51
+ P = ParamSpec("P")
52
+ R = TypeVar("R")
53
+ R_PromptResult = TypeVar("R_PromptResult", bound=PromptResult)
54
+
50
55
 
51
56
  class Settings(BaseSettings):
52
57
  """FastMCP server settings.
@@ -222,7 +227,9 @@ class FastMCP:
222
227
  """
223
228
  self._tool_manager.add_tool(fn, name=name, description=description)
224
229
 
225
- def tool(self, name: str | None = None, description: str | None = None) -> Callable:
230
+ def tool(
231
+ self, name: str | None = None, description: str | None = None
232
+ ) -> Callable[[Callable[P, R]], Callable[P, R]]:
226
233
  """Decorator to register a tool.
227
234
 
228
235
  Tools can optionally request a Context object by adding a parameter with the Context type annotation.
@@ -254,7 +261,7 @@ class FastMCP:
254
261
  "Did you forget to call it? Use @tool() instead of @tool"
255
262
  )
256
263
 
257
- def decorator(fn: Callable) -> Callable:
264
+ def decorator(fn: Callable[P, R]) -> Callable[P, R]:
258
265
  self.add_tool(fn, name=name, description=description)
259
266
  return fn
260
267
 
@@ -275,7 +282,7 @@ class FastMCP:
275
282
  name: str | None = None,
276
283
  description: str | None = None,
277
284
  mime_type: str | None = None,
278
- ) -> Callable:
285
+ ) -> Callable[[Callable[P, R]], Callable[P, R]]:
279
286
  """Decorator to register a function as a resource.
280
287
 
281
288
  The function will be called when the resource is read to generate its content.
@@ -309,9 +316,9 @@ class FastMCP:
309
316
  "Did you forget to call it? Use @resource('uri') instead of @resource"
310
317
  )
311
318
 
312
- def decorator(fn: Callable) -> Callable:
319
+ def decorator(fn: Callable[P, R]) -> Callable[P, R]:
313
320
  @functools.wraps(fn)
314
- def wrapper(*args: Any, **kwargs: Any) -> Any:
321
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
315
322
  return fn(*args, **kwargs)
316
323
 
317
324
  # Check if this should be a template
@@ -361,7 +368,7 @@ class FastMCP:
361
368
 
362
369
  def prompt(
363
370
  self, name: str | None = None, description: str | None = None
364
- ) -> Callable:
371
+ ) -> Callable[[Callable[P, R_PromptResult]], Callable[P, R_PromptResult]]:
365
372
  """Decorator to register a prompt.
366
373
 
367
374
  Args:
@@ -402,7 +409,7 @@ class FastMCP:
402
409
  "Did you forget to call it? Use @prompt() instead of @prompt"
403
410
  )
404
411
 
405
- def decorator(func: Callable) -> Callable:
412
+ def decorator(func: Callable[P, R_PromptResult]) -> Callable[P, R_PromptResult]:
406
413
  prompt = Prompt.from_function(func, name=name, description=description)
407
414
  self.add_prompt(prompt)
408
415
  return func
@@ -8,7 +8,7 @@ from typing import (
8
8
  )
9
9
  from pydantic import Field
10
10
  from fastmcp.exceptions import InvalidSignature
11
- from pydantic._internal._typing_extra import try_eval_type
11
+ from pydantic._internal._typing_extra import eval_type_lenient
12
12
  import json
13
13
  from pydantic import BaseModel
14
14
  from pydantic.fields import FieldInfo
@@ -91,7 +91,7 @@ class FuncMetadata(BaseModel):
91
91
  pre_parsed = json.loads(data[field_name])
92
92
  except json.JSONDecodeError:
93
93
  continue # Not JSON - skip
94
- if isinstance(pre_parsed, str):
94
+ if isinstance(pre_parsed, (str, int, float)):
95
95
  # This is likely that the raw value is e.g. `"hello"` which we
96
96
  # Should really be parsed as '"hello"' in Python - but if we parse
97
97
  # it as JSON it'll turn into just 'hello'. So we skip it.
@@ -178,12 +178,7 @@ def func_metadata(func: Callable, skip_names: Sequence[str] = ()) -> FuncMetadat
178
178
  def _get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:
179
179
  if isinstance(annotation, str):
180
180
  annotation = ForwardRef(annotation)
181
- annotation, status = try_eval_type(annotation, globalns, globalns)
182
-
183
- # This check and raise could perhaps be skipped, and we (FastMCP) just call
184
- # model_rebuild right before using it 🤷
185
- if status is False:
186
- raise InvalidSignature(f"Unable to evaluate type annotation {annotation}")
181
+ annotation = eval_type_lenient(annotation, globalns, globalns)
187
182
 
188
183
  return annotation
189
184
 
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fastmcp
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: A more ergonomic interface for MCP servers
5
5
  Author: Jeremiah Lowin
6
- License: Apache-2.0
6
+ License: MIT
7
7
  Requires-Python: >=3.10
8
8
  Requires-Dist: httpx>=0.26.0
9
9
  Requires-Dist: mcp<2.0.0,>=1.0.0
@@ -1,6 +1,7 @@
1
1
  fastmcp/__init__.py,sha256=Y5dHGBwyQPgNP5gzOyNIItefvMZ3vJLdom1oV8A1u_k,248
2
2
  fastmcp/exceptions.py,sha256=q9djUDmpwmGEWcHI8q4UzJBtf7s7UtgL--OB7OaGzyQ,435
3
- fastmcp/server.py,sha256=VBO8UfhxT-bj1zhSO6M5TnIrYooHfEkegP8W-KcmGog,22302
3
+ fastmcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ fastmcp/server.py,sha256=ZyAXh9rBwpYXifJBwmf7xtanBjC3B-t0Uo-rXFTDAIY,22678
4
5
  fastmcp/cli/__init__.py,sha256=7hrwtCHX9nMd9qcz7R_JFSoqbL71fC35cBLXBS430mg,88
5
6
  fastmcp/cli/claude.py,sha256=5SoVEsA_PnOyOe2bcItvfcCwuhfX6W99TP1nXahLIJE,4442
6
7
  fastmcp/cli/cli.py,sha256=sWNhq0ryeWcT_ANCW-Ss4ldHfptVDm8d6GjNtJe-8x8,13510
@@ -17,11 +18,11 @@ fastmcp/tools/__init__.py,sha256=ZboxhyMJDl87Svjov8YwNYwNZi55P9VhmpTjBZLesnk,96
17
18
  fastmcp/tools/base.py,sha256=aJEOnNUs5KiTC16Szr8AEZyozTtpp0vZXtF5wMIA2mM,2797
18
19
  fastmcp/tools/tool_manager.py,sha256=PT6XHcQWzhdC6kfdsJaddRn7VLps4nAs5FMG8l1j8Zc,1617
19
20
  fastmcp/utilities/__init__.py,sha256=-imJ8S-rXmbXMWeDamldP-dHDqAPg_wwmPVz-LNX14E,31
20
- fastmcp/utilities/func_metadata.py,sha256=xJWWOoMC0oxMK0R8cbC7w1HLfT8K0jBDlapdCTVxOTI,7503
21
+ fastmcp/utilities/func_metadata.py,sha256=khB5bPMB9I8T7LfFDRwNzQSFqYVSME41KNZpIESmKY4,7266
21
22
  fastmcp/utilities/logging.py,sha256=1ipiOXzgWUp3Vih_JtEiLX7aAFmrUDZNr4KrZbofZTM,818
22
23
  fastmcp/utilities/types.py,sha256=kCjz2h3UlMAfHBB-HR5w6s9kauX0KLyQzRuHyhpaP4A,1810
23
- fastmcp-0.4.0.dist-info/METADATA,sha256=86PQLRngMLSdkTOGcjt_Xv6_StUP2e-o9pW4JEqyG-4,16374
24
- fastmcp-0.4.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
25
- fastmcp-0.4.0.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
26
- fastmcp-0.4.0.dist-info/licenses/LICENSE,sha256=l3hc_411P__OCHoZlE2ZYWekMW-fmIZe9cYnGVyhu9I,1071
27
- fastmcp-0.4.0.dist-info/RECORD,,
24
+ fastmcp-0.4.1.dist-info/METADATA,sha256=2fHmIZuO5ZRyealHazfFjz1i3-GCkS5LLhbNQlyU4C4,16367
25
+ fastmcp-0.4.1.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
26
+ fastmcp-0.4.1.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
27
+ fastmcp-0.4.1.dist-info/licenses/LICENSE,sha256=l3hc_411P__OCHoZlE2ZYWekMW-fmIZe9cYnGVyhu9I,1071
28
+ fastmcp-0.4.1.dist-info/RECORD,,