Jeremiah Lowin commited on
Commit
0d5b336
·
1 Parent(s): a6ffd5a

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(self.fn)
 
 
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(cls: T) -> TypeAdapter[T]:
 
 
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
- return TypeAdapter(cls)
 
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: