Skip to content

What does this error message require me to do, please? [not a bug] #3266

Description

@davidbernat

Description

Howdy. My internal systems use code wrappers to transform our code repository functions into REST APIs, and now MCP Tools. We are wrapping (pun... 7/10) up our first testing of the MCP wrappers for FastMCP. In particular, our internal functions use arguments with wrappers that allow us greater transparency into what the developer intention was, and greater flexibility to use the same system of code across multiple endpoints (MCPs, APIs, etc). None of this is rocket science and the code is straightforward. As you know, FastMCP defaults to using the name and docstring attributes to create critical LLM-facing MCP context, so there is a copy of a those attributes over to the wrapped function as well.

We are getting this error. As you can see there are notes to double-private internal schema generation which is territory I should not need to touch. You can see that the problem (disagreement) arises from our code wrapping a function with functools.partial The simpler config setting of arbitrary_types_allowed=True is more likely the path to a solution, but I have no idea what this means, and this appears to be a Pydantic internal configuration, which we are not directly using, so is not our bag, baby.

pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for <method-wrapper '__call__' of functools.partial object at 0x131f34c20>. Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it.
If you got this error by calling handler(<some type>) within `__get_pydantic_core_schema__` then you likely need to call `handler.generate_schema(<some type>)` since we do not call `__get_pydantic_core_schema__` on `<some type>` otherwise to avoid infinite recursion.
For further information visit https://errors.pydantic.dev/2.12/u/schema-for-unknown-type
python-BaseException

Here is in all its glory our reduced wrapper function. The problem most likely stems from an implicit mismatch between the native Python handling (i.e., functools), Pydantic (which we use as a type hint on the wrapped function), and FastMCP (which expects to use argument type hints to create schema for the LLM-facing code). The fact that the error is from Pydantic being unable to create the schema is surprising to me, since this is a very simple use of a very simple robust Pydantic item. It is probably obvious what the mismatch is to a developer of either team.

    def _wrap_function_for_cloudtypes(self, fn: typing.Callable) -> typing.Callable:
        """Wrapped function transforms native CloudType to AnyHttpURL / AnyURL conversion suitable for text-only MCP."""
        for_mcp = types.FunctionType(fn.__code__,
                                     fn.__globals__,
                                     fn.__name__,
                                     fn.__defaults__,
                                     fn.__closure__)
        hints = typing.get_type_hints(fn)
        for arg_name, arg_hint in hints.items():
            if arg_hint == "return": continue
            operator = None
            if arg_hint == [example]: operator = [static function which transforms variable of one type to another]
            if not operator: continue
            hints[arg_name] = AnyHttpUrl if self.http_only else AnyUrl  # whether proprietary protocols are allowed
            def wrapper(_arg_name, _operator, **kwargs):
                kwargs[_arg_name] = _operator(kwargs[_arg_name])
                return for_mcp(**kwargs)
            for_mcp = functools.partial(wrapper, _arg_name=arg_name, _operator=operator)
            functools.update_wrapper(for_mcp, fn)
        for_mcp.__annotations__ = hints
        for_mcp.__name__ = fn.__name__  # added during testing because I realized this does not do this after wrapped oops
        for_mcp.__doc__ = fn.__doc__  # but is inconsequential to the root question above
        return for_mcp

It is unclear whether functools.partial can be used here, specifically, as well; I notice that the error message fails to recognize that the wrapped function should have a name. But this is a pretty simple piece of code except for the slightly recursive use of the for_mcp variable.

Thanks.

Example Code

Version Information

FastMCP version:                                                           3.0.1
MCP version:                                                              1.26.0
Python version:                                                           3.13.9
Platform:                                      macOS-26.3-arm64-arm-64bit-Mach-O

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementImprovement to existing functionality. For issues and smaller PR improvements.serverRelated to FastMCP server implementation or server-side functionality.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions