mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-21 13:04:18 +02:00
Ensure openapi tool responses are properly converted
This commit is contained in:
parent
fe9fcd32cd
commit
39e62bc11c
3 changed files with 38 additions and 14 deletions
|
|
@ -10,12 +10,12 @@ from re import Pattern
|
|||
from typing import TYPE_CHECKING, Any, Literal
|
||||
|
||||
import httpx
|
||||
from mcp.types import TextContent
|
||||
from mcp.types import EmbeddedResource, ImageContent, TextContent
|
||||
from pydantic.networks import AnyUrl
|
||||
|
||||
from fastmcp.resources import Resource, ResourceTemplate
|
||||
from fastmcp.server.server import FastMCP
|
||||
from fastmcp.tools.tool import Tool
|
||||
from fastmcp.tools.tool import Tool, _convert_to_content
|
||||
from fastmcp.utilities import openapi
|
||||
from fastmcp.utilities.func_metadata import func_metadata
|
||||
from fastmcp.utilities.logging import get_logger
|
||||
|
|
@ -239,9 +239,14 @@ class OpenAPITool(Tool):
|
|||
# Handle request errors (connection, timeout, etc.)
|
||||
raise ValueError(f"Request error: {str(e)}")
|
||||
|
||||
async def run(self, arguments: dict[str, Any], context: Any = None) -> Any:
|
||||
async def run(
|
||||
self,
|
||||
arguments: dict[str, Any],
|
||||
context: Context[ServerSessionT, LifespanContextT] | None = None,
|
||||
) -> list[TextContent | ImageContent | EmbeddedResource]:
|
||||
"""Run the tool with arguments and optional context."""
|
||||
return await self._execute_request(**arguments, context=context)
|
||||
response = await self._execute_request(**arguments, context=context)
|
||||
return _convert_to_content(response)
|
||||
|
||||
|
||||
class OpenAPIResource(Resource):
|
||||
|
|
@ -605,13 +610,4 @@ class FastMCPOpenAPI(FastMCP):
|
|||
|
||||
context = self.get_context()
|
||||
result = await self._tool_manager.call_tool(name, arguments, context=context)
|
||||
|
||||
# For other tools, ensure the response is wrapped in TextContent
|
||||
if isinstance(result, dict | str):
|
||||
if isinstance(result, dict):
|
||||
result_text = json.dumps(result)
|
||||
else:
|
||||
result_text = result
|
||||
return [TextContent(text=result_text, type="text")]
|
||||
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class ProxyTool(Tool):
|
|||
self,
|
||||
arguments: dict[str, Any],
|
||||
context: Context[ServerSessionT, LifespanContextT] | None = None,
|
||||
) -> Any:
|
||||
) -> list[TextContent | ImageContent | EmbeddedResource]:
|
||||
# the client context manager will swallow any exceptions inside a TaskGroup
|
||||
# so we return the raw result and raise an exception ourselves
|
||||
async with self._client:
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ from fastmcp.server.openapi import (
|
|||
OpenAPIResource,
|
||||
OpenAPIResourceTemplate,
|
||||
OpenAPITool,
|
||||
RouteMap,
|
||||
RouteType,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -268,6 +270,32 @@ class TestTools:
|
|||
user = json.loads(response_text)
|
||||
assert user == expected_data
|
||||
|
||||
async def test_call_tool_return_list(
|
||||
self,
|
||||
fastapi_app: FastAPI,
|
||||
api_client: httpx.AsyncClient,
|
||||
users_db: dict[int, User],
|
||||
):
|
||||
"""
|
||||
The tool created by the OpenAPI server should return a list of content.
|
||||
"""
|
||||
openapi_spec = fastapi_app.openapi()
|
||||
mcp_server = FastMCPOpenAPI(
|
||||
openapi_spec=openapi_spec,
|
||||
client=api_client,
|
||||
route_maps=[
|
||||
RouteMap(methods=["GET"], pattern=r".*", route_type=RouteType.TOOL)
|
||||
],
|
||||
)
|
||||
async with Client(mcp_server) as client:
|
||||
tool_response = await client.call_tool("get_users_users_get", {})
|
||||
assert isinstance(tool_response, list)
|
||||
assert isinstance(tool_response[0], TextContent)
|
||||
assert json.loads(tool_response[0].text) == [
|
||||
user.model_dump()
|
||||
for user in sorted(users_db.values(), key=lambda x: x.id)
|
||||
]
|
||||
|
||||
|
||||
class TestResources:
|
||||
async def test_list_resources(self, fastmcp_openapi_server: FastMCPOpenAPI):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue