Spaces:
Running
Running
Merge pull request #337 from jlowin/coerce-numbers-to-str
Browse files
src/fastmcp/tools/tool.py
CHANGED
|
@@ -127,7 +127,9 @@ class Tool(BaseModel):
|
|
| 127 |
except json.JSONDecodeError:
|
| 128 |
pass
|
| 129 |
|
| 130 |
-
type_adapter = get_cached_typeadapter(
|
|
|
|
|
|
|
| 131 |
result = type_adapter.validate_python(parsed_args | injected_args)
|
| 132 |
if inspect.isawaitable(result):
|
| 133 |
result = await result
|
|
|
|
| 127 |
except json.JSONDecodeError:
|
| 128 |
pass
|
| 129 |
|
| 130 |
+
type_adapter = get_cached_typeadapter(
|
| 131 |
+
self.fn, config=frozenset([("coerce_numbers_to_str", True)])
|
| 132 |
+
)
|
| 133 |
result = type_adapter.validate_python(parsed_args | injected_args)
|
| 134 |
if inspect.isawaitable(result):
|
| 135 |
result = await result
|
src/fastmcp/utilities/types.py
CHANGED
|
@@ -6,23 +6,26 @@ from collections.abc import Callable
|
|
| 6 |
from functools import lru_cache
|
| 7 |
from pathlib import Path
|
| 8 |
from types import UnionType
|
| 9 |
-
from typing import Annotated, TypeVar, Union, get_args, get_origin
|
| 10 |
|
| 11 |
from mcp.types import ImageContent
|
| 12 |
-
from pydantic import TypeAdapter
|
| 13 |
|
| 14 |
T = TypeVar("T")
|
| 15 |
|
| 16 |
|
| 17 |
@lru_cache(maxsize=5000)
|
| 18 |
-
def get_cached_typeadapter(
|
|
|
|
|
|
|
| 19 |
"""
|
| 20 |
TypeAdapters are heavy objects, and in an application context we'd typically
|
| 21 |
create them once in a global scope and reuse them as often as possible.
|
| 22 |
However, this isn't feasible for user-generated functions. Instead, we use a
|
| 23 |
cache to minimize the cost of creating them as much as possible.
|
| 24 |
"""
|
| 25 |
-
|
|
|
|
| 26 |
|
| 27 |
|
| 28 |
def issubclass_safe(cls: type, base: type) -> bool:
|
|
|
|
| 6 |
from functools import lru_cache
|
| 7 |
from pathlib import Path
|
| 8 |
from types import UnionType
|
| 9 |
+
from typing import Annotated, Any, TypeVar, Union, get_args, get_origin
|
| 10 |
|
| 11 |
from mcp.types import ImageContent
|
| 12 |
+
from pydantic import ConfigDict, TypeAdapter
|
| 13 |
|
| 14 |
T = TypeVar("T")
|
| 15 |
|
| 16 |
|
| 17 |
@lru_cache(maxsize=5000)
|
| 18 |
+
def get_cached_typeadapter(
|
| 19 |
+
cls: T, config: frozenset[tuple[str, Any]] | None = None
|
| 20 |
+
) -> TypeAdapter[T]:
|
| 21 |
"""
|
| 22 |
TypeAdapters are heavy objects, and in an application context we'd typically
|
| 23 |
create them once in a global scope and reuse them as often as possible.
|
| 24 |
However, this isn't feasible for user-generated functions. Instead, we use a
|
| 25 |
cache to minimize the cost of creating them as much as possible.
|
| 26 |
"""
|
| 27 |
+
config_dict = dict(config or {})
|
| 28 |
+
return TypeAdapter(cls, config=ConfigDict(**config_dict))
|
| 29 |
|
| 30 |
|
| 31 |
def issubclass_safe(cls: type, base: type) -> bool:
|