fleet-memory/hindsight-api/hindsight_api
DK09876 e798979733
Harden MCP server: fix routing, validation, and usage metering (#341)
* fix: move mental model usage metering into engine for MCP support

Mental model validation hooks (validate_mental_model_get, validate_mental_model_refresh)
were only called in REST HTTP handlers, not in the engine. MCP tools call engine methods
directly, so usage metering was skipped entirely for MCP mental model operations.

Moved pre-validation and post-completion hooks into memory_engine.py (matching the
retain/recall/reflect pattern) and removed the duplicate code from http.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove double validation from create_mental_model and add internal checks

- Remove pre-validation from create_mental_model since callers always call
  submit_async_refresh_mental_model next (which validates), preventing
  double credit checks
- Add is_internal checks to mental model metering validators (matching
  the existing pattern for recall/reflect) so background worker tasks
  skip billing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: prevent 307 redirect on /mcp that breaks MCP tool discovery

Starlette's Mount class redirects /mcp to /mcp/ with a 307 Temporary
Redirect. Many MCP clients don't follow POST redirects, which causes
tool discovery to fail (0 tools discovered despite successful auth).

Add _MCPPathRewriteMiddleware that rewrites /mcp to /mcp/ at the ASGI
level before routing, preventing the redirect entirely. Both /mcp and
/mcp/ now work identically.

Add regression test test_mcp_no_trailing_slash_works to verify URLs
with and without trailing slashes discover tools correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* harden MCP server for real-world usage

- Remove MCP_ENDPOINTS blocklist so banks named "sse"/"messages" route correctly
- Scope SSE body rewriting to text/event-stream responses only to prevent data corruption
- Add _validate_mental_model_inputs for name, source_query, max_tokens validation in MCP tools
- Improve "not found" error messages to include bank_id context
- Fix fragile tool count assertions (exact → minimum bounds)
- Add integration tests: tool execution, input validation, edge-case bank names
- Add unit tests for validation helper and tool-level validation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: replace Mount + rewrite middleware with wrapping middleware

Starlette's Mount class redirects /mcp -> /mcp/ with 307, which MCP clients
don't follow. Previously we patched this with _MCPPathRewriteMiddleware.

Now MCPMiddleware wraps the FastAPI app directly via add_middleware, intercepting
/mcp* requests before they reach Starlette's router. No Mount means no redirect.

- Remove _MCPPathRewriteMiddleware (no longer needed)
- Remove app.mount() call
- Add prefix parameter to MCPMiddleware
- Use app.add_middleware() for proper Starlette integration
- Simplify path stripping (just remove prefix, no mount/root_path handling)
- Update routing test to match current behavior (no MCP_ENDPOINTS blocklist)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update stale docstring referencing removed _MCPPathRewriteMiddleware

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 10:41:20 +01:00
..
admin feat: new 'worker' service (#176) 2026-01-20 10:17:56 +01:00
alembic feat: support markdown in reflect and mental models (#307) 2026-02-06 10:49:13 +01:00
api Harden MCP server: fix routing, validation, and usage metering (#341) 2026-02-11 10:41:20 +01:00
engine feat: add mental model CRUD tools to MCP server (#337) 2026-02-10 22:40:43 +01:00
extensions doc: prepare doc for 0.4.10 (#325) 2026-02-09 11:42:37 +01:00
worker Fix: load operation validator extension in worker process (#280) 2026-02-02 14:45:40 -05:00
__init__.py Release v0.4.10 2026-02-09 11:44:20 +01:00
banner.py fix: do not log db user/password (#312) 2026-02-09 10:15:03 +01:00
config.py feat: add otel traceability (#330) 2026-02-10 12:20:48 +01:00
daemon.py feat: improve openclaw and hindisght-embed params (#279) 2026-02-03 09:39:04 +01:00
main.py feat: add otel traceability (#330) 2026-02-10 12:20:48 +01:00
mcp_local.py feat(mcp): add timestamp to retain (#190) 2026-01-23 16:00:43 +01:00
mcp_tools.py Harden MCP server: fix routing, validation, and usage metering (#341) 2026-02-11 10:41:20 +01:00
metrics.py chore: remove dead code (#245) 2026-01-30 09:16:32 +01:00
migrations.py fix(helm): improve appVersion usage (#326) 2026-02-09 11:35:08 +01:00
models.py Add user_initiated flag to RequestContext for async task attribution (#338) 2026-02-10 22:37:42 +01:00
pg0.py feat: support vertex as llm provider (#233) 2026-01-29 16:13:57 -05:00
server.py Fix: Load extensions in server.py for multi-worker deployments (#155) 2026-01-13 17:55:33 +01:00
tracing.py feat: add otel traceability (#330) 2026-02-10 12:20:48 +01:00
utils.py fix(helm): improve appVersion usage (#326) 2026-02-09 11:35:08 +01:00