echocache
echocache
An MCP server for a cached LLM response — the way an HTTP cache caches an expensive server response, not the way a browser caches a static asset. Ask a question you already answered once, and the answer echoes back instead of being re-derived.
Two lookup paths, inspired by two different kinds of caching:
Exact-match, HTTP-style —
cache_get/cache_setkey on(model, prompt, params), withttl_secondsandstale_while_revalidate_secondsbehaving likeCache-Control: fresh, stale, or expired.Knowledge-graph recall — every stored entry is a node in a small similarity graph.
cache_queryfinds related entries by meaning, not just exact key;cache_relatedwalks graph edges (auto-linked "similar" entries, or explicit "derived-from" parents) to surface everything already known before an agent redoes work from scratch.cache_invalidatecan cascade through thosederived-fromedges when a source changes.
Runs as a standard stdio MCP server, so it works with Claude Code, Claude Desktop, Cursor, VS
Code + Copilot, or any other MCP-capable host — see Install below, and
AGENTS.md for the tool-use protocol any connected agent should follow.
What it's for — and what it isn't
Cache what an agent concluded, never what it read. This is the whole design, and it is worth stating plainly because the intuitive use is the wrong one: serving a cached file read costs the reader exactly the tokens that reading the file cost, since the content still has to enter the context. So caching file reads saves nothing at any hit rate, and if the agent re-emits the file to store it, that's output-rate tokens paid for zero benefit. A cache only pays when a hit stands in for regenerating something.
Where it pays, and where measurement said it does not:
Pays best: an expensive research or judgment call. A real 22-tool-call research chain in this project's own history cost 37,119 output tokens to reach a 255-token conclusion — a 728x gap against serving that conclusion back, weighted for output pricing. A single reuse pays for the write ~145x over. Live-validated the same way with a fresh web-search-derived design decision, correctly recalled by different wording and correctly outranking an unrelated entry sharing surface vocabulary. Not proven to recur yet in this project's own history — but the payoff on one hit is large enough that low frequency isn't disqualifying, unlike a file read.
Pays conditionally: re-orientation across sessions. An agent reads a codebase to understand it, the session ends, and a later session needs that understanding again. On
express/lib— six files, 62KB — re-reading the source costs 15,504 tokens against 549 to serve the cached orientation, about 28× fewer. That holds when the later session genuinely needs broad understanding; if it only needs one specific answer, it will grep and read a slice for ~900 tokens, and the cache isn't competitive.Does not pay: replacing reads in a parallel dispatch. Thirty subagents in one code-review dispatch pulled ~374,000 tokens of content a sibling had already read — but 127 of their 166 reads used
offset/limit, so they were already taking slices rather than whole files. Substituting a shared derivation for those slices measured 27% worse than what they actually did: grep is already a cheap, precise pointer, and a cached map competes with it on its own ground and loses.
The rule all three point at: cache what grep cannot reconstruct. A conclusion, a judgement, the reason something is the way it is, a cross-file synthesis no single search reveals, a research finding, the fact that something is absent. Never a location — grep finds those for less than the cache costs to consult — and never a file.
When a cached entry does carry file paths or line numbers, that is to point a reader at exact
detail, not to replace reading it. And reach for cache_query rather than cache_get when
looking for a match: a later session, or another agent, will not phrase the question the way the
writer did.
What this is not: a way to avoid reading files, a source of truth, or a substitute for prompt caching within one conversation, which is cheaper and needs no server. echocache is for results that must outlive the context that produced them.
What Claude Code already does for free
If your only host is Claude Code, its own persistent memory already does the core of this: write a conclusion to a memory file instead of the files it came from, and a later session reads it back before redoing the work. That's the same rule this project converged on, running for free, with no server to register. This project's own findings and measurements from building it are stored there, not in echocache itself — worth noticing, since it means the tool wasn't used to cache the very research that produced it.
What's actually different, in order of how much it matters:
Cross-project sharing. Claude Code's memory is scoped to one project directory. echocache is one SQLite file any project on the machine can register against, so a conclusion reached in one repo is queryable from another. Real, but unproven: this project's own history shows zero instances of a conclusion actually getting reused across sessions, and cross-project reuse is a narrower bar than that.
Semantic recall.
cache_queryfinds a match by meaning, independent of how it was phrased or which file it's filed under. Memory is retrieved by an always-loaded index plus the agent's own judgment about what to open — no vector search.Host-agnostic. Works from Cursor, VS Code, Claude Desktop, or any other MCP client — memory is native to Claude Code specifically.
Explicit freshness. TTL/stale-while-revalidate freshness and hash-based
derived_frominvalidation catch a source going stale automatically. Memory has neither; staleness is caught only if an agent happens to notice.
For a single user on a single host in one project, memory already captures most of the value here for free. What's left as echocache's actual case is narrower than "a cache for LLM responses": it's specifically sharing a derivation across projects or hosts that don't already share a memory store — and that narrower case is unproven, not just untested, until it's been measured the way everything else in this document has.
Related MCP server: mcp-llm
Install
No clone or build needed — register it straight from npm.
Claude Code
claude mcp add echocache -- npx -y echocacheClaude Desktop / Cursor / VS Code — add a stdio entry to the host's MCP config
(claude_desktop_config.json, .cursor/mcp.json, .vscode/mcp.json):
{
"mcpServers": {
"echocache": {
"command": "npx",
"args": ["-y", "echocache"]
}
}
}Any other MCP-capable host takes the same launch command; only the config file differs. Then point
your agent at AGENTS.md so it knows when to reach for the cache — the protocol
matters more than the wiring, since caching the wrong things costs tokens rather than saving them.
Configuration
Every setting is an environment variable, all optional:
Variable | Default | Meaning |
|
| SQLite file location |
|
| LRU ceiling on retained entries |
|
| LRU ceiling on retained response bytes |
|
| Freshness lifetime when a caller omits one |
|
| Similarity floor for auto-linking entries |
|
| Recent entries a new write is compared against |
| unset | 64 hex chars (32 bytes); enables AES-256-GCM at rest |
The database directory is created 0700 and its files 0600. Set an encryption key to also
encrypt entry contents at rest:
export ECHOCACHE_ENCRYPTION_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")Turning encryption on or off requires a fresh database — there is no in-place migration, and a key/database mismatch is refused at startup rather than failing on some later read.
Tools
Tool | Purpose |
| Exact-match lookup with fresh / stale / expired freshness |
| Store a result; auto-links it into the similarity graph |
| Semantic search across all cached entries |
| Graph traversal from one entry to entries linked to it |
| Delete an entry, optionally cascading to its dependents |
| Exact-match hit rate, |
One SQLite file backs all of them, shared across every project that registers the server — a conclusion reached in one repo is queryable from another. Concurrent readers and writers from separate processes are the expected case, not an edge case.
Developing
git clone https://github.com/kskurtveit/echocache && cd echocache
npm install
npm run check # typecheck + tests
npm start # or: npm run devSee CLAUDE.md for architecture and the module reference.
License
MIT
Available Tools
6 toolscache_getA
Look up a cached LLM response by exact (model, prompt, params) match, like an HTTP cache checking a request against its cache key. Call this BEFORE issuing an expensive prompt to a model. Returns hit:false on a miss or an expired entry — in that case, run the prompt yourself and store the result with cache_set. On a hit, freshness mirrors HTTP semantics: fresh means use it as-is; stale means it is past its TTL but within its stale-while-revalidate window, so you may still use it but consider refreshing it.
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | Model/tool identifier the response came from, e.g. "claude-sonnet-5" | |
| params | No | Other call parameters that affect the response (temperature, system prompt, etc.) | |
| prompt | Yes | The exact prompt or request text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations and no output schema, the description carries the behavioral burden and does it well: it discloses exact-match semantics, the hit:false miss/expired case, and the fresh vs stale distinction. It could be slightly more explicit about the shape of a hit:true response, but the freshness semantics go beyond what the schema reveals.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, all of which contribute: exact-match semantics, when to call, what to do on miss, and freshness handling. It is slightly dense but not wasteful, and the most important usage directive is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a cache lookup with no annotations and no output schema, the description gives the essential runtime semantics: miss behavior, expired-entry behavior, and fresh/stale handling. It could explicitly state the hit:true payload yields the cached response and mention alternatives like cache_query for non-exact lookups, but overall it is complete enough to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already covers all three parameters with 100% coverage, so the baseline is 3. The description adds value by explaining that model, prompt, and params together form the cache key for an exact match, which connects the parameters to the tool's behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Look up a cached LLM response by exact (model, prompt, params) match.' The exact-match qualifier and the HTTP cache analogy clearly define what the tool does and how it differs from sibling tools like cache_set or cache_query.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly tells the agent to call this 'BEFORE issuing an expensive prompt' and instructs what to do on a miss: run the prompt and store with cache_set. It lacks explicit comparisons to cache_query or cache_related, so it does not fully differentiate all sibling alternatives, but the core usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cache_invalidateA
Delete a cache entry, e.g. because the underlying source it was based on changed. With cascade:true, also deletes every entry that declared this one as a derived_from parent, and recursively theirs — dependency-graph invalidation instead of a manual hunt for stale copies.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| cascade | No | Also delete entries derived from this one, default false |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided at all, the description carries the full burden of behavioral disclosure. It does well: it reveals the destructive nature ('Delete'), the cascade semantics ('every entry that declared this one as a derived_from parent'), and recursion behavior. It does not mention edge cases like missing-id handling or irreversibility, but the core behaviors are transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler; the core action is front-loaded and the cascade nuance follows. The second sentence is semantically dense with nested clauses but earns its length by explaining recursive behavior and the rationale. Slightly compressed structure, but every part adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive 2-parameter tool with no annotations and no output schema, the description covers the main essentials: purpose, trigger scenario, and the cascade option's full behavior. Missing details are limited to edge-case behavior (nonexistent id, error handling, reversibility), which are conventional for cache invalidation and not severe gaps for an agent to proceed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 50%: the cascade parameter has a schema description but id does not. The description enriches the cascade semantics well (derived_from parent, recursive invalidation), adding meaning beyond the schema's 'Also delete entries derived from this one'. However, id receives no additional semantic context, and the description doesn't fully compensate for the missing id doc, though the parameter is fairly self-explanatory.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Delete a cache entry') and the specific resource, with a concrete motivating example ('underlying source it was based on changed'). It is clearly distinct from sibling cache_get/cache_set operations by virtue of being a deletion, though it does not explicitly name and differentiate from sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear when-to-use scenario: invalidate when the underlying source changed. It also explains the key decision between cascading and non-cascading deletion ('dependency-graph invalidation instead of a manual hunt for stale copies'). It lacks explicit exclusions or named alternatives, but the context is sufficiently clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cache_queryA
Semantic search across all cached entries, independent of exact key matching. Use this when you suspect something related was already computed even though the prompt wording differs — the knowledge-graph equivalent of a cache lookup by meaning instead of by exact key.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Text to search for semantically related cache entries | |
| top_k | No | Max results, default 5 | |
| min_similarity | No | Similarity floor 0-1, default 0.3 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the full burden of behavioral disclosure. It adds useful context: the search spans all cached entries and matches by meaning rather than exact key, implying a read-only lookup. However, it does not state whether it mutates anything, what it returns, or any performance implications of scanning all entries.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core function and then the trigger condition. The 'knowledge-graph equivalent' metaphor adds color but somewhat restates the first sentence, making it slightly less tight than it could be. Overall, it is still concise and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers what the tool does and when to use it, and the schema covers parameters. However, since there is no output schema, the description omits any indication of return shape or size. It also doesn't mention potential cost or side effects of searching 'all cached entries,' so the profile is adequate but has clear gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with each parameter already documented meaningfully (text, top_k, min_similarity). The tool description adds no parameter-specific information beyond what the schema provides, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Semantic search across all cached entries.' It also draws a clear contrast with 'exact key matching,' which distinguishes it from sibling tools like cache_get. An agent can tell what this tool does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when to use the tool: 'when you suspect something related was already computed even though the prompt wording differs.' It implies exact-key lookups are not its purpose by stressing 'independent of exact key matching,' though it doesn't name a specific alternative tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cache_setA
Store a prompt/response pair in the cache. Call this AFTER getting a fresh response from a model that cache_get did not have. New entries are automatically linked in a similarity graph to existing entries with related content, so cache_related and cache_query can surface them later even without an exact key match. Pass derived_from with parent entry ids if this result was built from other cached entries — invalidating a parent with cascade can then clean up anything derived from it.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| model | Yes | ||
| params | No | ||
| prompt | Yes | ||
| response | Yes | The response text to cache | |
| ttl_seconds | No | Freshness lifetime in seconds. null = never expires. Default: 1 day | |
| derived_from | No | Ids of parent entries this was built from | |
| stale_while_revalidate_seconds | No | Extra window after TTL expiry where the entry is still returned, marked stale |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden, and it discloses non-obvious behavior: automatic similarity-graph linking, its effect on cache_related and cache_query, and cascade invalidation via derived_from. It stops short of stating duplicate-key behavior, return values, or key composition, but the main side effects are covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, each earning its place: purpose, usage timing, automatic linking behavior, and derived_from semantics. The most important action is front-loaded and no filler is present.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the critical workflow (post-miss write, graph linkage, cascade invalidation) well enough for an agent to invoke correctly with the required fields. Missing return-value expectations and duplicate-handling behavior are minor gaps given the absence of an output schema, but the core context is solid.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 50%, and the description adds real meaning for derived_from (parent/cascade relationships). However, tags and the free-form params object receive no guidance, and the description does not compensate for those undocumented parameters. Optional fields like ttl_seconds rely entirely on the schema's default notes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence 'Store a prompt/response pair in the cache' states a specific verb and resource, and the references to cache_get, cache_related, and cache_query clearly situate it among the sibling tools. An agent can immediately distinguish this write operation from the read/query/invalidate siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs when to call: 'AFTER getting a fresh response from a model that cache_get did not have,' which names the triggering condition and the primary alternative (cache_get). The derived_from guidance adds a conditional usage rule for derived entries, leaving little ambiguity about when this tool is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cache_statsA
Cache analytics: entry/edge counts, exact-match hit rate, queryHits/queryMisses for semantic recall, and tokensServed — the token count handed back from cache. Note that tokensServed equals tokens saved only for entries that stand in for work which would otherwise be regenerated; serving a cached file read costs the same tokens as re-reading the file, so it saves nothing.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It adds a genuinely useful behavioral nuance: tokensServed equals tokens saved only for entries avoiding regeneration, not for cached file reads. It does not explicitly state read-only behavior, but 'analytics' and the absence of mutation verbs imply no side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the label front-loaded in 'Cache analytics'. The first sentence enumerates the return metrics; the second adds a necessary caveat about tokensServed. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter analytics tool with no annotations or output schema, the description covers the main return values and even clarifies a subtle metric. It does not specify the exact response container or explicitly state that the call is read-only, but those are minor gaps for this simple tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so parameter documentation is moot. The rubric's baseline for 0 params is 4, and the description needs no clarifification of parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the tool as 'Cache analytics' and lists concrete metrics (entry/edge counts, exact-match hit rate, queryHits/queryMisses, tokensServed), making its role clear. It is distinguishable from the sibling get/set/query/related/invalidate tools by being an analytics/stats tool, though it lacks an explicit verb like 'retrieves'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description does not mention siblings or exclusions, but the phrase 'Cache analytics' plus the metric list implies this is the tool to use when cache statistics are needed. There is no explicit when-not-to-use guidance, so it stops short of a 4.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
6 tool updates
v0.1.1- First observed
cache_get - First observed
cache_invalidate - First observed
cache_query - First observed
cache_related - First observed
cache_set - First observed
cache_stats
TDQS
Each tool targets a clearly distinct operation: exact-match lookup, storing new entries, semantic search, graph traversal, invalidation, and analytics. Even though cache_query and cache_related both deal with connected content, the descriptions make their different access patterns unambiguous.
All tools share a consistent cache_ prefix and mostly use a verb as the second element: get, set, query, invalidate, stats. cache_related is the one outlier since 'related' is not a verb, but the overall pattern is still highly predictable.
Six tools is well-scoped for a cache server: read, write, semantic access, graph traversal, invalidation, and statistics. Each tool earns its place without redundancy or bloat.
The cache lifecycle is well covered: exact lookup, storage with derived-from tracking, semantic retrieval, related-entry traversal, invalidation with cascade, and stats. Minor gaps like bulk clearing or listing all entries could be useful but are not essential for the stated purpose.
Maintenance
Related MCP Connectors
Cloud-hosted MCP server for durable AI memory
AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
An MCP memory server. One memory your agents share — across models, devices and apps.
Related MCP Servers
- FlicenseBqualityDmaintenanceA Model Context Protocol (MCP) server that optimizes token usage by caching data during language model interactions, compatible with any language model and MCP client.42-
- MIT
- AlicenseBqualityDmaintenanceMCP server providing context usage estimation, conversation compaction, and durable semantic memory via local embeddings and SQLite.17143MIT
- FlicenseNot gradedqualityAmaintenanceLocal MCP server that lets your AI coding agent query its own cross-tool project history - file/command freshness, past test failures, cost & token spend, cache status, and session handoff - over stdio, 100% local, no telemetry.42-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kskurtveit/echocache'
If you have feedback or need assistance with the MCP directory API, please join our Discord server