Skip to content

fix(mcp): raise the FastMCP runtime ToolError instead of the legacy MCP SDK class #1197

Description

@phernandez

Summary

Core raises the legacy MCP SDK ToolError from mcp.server.fastmcp.exceptions, even though the server runtime is FastMCP 3.x and hosted middleware handles fastmcp.exceptions.ToolError.

Those are different Python classes. As a result, a structured hosted API error can escape the Cloud middleware as a bare tool failure instead of being converted into the intended friendly MCP result.

Evidence

Core currently imports the legacy class in the shared HTTP helper:

  • src/basic_memory/mcp/tools/utils.py:33
  • several individual tools and project-context paths use the same import

Under the currently locked dependencies:

from fastmcp.exceptions import ToolError as FastMCPToolError
from mcp.server.fastmcp.exceptions import ToolError as LegacyToolError

assert LegacyToolError is not FastMCPToolError
assert not issubclass(LegacyToolError, FastMCPToolError)

The concrete hosted failure is:

  1. Cloud's tenant API returns a structured 403 subscription_required response with a subscribe URL.
  2. Core's HTTP helper catches httpx.HTTPStatusError and wraps it in the legacy SDK ToolError.
  3. Cloud middleware catches the FastMCP runtime ToolError.
  4. The class mismatch bypasses conversion, so tools such as recent_activity surface only Active subscription required instead of the actionable subscription result.

Cloud can temporarily recognize both classes, but Core should emit the exception type owned by its active FastMCP runtime.

Proposed fix

  • While Core remains on FastMCP 3.x, replace legacy mcp.server.fastmcp.exceptions.ToolError imports with fastmcp.exceptions.ToolError across the MCP tool/runtime surface.
  • Keep the original httpx.HTTPStatusError as the explicit cause so hosted middleware can inspect structured response details.
  • Add a focused regression test proving the shared HTTP helper raises the FastMCP runtime class and preserves the HTTP cause.
  • Audit tests and deferred imports that still name the legacy SDK class.

Acceptance criteria

  • Core MCP tools consistently raise the ToolError class expected by the active FastMCP runtime.
  • Shared HTTP helpers preserve httpx.HTTPStatusError as __cause__.
  • Hosted middleware can catch a Core tool error without a compatibility import for the legacy MCP SDK class.
  • Unrelated tool errors continue to fail loudly.
  • Focused MCP tests and repository checks pass.

Related

  • feat(mcp): adopt FastMCP 4 beta and validate hosted MCP Apps #1181 tracks the FastMCP 4 beta port. That port may use a different supported exception path; this issue is the narrower current-runtime bug and should not wait on the full upgrade.
  • basicmachines-co/basic-memory-cloud#1666 exposed the inconsistent agent-facing subscription error while testing hosted MCP tools.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcloudBasic Memory CloudproductionObserved in production

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions