Jeremiah Lowin commited on
Commit
265bc8e
·
1 Parent(s): d895aec

Improve json handling

Browse files
src/fastmcp/resources/types.py CHANGED
@@ -1,5 +1,6 @@
1
  """Concrete resource implementations."""
2
 
 
3
  import asyncio
4
  import json
5
  from pathlib import Path
@@ -58,8 +59,8 @@ class FunctionResource(Resource):
58
  if isinstance(result, str):
59
  return result
60
  try:
61
- return json.dumps(result, default=pydantic.json.pydantic_encoder)
62
- except TypeError:
63
  # If JSON serialization fails, try str()
64
  return str(result)
65
  except Exception as e:
 
1
  """Concrete resource implementations."""
2
 
3
+ import pydantic_core
4
  import asyncio
5
  import json
6
  from pathlib import Path
 
59
  if isinstance(result, str):
60
  return result
61
  try:
62
+ return json.dumps(pydantic_core.to_jsonable_python(result))
63
+ except (TypeError, pydantic_core.PydanticSerializationError):
64
  # If JSON serialization fails, try str()
65
  return str(result)
66
  except Exception as e:
src/fastmcp/server.py CHANGED
@@ -1,5 +1,6 @@
1
  """FastMCP - A more ergonomic interface for MCP servers."""
2
 
 
3
  from typing import Any, Literal, Optional, Union
4
 
5
  from mcp.server import RequestContext
@@ -14,7 +15,6 @@ from typing import Callable, Sequence
14
  import inspect
15
  import re
16
 
17
- import pydantic.json
18
  from mcp.server import Server as MCPServer
19
  from mcp.server.stdio import stdio_server
20
  from mcp.server.sse import SseServerTransport
@@ -397,7 +397,7 @@ def _convert_to_content(value: Any) -> Sequence[Union[TextContent, ImageContent]
397
  result.append(
398
  TextContent(
399
  type="text",
400
- text=json.dumps(item, default=pydantic.json.pydantic_encoder),
401
  )
402
  )
403
  return result
@@ -414,7 +414,7 @@ def _convert_to_content(value: Any) -> Sequence[Union[TextContent, ImageContent]
414
  return [
415
  TextContent(
416
  type="text",
417
- text=json.dumps(value, indent=2, default=pydantic.json.pydantic_encoder),
418
  )
419
  ]
420
 
 
1
  """FastMCP - A more ergonomic interface for MCP servers."""
2
 
3
+ import pydantic_core
4
  from typing import Any, Literal, Optional, Union
5
 
6
  from mcp.server import RequestContext
 
15
  import inspect
16
  import re
17
 
 
18
  from mcp.server import Server as MCPServer
19
  from mcp.server.stdio import stdio_server
20
  from mcp.server.sse import SseServerTransport
 
397
  result.append(
398
  TextContent(
399
  type="text",
400
+ text=json.dumps(pydantic_core.to_jsonable_python(item)),
401
  )
402
  )
403
  return result
 
414
  return [
415
  TextContent(
416
  type="text",
417
+ text=json.dumps(pydantic_core.to_jsonable_python(value)),
418
  )
419
  ]
420
 
tests/resources/test_function_resources.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import pytest
2
  from fastmcp.resources import FunctionResource
3
 
@@ -80,6 +81,20 @@ class TestFunctionResource:
80
  with pytest.raises(ValueError, match="Error reading resource function://test"):
81
  await resource.read()
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  async def test_custom_type_conversion(self):
84
  """Test handling of custom types."""
85
 
 
1
+ from pydantic import BaseModel
2
  import pytest
3
  from fastmcp.resources import FunctionResource
4
 
 
81
  with pytest.raises(ValueError, match="Error reading resource function://test"):
82
  await resource.read()
83
 
84
+ async def test_basemodel_conversion(self):
85
+ """Test handling of BaseModel types."""
86
+
87
+ class MyModel(BaseModel):
88
+ name: str
89
+
90
+ resource = FunctionResource(
91
+ uri="function://test",
92
+ name="test",
93
+ func=lambda: MyModel(name="test"),
94
+ )
95
+ content = await resource.read()
96
+ assert content == '{"name": "test"}'
97
+
98
  async def test_custom_type_conversion(self):
99
  """Test handling of custom types."""
100