77from mcp .server .fastmcp .utilities .func_metadata import func_metadata
88
99
10- class SomeInputModelA (BaseModel ):
10+ class SomeModelA (BaseModel ):
1111 pass
1212
1313
14- class SomeInputModelB (BaseModel ):
14+ class SomeModelB (BaseModel ):
1515 class InnerModel (BaseModel ):
1616 x : int
1717
@@ -46,15 +46,15 @@ def complex_arguments_fn(
4646 int , Field (1 )
4747 ],
4848 unannotated ,
49- my_model_a : SomeInputModelA ,
50- my_model_a_forward_ref : "SomeInputModelA " ,
51- my_model_b : SomeInputModelB ,
49+ my_model_a : SomeModelA ,
50+ my_model_a_forward_ref : "SomeModelA " ,
51+ my_model_b : SomeModelB ,
5252 an_int_annotated_with_field_default : Annotated [
5353 int ,
5454 Field (1 , description = "An int with a field" ),
5555 ],
5656 unannotated_with_default = 5 ,
57- my_model_a_with_default : SomeInputModelA = SomeInputModelA (), # noqa: B008
57+ my_model_a_with_default : SomeModelA = SomeModelA (), # noqa: B008
5858 an_int_with_default : int = 1 ,
5959 must_be_none_with_default : None = None ,
6060 an_int_with_equals_field : int = Field (1 , ge = 0 ),
@@ -85,6 +85,26 @@ def complex_arguments_fn(
8585 return "ok!"
8686
8787
88+ def simple_str_fun () -> str :
89+ return "ok"
90+
91+
92+ def simple_bool_fun () -> bool :
93+ return True
94+
95+
96+ def simple_int_fun () -> int :
97+ return 1
98+
99+
100+ def simple_float_fun () -> float :
101+ return 1.0
102+
103+
104+ def complex_model_fun () -> SomeModelB :
105+ return SomeModelB (how_many_shrimp = 1 , ok = SomeModelB .InnerModel (x = 2 ), y = None )
106+
107+
88108@pytest .mark .anyio
89109async def test_complex_function_runtime_arg_validation_non_json ():
90110 """Test that basic non-JSON arguments are validated correctly"""
@@ -269,7 +289,7 @@ def test_complex_function_json_schema():
269289 # Normalize the my_model_a_with_default field to handle both pydantic formats
270290 if "allOf" in actual_schema ["properties" ]["my_model_a_with_default" ]:
271291 normalized_schema ["properties" ]["my_model_a_with_default" ] = {
272- "$ref" : "#/$defs/SomeInputModelA " ,
292+ "$ref" : "#/$defs/SomeModelA " ,
273293 "default" : {},
274294 }
275295
@@ -281,12 +301,12 @@ def test_complex_function_json_schema():
281301 "title" : "InnerModel" ,
282302 "type" : "object" ,
283303 },
284- "SomeInputModelA " : {
304+ "SomeModelA " : {
285305 "properties" : {},
286- "title" : "SomeInputModelA " ,
306+ "title" : "SomeModelA " ,
287307 "type" : "object" ,
288308 },
289- "SomeInputModelB " : {
309+ "SomeModelB " : {
290310 "properties" : {
291311 "how_many_shrimp" : {
292312 "description" : "How many shrimp in the tank???" ,
@@ -297,7 +317,7 @@ def test_complex_function_json_schema():
297317 "y" : {"title" : "Y" , "type" : "null" },
298318 },
299319 "required" : ["how_many_shrimp" , "ok" , "y" ],
300- "title" : "SomeInputModelB " ,
320+ "title" : "SomeModelB " ,
301321 "type" : "object" ,
302322 },
303323 },
@@ -341,9 +361,9 @@ def test_complex_function_json_schema():
341361 "type" : "integer" ,
342362 },
343363 "unannotated" : {"title" : "unannotated" , "type" : "string" },
344- "my_model_a" : {"$ref" : "#/$defs/SomeInputModelA " },
345- "my_model_a_forward_ref" : {"$ref" : "#/$defs/SomeInputModelA " },
346- "my_model_b" : {"$ref" : "#/$defs/SomeInputModelB " },
364+ "my_model_a" : {"$ref" : "#/$defs/SomeModelA " },
365+ "my_model_a_forward_ref" : {"$ref" : "#/$defs/SomeModelA " },
366+ "my_model_b" : {"$ref" : "#/$defs/SomeModelB " },
347367 "an_int_annotated_with_field_default" : {
348368 "default" : 1 ,
349369 "description" : "An int with a field" ,
@@ -356,7 +376,7 @@ def test_complex_function_json_schema():
356376 "type" : "string" ,
357377 },
358378 "my_model_a_with_default" : {
359- "$ref" : "#/$defs/SomeInputModelA " ,
379+ "$ref" : "#/$defs/SomeModelA " ,
360380 "default" : {},
361381 },
362382 "an_int_with_default" : {
@@ -414,3 +434,49 @@ def func_with_str_and_int(a: str, b: int):
414434 result = meta .pre_parse_json ({"a" : "123" , "b" : 123 })
415435 assert result ["a" ] == "123"
416436 assert result ["b" ] == 123
437+
438+
439+ def test_simple_function_output_schema ():
440+ """Test JSON schema generation for simple return types."""
441+
442+ assert func_metadata (simple_str_fun ).output_schema == {
443+ "type" : "string" ,
444+ }
445+ assert func_metadata (simple_bool_fun ).output_schema == {
446+ "type" : "boolean" ,
447+ }
448+ assert func_metadata (simple_int_fun ).output_schema == {
449+ "type" : "integer" ,
450+ }
451+ assert func_metadata (simple_float_fun ).output_schema == {
452+ "type" : "number" ,
453+ }
454+
455+
456+ def test_complex_function_output_schema ():
457+ """Test JSON schema generation for simple return types."""
458+
459+ assert func_metadata (complex_model_fun ).output_schema == {
460+ "type" : "object" ,
461+ "$defs" : {
462+ "InnerModel" : {
463+ "properties" : {"x" : {"title" : "X" , "type" : "integer" }},
464+ "required" : [
465+ "x" ,
466+ ],
467+ "title" : "InnerModel" ,
468+ "type" : "object" ,
469+ }
470+ },
471+ "properties" : {
472+ "how_many_shrimp" : {
473+ "description" : "How many shrimp in the tank???" ,
474+ "title" : "How Many Shrimp" ,
475+ "type" : "integer" ,
476+ },
477+ "ok" : {"$ref" : "#/$defs/InnerModel" },
478+ "y" : {"title" : "Y" , "type" : "null" },
479+ },
480+ "required" : ["how_many_shrimp" , "ok" , "y" ],
481+ "title" : "SomeModelB" ,
482+ }
0 commit comments