You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(handlers): remember/recall/get_telemetry return dict not str (issue #17)
PSGSupport reported strict MCP clients (Claude Code tool runtime)
rejecting these three handlers with "structured_content must be a
dict or None. Got str". The DB writes happened but FastMCP rejected
the response before delivery to the client.
Root cause: mcp_server/tool_error_handler.py:safe_handler used to wrap
every handler return value in json.dumps(...) and return the JSON
string. FastMCP 2.x validates structured content against the declared
output_schema and rejects non-dict returns. Three handlers
(remember, recall, get_telemetry) declare output_schema and so failed;
others without output_schema worked because FastMCP auto-wraps strings
when no schema is declared.
The fix returns the dict directly from safe_handler (with a defensive
{} fallback for None). All tool registry signatures updated from
-> str to -> dict to match.
Liskov: every MCP handler now uniformly returns dict (or None) per
the output_schema contract. Added a contract-enforcement test in
tests_py/server/test_handler_contract.py that asserts the invariant
across all registered tools, so future handlers can't silently
regress this.
Also pinned the dict-not-str contract in:
- tests_py/handlers/test_get_telemetry.py (new file)
- tests_py/handlers/test_remember.py (TestRememberReturnsDict class)
- tests_py/handlers/test_recall.py (TestRecallReturnsDict class)
- tests_py/integration/test_cold_start.py (TestToolErrorHandler updates)
Verification: 16 new/updated tests pass; full handlers + server +
cold_start sweep stays green (355 passed).
Closes#17.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments