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.
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.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?