Claude Code & MCP

The Coalent MCP server — fresh, attributed facts in any MCP client. Bring your own vector DB (factory mode), or point it at a folder. Validated byte-identical to the library.

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.

i

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

ToolWhat 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.

i

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