Skip to content

Commit a669005

Browse files
committed
fix
1 parent 631cff2 commit a669005

File tree

1 file changed

+57
-46
lines changed

1 file changed

+57
-46
lines changed

src/mcp/server/fastmcp/utilities/func_metadata.py

Lines changed: 57 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -350,62 +350,73 @@ def _try_create_model_and_schema(
350350
model = None
351351
wrap_output = False
352352

353-
# First handle special case: None
354-
if type_expr is None:
355-
model = _create_wrapped_model(func_name, original_annotation)
356-
wrap_output = True
357-
358-
# Handle GenericAlias types (list[str], dict[str, int], Union[str, int], etc.)
359-
elif isinstance(type_expr, GenericAlias):
360-
origin = get_origin(type_expr)
361-
362-
# Special case: dict with string keys can use RootModel
363-
if origin is dict:
364-
args = get_args(type_expr)
365-
if len(args) == 2 and args[0] is str:
366-
# TODO: should we use the original annotation? We are loosing any potential `Annotated`
367-
# metadata for Pydantic here:
368-
model = _create_dict_model(func_name, original_annotation)
353+
try:
354+
# First handle special case: None
355+
if type_expr is None:
356+
model = _create_wrapped_model(func_name, original_annotation)
357+
wrap_output = True
358+
359+
# Handle GenericAlias types (list[str], dict[str, int], Union[str, int], etc.)
360+
elif isinstance(type_expr, GenericAlias):
361+
origin = get_origin(type_expr)
362+
363+
# Special case: dict with string keys can use RootModel
364+
if origin is dict:
365+
args = get_args(type_expr)
366+
if len(args) == 2 and args[0] is str:
367+
# TODO: should we use the original annotation? We are loosing any potential `Annotated`
368+
# metadata for Pydantic here:
369+
model = _create_dict_model(func_name, original_annotation)
370+
else:
371+
# dict with non-str keys needs wrapping
372+
model = _create_wrapped_model(func_name, original_annotation)
373+
wrap_output = True
369374
else:
370-
# dict with non-str keys needs wrapping
375+
# All other generic types need wrapping (list, tuple, Union, Optional, etc.)
371376
model = _create_wrapped_model(func_name, original_annotation)
372377
wrap_output = True
373-
else:
374-
# All other generic types need wrapping (list, tuple, Union, Optional, etc.)
375-
model = _create_wrapped_model(func_name, original_annotation)
376-
wrap_output = True
377378

378-
# Handle regular type objects
379-
elif isinstance(type_expr, type):
380-
type_annotation = cast(type[Any], type_expr)
379+
# Handle regular type objects
380+
elif isinstance(type_expr, type):
381+
type_annotation = cast(type[Any], type_expr)
381382

382-
# Case 1: BaseModel subclasses (can be used directly)
383-
if issubclass(type_annotation, BaseModel):
384-
model = type_annotation
383+
# Case 1: BaseModel subclasses (can be used directly)
384+
if issubclass(type_annotation, BaseModel):
385+
model = type_annotation
385386

386-
# Case 2: TypedDicts:
387-
elif is_typeddict(type_annotation):
388-
model = _create_model_from_typeddict(type_annotation)
387+
# Case 2: TypedDicts:
388+
elif is_typeddict(type_annotation):
389+
model = _create_model_from_typeddict(type_annotation)
389390

390-
# Case 3: Primitive types that need wrapping
391-
elif type_annotation in (str, int, float, bool, bytes, type(None)):
392-
model = _create_wrapped_model(func_name, original_annotation)
393-
wrap_output = True
391+
# Case 3: Primitive types that need wrapping
392+
elif type_annotation in (str, int, float, bool, bytes, type(None)):
393+
model = _create_wrapped_model(func_name, original_annotation)
394+
wrap_output = True
395+
396+
# Case 4: Other class types (dataclasses, regular classes with annotations)
397+
else:
398+
type_hints = get_type_hints(type_annotation)
399+
if type_hints:
400+
# Classes with type hints can be converted to Pydantic models
401+
model = _create_model_from_class(type_annotation, type_hints)
402+
# Classes without type hints are not serializable - model remains None
394403

395-
# Case 4: Other class types (dataclasses, regular classes with annotations)
404+
# Handle any other types not covered above
396405
else:
397-
type_hints = get_type_hints(type_annotation)
398-
if type_hints:
399-
# Classes with type hints can be converted to Pydantic models
400-
model = _create_model_from_class(type_annotation, type_hints)
401-
# Classes without type hints are not serializable - model remains None
406+
# This includes typing constructs that aren't GenericAlias in Python 3.10
407+
# (e.g., Union, Optional in some Python versions)
408+
model = _create_wrapped_model(func_name, original_annotation)
409+
wrap_output = True
402410

403-
# Handle any other types not covered above
404-
else:
405-
# This includes typing constructs that aren't GenericAlias in Python 3.10
406-
# (e.g., Union, Optional in some Python versions)
407-
model = _create_wrapped_model(func_name, original_annotation)
408-
wrap_output = True
411+
except (
412+
TypeError,
413+
ValueError,
414+
pydantic_core.SchemaError,
415+
pydantic_core.ValidationError,
416+
PydanticSchemaGenerationError,
417+
) as e:
418+
logger.info(f"Cannot create model for type {type_expr} in {func_name}: {type(e).__name__}: {e}")
419+
return None, None, False
409420

410421
if model:
411422
# If we successfully created a model, try to get its schema

0 commit comments

Comments
 (0)