PrefectHQ/fastmcp · error · MCPError
METHOD_NOT_FOUND
METHOD_NOT_FOUND
Error message
Method {binding.method!r} is not available at protocol version {ctx.protocol_version!r}. What it means
When an extension method binding declares an explicit protocol_versions set, the dispatcher raises MCPError with code METHOD_NOT_FOUND if the current request's negotiated protocol version is not in that set. This mimics standard JSON-RPC 'method not found' semantics for version-gated extension methods.
Source
Thrown at fastmcp_slim/fastmcp/server/extensions.py:265
def build_method_handler(binding: MethodBinding) -> ExtensionRequestHandler:
"""Wrap a `MethodBinding` into a low-level request handler.
The adapter enforces `protocol_versions` gating (rejecting other versions as
`METHOD_NOT_FOUND`, since `add_request_handler` registers unconditionally)
and binds the FastMCP request context so the handler can use `get_context()`,
auth, and other request-scoped dependencies.
"""
async def handler(
ctx: ServerRequestContext[Any, Any], params: Any
) -> BaseModel | dict[str, Any] | None:
if (
binding.protocol_versions is not None
and ctx.protocol_version not in binding.protocol_versions
):
raise MCPError(
code=METHOD_NOT_FOUND,
message=(
f"Method {binding.method!r} is not available at protocol "
f"version {ctx.protocol_version!r}."
),
)
with bind_request_context(ctx):
return await binding.handler(ctx, params)
return handler
def wrap_tool_call_interceptor(
extension: ServerExtension,
call_next: Callable[[Any], Awaitable[Any]],
) -> Callable[[Any], Awaitable[Any]]:
"""Fold one extension's `intercept_tool_call` around a middleware `call_next`.
View on GitHub (pinned to 1f02114297)
Solutions
- Add the client's protocol version to the binding's protocol_versions set if the handler supports it.
- Remove protocol_versions (None) to make the method available at all versions if there is no version-specific behavior.
- Upgrade the client to a protocol version the binding supports.
- Handle MCPError code METHOD_NOT_FOUND on the client and degrade gracefully.
Example fix
// before
MethodBinding(method="myext/export", handler=h, params_type=P, protocol_versions=frozenset({"2025-06-18"}))
// after
MethodBinding(method="myext/export", handler=h, params_type=P, protocol_versions=frozenset({"2024-11-05", "2025-06-18"})) Defensive patterns
Strategy: try-catch
Validate before calling
def supports_version(binding, version: str) -> bool:
return binding.protocol_versions is None or version in binding.protocol_versions Type guard
def is_supported(binding, ctx) -> bool:
return binding.protocol_versions is None or ctx.protocol_version in binding.protocol_versions Try / catch
try:
result = await call_extension_method(binding, ctx, params)
except MCPError as e:
if e.code == METHOD_NOT_FOUND:
result = fallback_result() # degrade gracefully
else:
raise Prevention
- Gate the client-side feature on the negotiated protocol version before calling
- Omit protocol_versions if the handler works across versions
- Keep client and server MCP SDK versions aligned
When it happens
Trigger: A client connected at a protocol version (ctx.protocol_version) outside binding.protocol_versions invokes the extension method; e.g. binding declared frozenset({'2025-06-18'}) but client negotiated '2024-11-05'.
Common situations: Older clients (or older SDKs) calling a new extension method gated to a newer spec version; servers narrowing protocol_versions during a version migration.
Related errors
- elicitation via server-initiated requests is unavailable on
- MethodBinding cannot bind spec method {self.method!r}; exten
- Extension {self.identifier!r} is not bound to a FastMCP serv
- Task-enabled tools ({names}) require the tasks extension, bu
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/f2a274557c330592.
Report an issue: GitHub.