Skip to content

Commit 0553f26

Browse files
committed
bugfix
1 parent bd28adb commit 0553f26

File tree

2 files changed

+43
-36
lines changed

2 files changed

+43
-36
lines changed

fastapi_mcp/http_tools.py

+24-13
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
from .openapi_utils import (
1717
clean_schema_for_display,
1818
generate_example_from_schema,
19-
parse_param_schema_for_python_type_and_default,
19+
get_python_type_and_default,
20+
get_single_param_type_from_schema,
2021
resolve_schema_references,
2122
PYTHON_TYPE_IMPORTS,
2223
)
@@ -101,18 +102,22 @@ def create_mcp_tools_from_openapi(
101102

102103
def _create_http_tool_function(function_template: Callable, properties: Dict[str, Any], additional_variables: Dict[str, Any]) -> Callable:
103104
# Build parameter string with type hints
104-
param_list = []
105-
param_list_with_defaults = []
106-
for name, schema in properties.items():
107-
type_hint, has_default_value = parse_param_schema_for_python_type_and_default(schema)
105+
parsed_parameters = {}
106+
parsed_parameters_with_defaults = {}
107+
for param_name, parsed_param_schema in properties.items():
108+
type_hint, has_default_value = get_python_type_and_default(parsed_param_schema)
108109
if has_default_value:
109-
param_list_with_defaults.append(f"{name}: {type_hint}")
110+
parsed_parameters_with_defaults[param_name] = f"{param_name}: {type_hint}"
110111
else:
111-
param_list.append(f"{name}: {type_hint}")
112-
parameters_str = ", ".join(param_list + param_list_with_defaults)
112+
parsed_parameters[param_name] = f"{param_name}: {type_hint}"
113+
114+
parsed_parameters_keys = list(parsed_parameters.keys()) + list(parsed_parameters_with_defaults.keys())
115+
parsed_parameters_values = list(parsed_parameters.values()) + list(parsed_parameters_with_defaults.values())
116+
parameters_str = ", ".join(parsed_parameters_values)
117+
kwargs_str = ', '.join([f"'{k}': {k}" for k in parsed_parameters_keys])
113118

114119
dynamic_function_body = f"""async def dynamic_http_tool_function({parameters_str}):
115-
kwargs = {{{', '.join([f"'{k}': {k}" for k in properties.keys()])}}}
120+
kwargs = {{{kwargs_str}}}
116121
return await http_tool_function_template(**kwargs)
117122
"""
118123

@@ -302,7 +307,6 @@ def create_http_tool(
302307
query_params = []
303308
header_params = []
304309
body_params = []
305-
306310
for param in parameters:
307311
param_name = param.get("name")
308312
param_in = param.get("in")
@@ -360,10 +364,12 @@ def create_http_tool(
360364
param_required = param.get("required", False)
361365

362366
properties[param_name] = {
363-
"type": param_schema.get("type", "string"),
367+
"type": get_single_param_type_from_schema(param_schema),
364368
"title": param_name,
365369
"description": param_desc,
366370
}
371+
if "default" in param_schema:
372+
properties[param_name]["default"] = param_schema["default"]
367373

368374
if param_required:
369375
required_props.append(param_name)
@@ -373,8 +379,13 @@ def create_http_tool(
373379
param_schema = param.get("schema", {})
374380
param_required = param.get("required", False)
375381

376-
properties[param_name] = param_schema
377-
properties[param_name]["title"] = param_name
382+
# properties[param_name] = param_schema
383+
properties[param_name] = {
384+
"type": get_single_param_type_from_schema(param_schema),
385+
"title": param_name,
386+
}
387+
if "default" in param_schema:
388+
properties[param_name]["default"] = param_schema["default"]
378389

379390
if param_required:
380391
required_props.append(param_name)

fastapi_mcp/openapi_utils.py

+19-23
Original file line numberDiff line numberDiff line change
@@ -107,36 +107,32 @@
107107
"unknown": "Any"
108108
}
109109

110-
111-
def parse_param_schema_for_python_type_and_default(param_schema: Dict[str, Any]) -> tuple[str, bool]:
110+
def get_single_param_type_from_schema(param_schema: Dict[str, Any]) -> str:
112111
"""
113-
Parse OpenAPI parameters into a python type and default value string.
114-
115-
Args:
116-
parameters: List of OpenAPI parameter objects
117-
118-
Returns:
119-
A tuple containing:
120-
- A string representing the Python type annotation (e.g. "str", "Optional[int]", etc.)
121-
- A boolean indicating whether a default value is present
112+
Get the type of a parameter from the schema.
113+
If the schema is a union type, return the first type.
122114
"""
123-
# Handle anyOf case
124115
if "anyOf" in param_schema:
125-
# Get a set of possible types for this parameter
126116
types = {schema.get("type") for schema in param_schema["anyOf"] if schema.get("type")}
127-
# If null is one of the types, make None the default value
128117
if "null" in types:
129118
types.remove("null")
130-
if types:
131-
return f"Optional[{OPENAPI_PYTHON_TYPES_MAP.get(next(iter(types)), 'Any')}] = None", True
132-
return "Optional[str] = None", True
133-
return f"Union[{', '.join([OPENAPI_PYTHON_TYPES_MAP.get(t, 'Any') for t in types])}]", False
134-
119+
if types:
120+
return next(iter(types))
121+
return "string"
122+
return param_schema.get("type", "string")
123+
124+
def get_python_type_and_default(parsed_param_schema: Dict[str, Any]) -> tuple[str, bool]:
125+
"""
126+
Parse parameters into a python type and default value string.
127+
Returns:
128+
A tuple containing:
129+
- A string representing the Python type annotation (e.g. "str", "int = 0", etc.)
130+
- A boolean indicating whether a default value is present
131+
"""
135132
# Handle direct type specification
136-
python_type = OPENAPI_PYTHON_TYPES_MAP.get(param_schema.get("type", ""), 'Any')
137-
default_value = param_schema.get("default")
138-
if default_value is not None:
139-
return f"{python_type} = {default_value}", True
133+
python_type = OPENAPI_PYTHON_TYPES_MAP.get(parsed_param_schema.get("type", ""), "Any")
134+
if "default" in parsed_param_schema:
135+
return f"{python_type} = {parsed_param_schema.get("default")}", True
140136
return python_type, False
141137

142138
def resolve_schema_references(schema_part: Dict[str, Any], reference_schema: Dict[str, Any]) -> Dict[str, Any]:

0 commit comments

Comments
 (0)