4141 GetPromptResult ,
4242 ImageContent ,
4343 TextContent ,
44+ DataContent ,
4445 ToolAnnotations ,
4546)
4647from mcp .types import Prompt as MCPPrompt
@@ -169,14 +170,17 @@ def _setup_handlers(self) -> None:
169170 self ._mcp_server .get_prompt ()(self .get_prompt )
170171 self ._mcp_server .list_resource_templates ()(self .list_resource_templates )
171172
173+
172174 async def list_tools (self ) -> list [MCPTool ]:
173175 """List all available tools."""
174176 tools = self ._tool_manager .list_tools ()
177+ logger .info (f"list tools: { tools } " )
175178 return [
176179 MCPTool (
177180 name = info .name ,
178181 description = info .description ,
179182 inputSchema = info .parameters ,
183+ outputSchema = info .outputSchema ,
180184 annotations = info .annotations ,
181185 )
182186 for info in tools
@@ -195,10 +199,11 @@ def get_context(self) -> Context[ServerSession, object]:
195199
196200 async def call_tool (
197201 self , name : str , arguments : dict [str , Any ]
198- ) -> Sequence [TextContent | ImageContent | EmbeddedResource ]:
202+ ) -> Sequence [TextContent | ImageContent | DataContent | EmbeddedResource ]:
199203 """Call a tool by name with arguments."""
200204 context = self .get_context ()
201205 result = await self ._tool_manager .call_tool (name , arguments , context = context )
206+ logger .info (f"call tool: { name } with args: { arguments } -> { result } " )
202207 converted_result = _convert_to_content (result )
203208 return converted_result
204209
@@ -260,7 +265,10 @@ def add_tool(
260265 annotations: Optional ToolAnnotations providing additional tool information
261266 """
262267 self ._tool_manager .add_tool (
263- fn , name = name , description = description , annotations = annotations
268+ fn ,
269+ name = name ,
270+ description = description ,
271+ annotations = annotations ,
264272 )
265273
266274 def tool (
@@ -304,7 +312,10 @@ async def async_tool(x: int, context: Context) -> str:
304312
305313 def decorator (fn : AnyFunction ) -> AnyFunction :
306314 self .add_tool (
307- fn , name = name , description = description , annotations = annotations
315+ fn ,
316+ name = name ,
317+ description = description ,
318+ annotations = annotations ,
308319 )
309320 return fn
310321
@@ -547,12 +558,13 @@ async def get_prompt(
547558
548559def _convert_to_content (
549560 result : Any ,
550- ) -> Sequence [TextContent | ImageContent | EmbeddedResource ]:
561+ ) -> Sequence [TextContent | ImageContent | EmbeddedResource | DataContent ]:
551562 """Convert a result to a sequence of content objects."""
552563 if result is None :
553564 return []
554565
555- if isinstance (result , TextContent | ImageContent | EmbeddedResource ):
566+ # Handle existing content types
567+ if isinstance (result , TextContent | ImageContent | EmbeddedResource | DataContent ):
556568 return [result ]
557569
558570 if isinstance (result , Image ):
@@ -561,9 +573,21 @@ def _convert_to_content(
561573 if isinstance (result , list | tuple ):
562574 return list (chain .from_iterable (_convert_to_content (item ) for item in result )) # type: ignore[reportUnknownVariableType]
563575
576+ # For non-string objects, convert to DataContent
564577 if not isinstance (result , str ):
565- result = pydantic_core .to_json (result , fallback = str , indent = 2 ).decode ()
578+ # Try to convert to a JSON-serializable structure
579+ try :
580+ # Get the data as a dict/list structure
581+ data = pydantic_core .to_jsonable_python (result )
582+ # Create DataContent with the data
583+ return [DataContent (type = "data" , data = data )]
584+ except Exception as e :
585+ logger .warning (f"Failed to convert result to DataContent: { e } " )
586+ # Fall back to string representation
587+ result_str = pydantic_core .to_json (result , fallback = str , indent = 2 ).decode ()
588+ return [TextContent (type = "text" , text = result_str )]
566589
590+ # For strings, use TextContent
567591 return [TextContent (type = "text" , text = result )]
568592
569593
0 commit comments