PrefectHQ/fastmcp · error · TypeError
server/discover handler returned {type(raw).__name__}; expec
Error message
server/discover handler returned {type(raw).__name__}; expected DiscoverResult or mapping What it means
The low-level server/discover dispatcher expects the registered handler to return a DiscoverResult instance or a mapping that can be validated into one (unless the handler returned a raw string result outside CORE_RESULT_TYPES). Any other return type raises TypeError naming the actual type returned.
Source
Thrown at fastmcp_slim/fastmcp/server/low_level.py:362
message = _mw_ctx.message
params = (
message.params.model_dump(by_alias=True, mode="json", exclude_none=True)
if message.params is not None
else None
)
raw = await call_next(replace(ctx, params=params))
if isinstance(raw, mcp_types.DiscoverResult):
return raw
if isinstance(raw, Mapping):
result = dict(raw)
result_type = result.get("resultType")
if (
isinstance(result_type, str)
and result_type not in mcp_types.CORE_RESULT_TYPES
):
return result
return mcp_types.DiscoverResult.model_validate(result)
raise TypeError(
"server/discover handler returned "
f"{type(raw).__name__}; expected DiscoverResult or mapping"
)
async with Context(fastmcp=fastmcp, session=ctx.session) as fastmcp_ctx:
mw_context = MiddlewareContext(
message=discover_message,
source="client",
type="request",
method="server/discover",
fastmcp_context=fastmcp_ctx,
)
return await fastmcp._run_middleware(
mw_context,
cast("FastMCPCallNext[Any, Any]", call_original_handler),
)
async def _run_initialize_mw(View on GitHub (pinned to 1f02114297)
Solutions
- Return a DiscoverResult from the handler: return mcp_types.DiscoverResult(servers=[...]).
- Return a dict matching the DiscoverResult schema so model_validate can coerce it.
- If returning a string result intentionally, ensure it is not one of CORE_RESULT_TYPES or wrap it appropriately.
- Inspect the handler for middleware wrappers that may be converting the result to an unsupported type.
Example fix
// before
async def discover_handler(ctx, params):
return ["server-a", "server-b"] # TypeError: list returned
// after
async def discover_handler(ctx, params):
return mcp_types.DiscoverResult.model_validate({"servers": ["server-a", "server-b"]}) Defensive patterns
Strategy: type-guard
Validate before calling
def valid_discover_result(raw) -> bool:
import mcp.types as mcp_types
return isinstance(raw, (mcp_types.DiscoverResult, dict)) Type guard
def is_discover_result(raw) -> bool:
import mcp.types as mcp_types
return isinstance(raw, mcp_types.DiscoverResult) Try / catch
try:
result = await dispatch("server/discover", ctx, params)
except TypeError as e:
logger.error("Discover handler must return DiscoverResult/mapping: %s", e)
raise Prevention
- Always build handler returns via mcp_types.DiscoverResult.model_validate(...)
- Type-hint the handler's return as DiscoverResult and run a type checker
- Check middleware wrappers preserve the DiscoverResult return type
When it happens
Trigger: Registering a custom server/discover handler that returns e.g. a list, a string that is a core result type name, a pydantic model of the wrong type, or None where a result is required.
Common situations: Implementing a custom discovery handler returning plain Python lists of servers; wrapping/middleware that accidentally transforms the result; migrating a handler after the DiscoverResult result-type contract was introduced.
Related errors
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/45e51b950edd8001.
Report an issue: GitHub.