From ddbf398892c3c1f6de4088f5848e5aad1d0a61ef Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Tue, 6 May 2025 10:38:21 -0400 Subject: [PATCH] Coerce numbers to str --- src/fastmcp/tools/tool.py | 4 +++- src/fastmcp/utilities/types.py | 11 +++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/fastmcp/tools/tool.py b/src/fastmcp/tools/tool.py index fbe51130c..2bdfaac2c 100644 --- a/src/fastmcp/tools/tool.py +++ b/src/fastmcp/tools/tool.py @@ -127,7 +127,9 @@ class Tool(BaseModel): except json.JSONDecodeError: pass - type_adapter = get_cached_typeadapter(self.fn) + type_adapter = get_cached_typeadapter( + self.fn, config=frozenset([("coerce_numbers_to_str", True)]) + ) result = type_adapter.validate_python(parsed_args | injected_args) if inspect.isawaitable(result): result = await result diff --git a/src/fastmcp/utilities/types.py b/src/fastmcp/utilities/types.py index 0ad371db3..f21a013f7 100644 --- a/src/fastmcp/utilities/types.py +++ b/src/fastmcp/utilities/types.py @@ -6,23 +6,26 @@ from collections.abc import Callable from functools import lru_cache from pathlib import Path from types import UnionType -from typing import Annotated, TypeVar, Union, get_args, get_origin +from typing import Annotated, Any, TypeVar, Union, get_args, get_origin from mcp.types import ImageContent -from pydantic import TypeAdapter +from pydantic import ConfigDict, TypeAdapter T = TypeVar("T") @lru_cache(maxsize=5000) -def get_cached_typeadapter(cls: T) -> TypeAdapter[T]: +def get_cached_typeadapter( + cls: T, config: frozenset[tuple[str, Any]] | None = None +) -> TypeAdapter[T]: """ TypeAdapters are heavy objects, and in an application context we'd typically create them once in a global scope and reuse them as often as possible. However, this isn't feasible for user-generated functions. Instead, we use a cache to minimize the cost of creating them as much as possible. """ - return TypeAdapter(cls) + config_dict = dict(config or {}) + return TypeAdapter(cls, config=ConfigDict(**config_dict)) def issubclass_safe(cls: type, base: type) -> bool: