MCP result cache: SHA-256 keys, per-source TTLs, query normalizer

Gadoes adds a caching layer for MCP tool results to reduce repeated hits on external legal sources. Migration `004_cache_results.sql` defines the backing table; `queryNormalizer.ts` canonicalises inputs before hashing; `CacheManager` handles get/set/expiry with two TTL tiers.

infrastructureintegration

Schema. mcp_cache stores cache_key (SHA-256 hex, primary key), source, query, result_json, created_at, and expires_at. Two indexes: on expires_at for TTL sweeps and on source for per-source queries. The same migration is duplicated into supabase/migrations/ alongside copies of 001-003, suggesting the project migrated to Supabase tooling here.

Query normalizer. queryNormalizer.ts is 21 lines. It lowercases, collapses whitespace, and strips trailing punctuation. The key test case: all four variants of "FIDIC time-bar", "fidic time-bar", " FIDIC TIME-BAR ", and "FIDIC time-bar." hash to the same cache key.

CacheManager. 78 lines. Cache key is SHA-256("{source}:{normalizedQuery}"). TTLs are split: stable sources (al-meezan, italaw, icsid) get 86,400 seconds (24 hours); live sources (courtlistener, eurlex, govinfo) get 3,600 seconds (1 hour). The tests exercise expiry correctly using Vitest fake timers, including the case where a stable-source entry survives past the live TTL threshold.

One thing to check before relying on this: queryNormalizer handles the common case but may not cover all input shapes from sources you add. The normalizer is the right place to extend, but it's short enough that edge cases are easy to miss.

So what Worth importing if you're running any live MCP sources at volume. The implementation is small (about 230 lines of new code) and well-tested. The duplicate migration paths between `backend/migrations/` and `supabase/migrations/` are intentional but do mean two places to keep in sync going forward.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

2 commits from Gadoes/dispumike, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
19dfc0a4 Chunk 17: Caching Layer (queryNormalizer, CacheManager, migration 004) Gadoes 2026-05-02 ↗ GitHub
2affe555 Merge Chunk 17: Caching Layer Gadoes 2026-05-02 ↗ GitHub

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-25.md from inside the repo you want the changes in.

⬇ Download capture-thread-25.md