Skip to content

Commit 1ed8eca

Browse files
committed
add describe_all_responses and describe_full_response_schema params
1 parent 39b413e commit 1ed8eca

File tree

8 files changed

+75
-446
lines changed

8 files changed

+75
-446
lines changed

examples/sample_app.py

Lines changed: 0 additions & 143 deletions
This file was deleted.

examples/simple_integration.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ async def search_items(
147147
name="Item API MCP",
148148
description="MCP server for the Item API",
149149
base_url="http://localhost:8000",
150+
describe_all_responses=False, # Only describe the success response in tool descriptions
151+
describe_full_response_schema=False, # Only show LLM-friendly example response in tool descriptions, not the full json schema
150152
)
151153

152154

fastapi_mcp/http_tools.py

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@
44
This module provides functionality for creating MCP tools from FastAPI endpoints.
55
"""
66

7-
import inspect
87
import json
98
import logging
10-
from typing import Any, Callable, Dict, List, Optional, Type, get_type_hints
9+
from typing import Any, Dict, List, Optional
1110

1211
import httpx
13-
from fastapi import FastAPI, params
12+
from fastapi import FastAPI
1413
from fastapi.openapi.utils import get_openapi
1514
from mcp.server.fastmcp import FastMCP
16-
from pydantic import BaseModel
1715

1816
logger = logging.getLogger("fastapi_mcp")
1917

@@ -101,14 +99,22 @@ def clean_schema_for_display(schema: Dict[str, Any]) -> Dict[str, Any]:
10199
return schema
102100

103101

104-
def create_mcp_tools_from_openapi(app: FastAPI, mcp_server: FastMCP, base_url: str = None) -> None:
102+
def create_mcp_tools_from_openapi(
103+
app: FastAPI,
104+
mcp_server: FastMCP,
105+
base_url: Optional[str] = None,
106+
describe_all_responses: bool = False,
107+
describe_full_response_schema: bool = False,
108+
) -> None:
105109
"""
106110
Create MCP tools from a FastAPI app's OpenAPI schema.
107111
108112
Args:
109113
app: The FastAPI application
110114
mcp_server: The MCP server to add tools to
111115
base_url: Base URL for API requests (defaults to http://localhost:$PORT)
116+
describe_all_responses: Whether to include all possible response schemas in tool descriptions
117+
describe_full_response_schema: Whether to include full response schema in tool descriptions
112118
"""
113119
# Get OpenAPI schema from FastAPI app
114120
openapi_schema = get_openapi(
@@ -161,6 +167,8 @@ def create_mcp_tools_from_openapi(app: FastAPI, mcp_server: FastMCP, base_url: s
161167
request_body=operation.get("requestBody", {}),
162168
responses=operation.get("responses", {}),
163169
openapi_schema=openapi_schema,
170+
describe_all_responses=describe_all_responses,
171+
describe_full_response_schema=describe_full_response_schema,
164172
)
165173

166174

@@ -176,6 +184,8 @@ def create_http_tool(
176184
request_body: Dict[str, Any],
177185
responses: Dict[str, Any],
178186
openapi_schema: Dict[str, Any],
187+
describe_all_responses: bool,
188+
describe_full_response_schema: bool,
179189
) -> None:
180190
"""
181191
Create an MCP tool that makes an HTTP request to a FastAPI endpoint.
@@ -192,6 +202,8 @@ def create_http_tool(
192202
request_body: OpenAPI request body
193203
responses: OpenAPI responses
194204
openapi_schema: The full OpenAPI schema
205+
describe_all_responses: Whether to include all possible response schemas in tool descriptions
206+
describe_full_response_schema: Whether to include full response schema in tool descriptions
195207
"""
196208
# Build tool description
197209
tool_description = f"{summary}" if summary else f"{method.upper()} {path}"
@@ -210,8 +222,16 @@ def create_http_tool(
210222
success_response = responses[str(status_code)]
211223
break
212224

213-
# Process all responses
214-
for status_code, response_data in responses.items():
225+
# Get the list of responses to include
226+
responses_to_include = responses
227+
if not describe_all_responses and success_response:
228+
# If we're not describing all responses, only include the success response
229+
success_code = next((code for code in success_codes if str(code) in responses), None)
230+
if success_code:
231+
responses_to_include = {str(success_code): success_response}
232+
233+
# Process all selected responses
234+
for status_code, response_data in responses_to_include.items():
215235
response_desc = response_data.get("description", "")
216236
response_info += f"\n**{status_code}**: {response_desc}"
217237

@@ -310,30 +330,25 @@ def create_http_tool(
310330
response_info += json.dumps(generated_example, indent=2)
311331
response_info += "\n```"
312332

313-
# Format schema information based on its type
314-
if display_schema.get("type") == "array" and "items" in display_schema:
315-
items_schema = display_schema["items"]
316-
# Check if items reference a model
317-
items_model_name = None
318-
if "$ref" in schema.get("items", {}):
319-
items_ref_path = schema["items"]["$ref"]
320-
if items_ref_path.startswith("#/components/schemas/"):
321-
items_model_name = items_ref_path.split("/")[-1]
322-
response_info += f"\nArray of: {items_model_name}"
323-
324-
response_info += (
325-
"\n\n**Output Schema:** Array of items with the following structure:\n```json\n"
326-
)
327-
response_info += json.dumps(items_schema, indent=2)
328-
response_info += "\n```"
329-
elif "properties" in display_schema:
330-
response_info += "\n\n**Output Schema:**\n```json\n"
331-
response_info += json.dumps(display_schema, indent=2)
332-
response_info += "\n```"
333-
else:
334-
response_info += "\n\n**Output Schema:**\n```json\n"
335-
response_info += json.dumps(display_schema, indent=2)
336-
response_info += "\n```"
333+
# Only include full schema information if requested
334+
if describe_full_response_schema:
335+
# Format schema information based on its type
336+
if display_schema.get("type") == "array" and "items" in display_schema:
337+
items_schema = display_schema["items"]
338+
339+
response_info += (
340+
"\n\n**Output Schema:** Array of items with the following structure:\n```json\n"
341+
)
342+
response_info += json.dumps(items_schema, indent=2)
343+
response_info += "\n```"
344+
elif "properties" in display_schema:
345+
response_info += "\n\n**Output Schema:**\n```json\n"
346+
response_info += json.dumps(display_schema, indent=2)
347+
response_info += "\n```"
348+
else:
349+
response_info += "\n\n**Output Schema:**\n```json\n"
350+
response_info += json.dumps(display_schema, indent=2)
351+
response_info += "\n```"
337352

338353
tool_description += response_info
339354

fastapi_mcp/server.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
This module provides functionality for creating and mounting MCP servers to FastAPI applications.
55
"""
66

7-
from typing import Dict, Optional, Union, Any
7+
from typing import Dict, Optional, Any
88

99
from fastapi import FastAPI
1010
from mcp.server.fastmcp import FastMCP
@@ -53,6 +53,8 @@ def mount_mcp_server(
5353
mount_path: str = "/mcp",
5454
serve_tools: bool = True,
5555
base_url: Optional[str] = None,
56+
describe_all_responses: bool = False,
57+
describe_full_response_schema: bool = False,
5658
) -> None:
5759
"""
5860
Mount an MCP server to a FastAPI app.
@@ -63,6 +65,8 @@ def mount_mcp_server(
6365
mount_path: Path where the MCP server will be mounted
6466
serve_tools: Whether to serve tools from the FastAPI app
6567
base_url: Base URL for API requests
68+
describe_all_responses: Whether to include all possible response schemas in tool descriptions. Recommended to keep False, as the LLM will probably derive if there is an error.
69+
describe_full_response_schema: Whether to include full json schema for responses in tool descriptions. Recommended to keep False, as examples are more LLM friendly, and save tokens.
6670
"""
6771
# Normalize mount path
6872
if not mount_path.startswith("/"):
@@ -88,7 +92,13 @@ async def handle_mcp_connection(request: Request):
8892

8993
# Serve tools from the FastAPI app if requested
9094
if serve_tools:
91-
create_mcp_tools_from_openapi(app, mcp_server, base_url)
95+
create_mcp_tools_from_openapi(
96+
app,
97+
mcp_server,
98+
base_url,
99+
describe_all_responses=describe_all_responses,
100+
describe_full_response_schema=describe_full_response_schema,
101+
)
92102

93103

94104
def add_mcp_server(
@@ -99,6 +109,8 @@ def add_mcp_server(
99109
capabilities: Optional[Dict[str, Any]] = None,
100110
serve_tools: bool = True,
101111
base_url: Optional[str] = None,
112+
describe_all_responses: bool = False,
113+
describe_full_response_schema: bool = False,
102114
) -> FastMCP:
103115
"""
104116
Add an MCP server to a FastAPI app.
@@ -111,6 +123,8 @@ def add_mcp_server(
111123
capabilities: Optional capabilities for the MCP server
112124
serve_tools: Whether to serve tools from the FastAPI app
113125
base_url: Base URL for API requests (defaults to http://localhost:$PORT)
126+
describe_all_responses: Whether to include all possible response schemas in tool descriptions. Recommended to keep False, as the LLM will probably derive if there is an error.
127+
describe_full_response_schema: Whether to include full json schema for responses in tool descriptions. Recommended to keep False, as examples are more LLM friendly, and save tokens.
114128
115129
Returns:
116130
The FastMCP instance that was created and mounted
@@ -119,6 +133,14 @@ def add_mcp_server(
119133
mcp_server = create_mcp_server(app, name, description, capabilities)
120134

121135
# Mount MCP server to FastAPI app
122-
mount_mcp_server(app, mcp_server, mount_path, serve_tools, base_url)
136+
mount_mcp_server(
137+
app,
138+
mcp_server,
139+
mount_path,
140+
serve_tools,
141+
base_url,
142+
describe_all_responses=describe_all_responses,
143+
describe_full_response_schema=describe_full_response_schema,
144+
)
123145

124146
return mcp_server

0 commit comments

Comments
 (0)