Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions fastapi_mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ def __init__(
Optional[AuthConfig],
Doc("Configuration for MCP authentication"),
] = None,
prefer_structured_content: Annotated[
bool,
Doc(
"Whether to prefer structured content over text content in responses. Defaults to False for backwards compatibility."
),
] = False,
headers: Annotated[
List[str],
Doc(
Expand Down Expand Up @@ -108,6 +114,7 @@ def __init__(
self._include_tags = include_tags
self._exclude_tags = exclude_tags
self._auth_config = auth_config
self._prefer_structured_content = prefer_structured_content

if self._auth_config:
self._auth_config = self._auth_config.model_validate(self._auth_config)
Expand Down Expand Up @@ -150,7 +157,7 @@ async def handle_list_tools() -> List[types.Tool]:
@mcp_server.call_tool()
async def handle_call_tool(
name: str, arguments: Dict[str, Any]
) -> List[Union[types.TextContent, types.ImageContent, types.EmbeddedResource]]:
) -> Union[List[Union[types.TextContent, types.ImageContent, types.EmbeddedResource]], Dict[str, Any]]:
# Extract HTTP request info from MCP context
http_request_info = None
try:
Expand Down Expand Up @@ -491,7 +498,7 @@ async def _execute_api_tool(
Optional[HTTPRequestInfo],
Doc("HTTP request info to forward to the actual API call"),
] = None,
) -> List[Union[types.TextContent, types.ImageContent, types.EmbeddedResource]]:
) -> Union[List[Union[types.TextContent, types.ImageContent, types.EmbeddedResource]], Dict[str, Any]]:
"""
Execute an MCP tool by making an HTTP request to the corresponding API endpoint.

Expand Down Expand Up @@ -544,6 +551,7 @@ async def _execute_api_tool(
response = await self._request(client, method, path, query, headers, body)

# TODO: Better typing for the AsyncClientProtocol. It should return a ResponseProtocol that has a json() method that returns a dict/list/etc.
result = None
try:
result = response.json()
result_text = json.dumps(result, indent=2, ensure_ascii=False)
Expand All @@ -560,6 +568,9 @@ async def _execute_api_tool(
f"Error calling {tool_name}. Status code: {response.status_code}. Response: {response.text}"
)

if result is not None and self._prefer_structured_content:
return result

try:
return [types.TextContent(type="text", text=result_text)]
except ValueError:
Expand Down
Loading