Coalent ships an MCP server: coalent-mcp New in v0.6.1. It puts the cache behind the
Model Context Protocol so any MCP client — Claude Code, Claude Desktop, Cursor — gets fresh,
attributed facts that are invalidated the moment a source changes, in one tool call.
pip install "coalent[mcp]" # the server (add ,openai for folder mode)
One tool surface, two deployment modes. Factory mode (bring your own stack) is the primary
mode — and it is measured to transmit library quality with zero loss: on the 609-article
benchmark corpus, 100 frozen benchmark questions driven through get_context scored 0.7100
strict accuracy — byte-identical to the library's own 0.7100 on the same questions (identical
CIs, 100/100 served, 0 errors, 98/100 payloads byte-equal to the library's store). The MCP layer
is glue; the library is unchanged behind it.
Factory mode — bring your own vector DB (primary)
Your factory function returns a fully user-constructed SemanticCache: your retriever /
vector DB, your embedder, your LLM, every knob — including store= for persistence and
pool_header= for attribution. The server adds only the protocol.
# my_cache.py — importable from the directory you launch in (cwd is on sys.path)
from coalent import (SemanticCache, LLMSynthesizer, OpenAIProvider,
OpenAIEmbedder, SQLiteCognitionStore)
def build() -> SemanticCache:
return SemanticCache(
my_vector_retriever, # YOUR index, unchanged (Qdrant/Chroma/pgvector/...)
LLMSynthesizer(OpenAIProvider(), model="gpt-4o-mini"),
embedder=OpenAIEmbedder(),
read_path="pool", # the measured v0.6 operating point
pool_header=my_header, # your metadata: "[title | source | date]"
residual_spans=True, query_keys=True,
store=SQLiteCognitionStore("kb.db"),
)
Add it to Claude Code:
claude mcp add coalent -- coalent-mcp --cache-factory my_cache:build
Or in .mcp.json (project-scoped, works in any MCP client):
{
"mcpServers": {
"coalent": {
"command": "coalent-mcp",
"args": ["--cache-factory", "my_cache:build"]
}
}
}
A broken factory fails loud at startup with the module:function named — never a silently
misconfigured server. Factory mode demands no OPENAI_API_KEY of its own: your factory brings
its own models.
Freshness in factory mode is signal-driven: your ingestion pipeline calls the
source_changed tool when a document changes, and every cached fact derived from it invalidates
immediately. You can also add --watch DIR alongside the factory — the folder scan then fires
source_changed for edited files. Honest caveat: watching never ingests into your index (two
corpora — yours is the retriever); it only invalidates, and only when your artifact_ids equal
the watch-relative file paths.
Folder mode — the zero-config wedge
No index yet? Point the server at a folder:
claude mcp add coalent -- coalent-mcp --watch ./docs
This mounts the recommended v0.6 deployment (read_path="pool", residual spans, query keys)
over the directory: files are paragraph-chunked into the library's built-in vector retriever,
artifact_id is the relative file path, and attribution ships the golden path automatically —
pool_header is wired to [{path} | modified {YYYY-MM-DD}] per source group, so the measured
0.68-vs-0.73 header-ladder gap never opens here. The cache persists to
<watch-dir>/.coalent/store.db (override with --store); an untouched folder restarts fully
warm. Folder mode requires OPENAI_API_KEY (embeddings + gpt-4o-mini build synthesis) and exits
loudly without it — it never degrades to the lexical embedder.
Folder mode has a measured cost. On the same 100 benchmark questions, folder mode scored 0.46 vs factory mode's 0.71 (40 vs 18 refusals) — the price of generic paragraph chunking plus keyhole lazy builds over a fresh corpus, versus your own tuned index. It is the honest zero-config on-ramp, not the destination. When you have a real vector DB, use the factory.
Flags: --ext md,txt,mdx,rst (watched extensions), --budget 1000 (serve budget in estimated
tokens), --store PATH. With --cache-factory, the folder-mode flags --store and --budget
are refused loudly — your factory sets those itself.
HTTP mode — one shared cache for many agents
--transport stdio is the default: the client launches the server as a child process.
coalent-mcp --cache-factory my_cache:build --transport http --port 8765
--transport http (streamable HTTP) runs one long-lived process, many concurrent clients,
one shared cache — what one agent learns (builds, confirmed query keys), every agent gets.
A single lock serializes every tool body (serves are milliseconds; the lock also means two
concurrent identical misses build once, not twice).
Validated on the benchmark corpus: 2 concurrent clients interleaving 20 reads produced answers identical to the sequential run (20/20), one shared cache, zero errors and zero duplicate synthesis — warm hits observed across clients.
Set COALENT_MCP_TOKEN to require Authorization: Bearer on every request. Bind localhost or
trusted networks; multi-tenant auth is deliberately out of scope for this server.
stdio is single-writer. Each stdio server is a per-client child process, and a store must
have one writer. Do not point two stdio servers at the same --store (or the same factory
store) — that is exactly what --transport http is for: one server process owns the cache,
every agent shares it.
The seven tools
| Tool | What it does |
|---|---|
get_context(query, budget?) | The read. Returns the budget-packed, per-source-attributed fact payload, the contributing sources[], cache_hit, and a read_id. In folder mode it rescans watched files (mtime + content hash) before serving. |
report_refusal(read_id) | Your answerer refused over a payload? Returns a retry payload of up to 2 attributed verbatim source excerpts the extraction missed (payload=null if none qualifies). Zero LLM / retrieval calls. |
report_success(read_id) | Confirm a retry succeeded — the refused query becomes a durable alternate retrieval key on the fact that rescued it (persisted across restarts). |
source_changed(artifact_id, text?) | New in v0.6.1 The BYO freshness signal: every cached fact derived from artifact_id invalidates immediately. With text, unchanged content is hash-detected and skipped. In folder mode it works as a manual override; the scan stays authoritative. |
list_sources() | Watched files with freshness state (fresh / stale-pending / new-pending / removed-pending) + last-modified. Empty without folder watching. Read-only. |
cache_stats() | The library stats() dict: units, reads, hits, staleness_prevented, pool-gate diagnostics. |
refresh() | Force a full folder rescan now; returns what was added / changed / removed and how many units were invalidated or evicted. |
The freshness guarantee
In folder mode, every get_context call scans the watched files before serving; a file whose
content actually changed invalidates its derived facts first. You cannot get a stale answer
after saving a file. In factory mode the same guarantee holds from the moment your pipeline
calls source_changed.
This was probed at the answer level during validation: mid-run file edits flipped the served answers themselves (a top-speed fact 143.7 → 178.2 mph; a passenger count 2.94M → 4.61M) on the very next read, and zero stale serves were observed across the entire validation — every smoke, every probe.
One benign regime note. A question about a just-added file can honestly refuse from a
warm pool until a build fires for the new content — the gate prefers refusal over serving
facts it doesn't yet have. Nothing stale is ever served; ask again (or call refresh()) and
the build lands. This is the documented serve-vs-build gate behavior, not a freshness hole.
Out of scope (documented, not forgotten)
MCP sampling (using the client's LLM for builds), resources/prompts surfaces, multi-dir namespaces, non-text files, multi-tenant auth.
Next
- LangChain — the same BYO-first principle as a LangChain integration.
- Context intelligence — the pool read path the server deploys.
- Provenance & freshness — what
source_changedacts on. - Example — MCP & tool results — the inverse direction: caching your MCP tools' results.