Skip to content

from_fastapi integration fails to handle dictionary/JSON return types from FastAPI endpoints #186

Closed
@RoacherM

Description

@RoacherM

When using FastMCP.from_fastapi() to integrate an existing FastAPI application, the MCP tools generated from FastAPI routes seem unable to correctly handle endpoints that return standard Python dictionaries (which FastAPI serializes to JSON).
While the underlying FastAPI endpoint executes successfully (confirmed via server logs and internal httpx calls returning 200 OK), the client.call_tool() fails on the client-side, often with errors related to task groups or response handling.
However, if the FastAPI endpoint is modified to return a simple string, or manually constructs and returns a List[TextContent] object, the client.call_tool() succeeds.
This suggests that the from_fastapi integration layer isn't properly converting the JSON response received from the FastAPI endpoint back into the List[Content] format required by the MCP protocol before sending it to the client. Ideally, from_fastapi should handle common FastAPI return types like dictionaries/JSON automatically, perhaps by converting them into a default TextContent representation or similar.

    from fastapi import FastAPI
    from fastmcp import FastMCP
    # from mcp.types import TextContent # Not needed for demonstrating the bug
    import logging

    logging.basicConfig(level=logging.INFO)
    log = logging.getLogger(__name__)

    fastapi_app = FastAPI(title="My Existing API")

    @fastapi_app.post("/items")
    def create_item(name: str, price: float):
        log.info(f"FastAPI endpoint called: name={name}, price={price}")
        # Returning a dictionary causes the client call to fail
        return {"id": 1, "name": name, "price": price}
        # Returning a string or List[TextContent] works:
        # return f"name: {name}, price: {price}" 
        # return [TextContent(text=f"name: {name}, price: {price}")]

    mcp_server = FastMCP.from_fastapi(fastapi_app)

    if __name__ == "__main__":
        log.info("Starting MCP server with default transport")
        # Using default transport (e.g., WebSocket), also observed with SSE
        mcp_server.run() 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions