diff --git a/src/mcp/server/fastmcp/utilities/func_metadata.py b/src/mcp/server/fastmcp/utilities/func_metadata.py index cf93049..629580e 100644 --- a/src/mcp/server/fastmcp/utilities/func_metadata.py +++ b/src/mcp/server/fastmcp/utilities/func_metadata.py @@ -88,7 +88,7 @@ def pre_parse_json(self, data: dict[str, Any]) -> dict[str, Any]: pre_parsed = json.loads(data[field_name]) except json.JSONDecodeError: continue # Not JSON - skip - if isinstance(pre_parsed, str): + if isinstance(pre_parsed, (str, int, float)): # This is likely that the raw value is e.g. `"hello"` which we # Should really be parsed as '"hello"' in Python - but if we parse # it as JSON it'll turn into just 'hello'. So we skip it. diff --git a/tests/server/fastmcp/test_func_metadata.py b/tests/server/fastmcp/test_func_metadata.py index 7173b43..ad14def 100644 --- a/tests/server/fastmcp/test_func_metadata.py +++ b/tests/server/fastmcp/test_func_metadata.py @@ -176,6 +176,21 @@ def func_with_str_types(str_or_list: str | list[str]): assert result["str_or_list"] == ["hello", "world"] +def test_str_vs_int(): + """ + Test that string values are kept as strings even when they contain numbers, + while numbers are parsed correctly. + """ + + def func_with_str_and_int(a: str, b: int): + return a + + meta = func_metadata(func_with_str_and_int) + result = meta.pre_parse_json({"a": "123", "b": 123}) + assert result["a"] == "123" + assert result["b"] == 123 + + def test_skip_names(): """Test that skipped parameters are not included in the model"""