Skip to content

fix(recall): normalize tool output to JSON-native at the safe_handler boundary (v3.24.1)#66

Merged
cdeust merged 3 commits into
mainfrom
fix/recall-cross-backend-structuredcontent
Jun 23, 2026
Merged

fix(recall): normalize tool output to JSON-native at the safe_handler boundary (v3.24.1)#66
cdeust merged 3 commits into
mainfrom
fix/recall-cross-backend-structuredcontent

Conversation

@cdeust

@cdeust cdeust commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Problème

recall (et les 42 autres outils MCP) échouait côté PostgreSQL uniquement avec :

Output validation error: outputSchema defined but no structured output returned

Le backend PG renvoie des types non-natifs (numpy.float32, datetime) là où SQLite renvoie float/str. FastMCP ne sérialisait pas ces types → pas de structuredContent émis → rejet wire-level PG-only.

Root cause & fix

Correction au choke point safe_handler (mcp_server/tool_error_handler.py:144-181), pas par-store : to_json_native(result) est appliqué en sortie de chaque handler. Un seul point de normalisation → format de retour unique cross-backend pour les 43 outils.

  • mcp_server/shared/json_native.py (NEW) — to_json_native, normaliseur pur stdlib / duck-typing (numpy, datetime, Decimal, etc.).
  • mcp_server/tool_error_handler.pysafe_handler applique la normalisation.

Vérification

  • Repro avant/après (PG renvoyait numpy.float32/datetime, désormais natif).
  • 31 tests verts : tests_py/shared/test_json_native.py (NEW) + tests_py/server/test_handler_contract.py::TestWireValuesAreJsonNative (régressions backend-agnostiques).
  • Mutation testing 26/27 (1 mutant équivalent prouvé) — mutmut câblé dans ce même PR.

Inclus aussi (commit a83353d0)

  • Câblage mutmut : pyproject.toml [tool.mutmut], scripts/mutation_check.sh, standard coding-standards.md §12, template stryker.conf.json.
  • Release v3.24.0 → v3.24.1 : pyproject.toml / manifest.json / server.json + CHANGELOG.

Post-merge (manuel, hors PR)

Republier PyPI hypermnesia-mcp 3.24.1 + plugin → re-sync copie installée cortex/3.24.x → redémarrer la session. Tant que ce n'est pas fait, cortex:recall reste cassé côté PG dans les sessions en cours.

🤖 Generated with Claude Code

cdeust and others added 3 commits June 23, 2026 20:38
… boundary

The PostgreSQL store returns numpy.float32 scores and datetime timestamps
where SQLite returns float/str. FastMCP can only build structuredContent from
JSON-native values, so a non-native field dropped structuredContent and the
host rejected recall with "outputSchema defined but no structured output
returned" -- on PostgreSQL only, while SQLite-backed tests stayed green.

Add shared/json_native.py::to_json_native (pure, stdlib-only, duck-typed
numpy) applied at the tool_error_handler.safe_handler boundary every handler
crosses, so all 43 tools return one JSON-native shape across backends.
Regression tests are backend-agnostic (a fake PG-shaped handler) so CI fails
regardless of which store the suite runs against.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mutation testing is the objective check that the test suite can detect a
regression -- the recall bug shipped behind 100% green line coverage because
no test asserted JSON-serializability and the suite ran on SQLite (native
types), hiding the PostgreSQL-only failure.

Add mutmut 3.x to the dev group, [tool.mutmut] config, and
scripts/mutation_check.sh (scoped per-change runner that restores pyproject).
Demonstrated on shared/json_native.py: first pass surfaced dead code (an
unreachable .item() branch) and a test gap (invalid-utf8 bytes); after fixing
both, only a proven-equivalent mutant survives. gitignore the mutants/ working
dir. Bump 3.24.0 -> 3.24.1 (recall cross-backend fix).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 3.24.0→3.24.1 bump (a83353d) updated pyproject/manifest.json/server.json
but missed the two plugin manifests, reintroducing the exact version skew that
4b0994a previously fixed. The `version` field is the marketplace update signal:
leaving it at 3.24.0 means Claude Code never offers the update to existing
plugin/marketplace users, so the recall fix would not ship via the supported
(git-tree) channel. All five manifests are now 3.24.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cdeust cdeust merged commit 7a31a6e into main Jun 23, 2026
12 checks passed
@cdeust cdeust deleted the fix/recall-cross-backend-structuredcontent branch June 23, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant