chist
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@chistfind that conversation about the Docker networking issue"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
chist
日本語版は README.ja.md。
Unified full-text search across your Claude Code, Codex, Cursor CLI, and Antigravity CLI chat history. Ingests every transcript into one SQLite database and lets you search it from a web UI, an MCP server, or the command line.
Ingestion and search run on the Python 3.9 standard library — zero dependencies. Only the MCP server needs an external package.

python3 -m chist ingest # incremental import
python3 -m chist search 'trigram' # full-text search
python3 -m chist show <ext_id> # read a conversationWhy
Chat history is scattered: each CLI keeps its own format in its own directory, and none
of them can see the others. When you already solved something months ago in a different
tool, you can't find it. chist normalizes all four into one schema and one index, so a
single query reaches everything — and project_key (derived from the git remote) groups
the same project across different machines and different tools.
Related MCP server: cursor-history-mcp
Features
Four sources, one index — JSONL for Claude Code / Codex / Cursor CLI, and raw protobuf-in-SQLite for Antigravity CLI (decoded without a
.protodefinition)Incremental ingest — unchanged files are skipped by mtime+size; changed ones resume from a byte offset, verified against a hash of the first 4 KB
CJK-capable search — FTS5 with the
trigramtokenizer, so Japanese substrings match (the defaultunicode61tokenizer cannot)Web UI — Svelte SPA with search, session browsing, and statistics
MCP server — lets an agent query its own history (
search_history,list_sessions,get_session)Multi-machine aggregation — each machine ingests locally and pushes deltas to a central server over HTTP
Secret masking — credentials are masked on display, and always before storage on the aggregation server
Measured performance
macOS, 1,034 files / ~1.86 GB of transcripts:
Metric | Value |
Initial ingest (all files) | 14.9 s |
Second run (no changes) | < 0.1 s |
Database size | 130 MB (including the FTS index) |
Search latency | ~0.05 s |
source | messages | sessions |
claude-code | 49,263 | 769 |
codex | 1,488 | 10 |
cursor-cli | 410 | 9 |
antigravity-cli | 225 | 3 |
Quick start (local, no Docker)
git clone https://github.com/you/chist-server.git
cd chist-server
python3 -m chist ingest
python3 -m chist search 'docker compose'The database defaults to ~/.local/share/chist/history.db (mode 600). Override it with
--db or CHIST_DB.
Options
search -s/--source filter by source (repeatable)
--host filter by machine (repeatable)
-c/--cwd substring match on the project path
-r/--role user | assistant | system | tool
--since / --until ISO 8601 (e.g. 2026-07-01)
-n/--limit default 20
--raw do not mask secrets
show --thinking include thinking blocks
ingest --limit N cap the number of files (for smoke tests)
prune --before / --after time range (ISO 8601)
-s/--source by source
--session by session (ext_id or id)
--match substring of the body (to undo a bad import)
--dry-run report counts without deleting
-y/--yes skip confirmation (required non-interactively)
--vacuum reclaim file size after deletingPruning history
Ingest is append-only, so the database only grows. Measured at 3.8–5.9 KB per message (the trigram index alone is ~1.9× the body), which is roughly 150–300 MB per year in daily use. Capacity is rarely the issue — the real need is removing something imported by mistake, or a conversation you don't want kept.
chist prune --before 2026-01-01 --dry-run # check the count first
chist prune --before 2026-01-01 --yes --vacuum
chist prune --match 'password' --dry-run # undo a bad import
chist prune --session <ext_id> --yesConditions combine with AND. With no condition it does nothing — deleting everything is deliberately not offered (remove the database file instead).
On the aggregation server, run the same CLI inside the container:
docker exec chist-server python -m chist prune --before 2026-01-01 --dry-runNotes:
Sources without timestamps (Cursor CLI) are still covered by time ranges — the session's end time is used as a fallback, so nothing is silently skipped
Without
--vacuumthe file does not shrink (space is only reused). VACUUM rewrites the database, so it needs free space equal to its sizeSessions left with no body are removed too (
--keep-sessionskeeps them). Empty sessions outside the delete set are never touchedIf the original log files still exist and you clear
ingest_state, a re-ingest brings the messages back. Delete the source files to remove them for goodNo prune tool is exposed over MCP — the tools are declared
read_only_hint, and a mistaken deletion cannot be undone, so deletion stays in the CLI
Server deployment
For multiple machines, run the aggregation server in Docker behind an existing reverse proxy. Each machine ingests locally and pushes only the delta.
cp .env.example .env # CHIST_TOKEN, CHIST_HOST, CHIST_BASICAUTH, …
docker compose up -d --build# on each machine (still dependency-free)
export CHIST_TOKEN=<same token>
python3 -m chist ingest
python3 -m chist push https://chist.example.comThe compose file reads every environment-specific value from .env, publishes no host
port, and joins the proxy's network directly. The Svelte UI is built in a
node:22-alpine stage and baked into the image, so the server does not need Node
installed. See docs/deploy.md.
Web UI
Three tabs — search, sessions, statistics. Opening a URL with ?q=<query> runs that
search immediately, and #search / #sessions / #stats select the tab, so results are
shareable as links. Light/dark themes follow the OS setting by default.
Filtering by machine is available from the web UI, the CLI (--host), and MCP.
In the web UI the machine filter and column appear only when two or more machines have
pushed — with a single machine they stay hidden. The list of machines is read from the
hosts table at runtime, so adding a machine needs no configuration.
MCP server
claude mcp add --transport http chist https://chist.example.com/mcpImplements MCP 2026-07-28 over stdio or streamable HTTP, read-only and stateless.
Tools: search_history, list_sessions, get_session. See
docs/mcp-setup.md.
For stdio use, the SDK requires Python 3.10+:
uv venv --python 3.12 .venv
uv pip install --python .venv/bin/python mcp
.venv/bin/python -m chist.mcp_serverOnly chist/mcp_server.py imports mcp. Ingest, search, and the CLI stay
dependency-free on the system Python.
Tests
Standard-library unittest only — the zero-dependency rule holds for the tests too.
python3 -m unittest discover -s tests -t .Server-side tests need the MCP SDK and skip automatically without it. To run everything, use the image:
docker run --rm -v "$PWD/tests":/app/tests:ro -w /app chist:latest \
python -m unittest discover -s tests -t /appThe suite covers behaviour that has actually broken, or could:
masking detects secrets and leaves ordinary prose alone (labels with no value, short placeholders, everyday commands)
session titles are masked, not just bodies — Cursor and Antigravity derive titles from the first user message
the same ext_id under two sources is ambiguous, and
sourceresolves itthe 3-character trigram floor, and that FTS special characters never raise
prune refuses to run without a condition, does not sweep up already-empty sessions, covers sources with NULL timestamps, and keeps the FTS index in step
foreign keys and
ON DELETE CASCADE; deduplication viaUNIQUE (source, ext_id, part)authentication (match, mismatch, and deny-all when no token is configured), the 64 MiB body cap, and malformed payloads
Security model
Never expose the app directly. Two route groups cannot authenticate themselves:
Path | Why | Protection |
| routed by the MCP SDK, bypasses the app's bearer check | proxy forwardAuth → |
| browsers cannot send a bearer token | proxy basicauth |
| — | bearer token in the app |
| — | unauthenticated by design (health checks) |
The shipped docker-compose.yml wires this up as three Traefik routers with an IP
allowlist on each. The server refuses to start without CHIST_TOKEN, so there is no
path to running it unauthenticated.
Secret masking
The local database stores raw text and masks on display (--raw disables it). The
aggregation server masks before storing, so push --raw still cannot put live
credentials into the server database.
Detected: known prefixes (sk-, ghp_, AKIA, AIza, Bearer, JWTs, PEM private
keys); labelled values — TOKEN=… plus password: / token: / secret: / api key: /
access key: and their Japanese equivalents, with the full-width colon accepted; and
credential-bearing commands (curl -u user:pass, htpasswd -nbB user pass).
A bare random string cannot be masked. With no label and no prefix there is nothing to
key on, and entropy-based detection produces too many false positives to be usable. Write
secrets with a label (password: …) and they will be masked.
Masking is best-effort, not a guarantee. It always covers message bodies and session titles (titles matter: Cursor CLI and Antigravity derive them from the first user message, so a prompt like "deploy with TOKEN=…" would otherwise leak through the title). It still has limits:
bare random strings, as above
cwd/git_branch/project_keyare not masked — filtering and cross-machine project grouping depend on them. Keep secrets out of pathsthe local database stores bodies verbatim and masks on display
Treat the database file itself as a secret. The local database is 0600; the server
keeps it inside a docker volume. Back it up on the same assumption. "Masking exists, so
the database is safe" does not hold.
Notes and limitations
Queries shorter than 3 characters fall back to LIKE. The
trigramtokenizer cannot MATCH fewer than 3 characters; the CLI and UI switch automatically and say so.tool_call/tool_resultare stored but not indexed. Large diffs and file dumps drown out the signal. They are over 70% of all rows.Resumed sessions keep their original
uuid. Claude Code copies prior history into a new file on resume, soUNIQUE (source, ext_id, part)keeps only one copy. Search never shows duplicates;show <resumed-id>may be missing the earlier part.Cursor CLI has no timestamps or model names.
tsis NULL and session spans fall back to file mtime.Codex
reasoningis usually encrypted. Only plaintextsummaryblocks are kept.Antigravity CLI is decoded without a
.proto. Field numbers were identified from real data, so a format change could silently drop messages — watchchist statsfor unexpected drops.
Documentation
File | Contents |
Server deployment and multi-machine aggregation | |
Registering the MCP server with each tool | |
Schema of record, with design notes |
License
MIT — see LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceAn MCP server that enables users to retrieve, filter, and search through Claude Code conversation history stored in local projects. It provides tools for listing projects and sessions, paginating through message history, and searching across conversations with keyword filtering.Last updated3611MIT
- AlicenseAqualityBmaintenanceMCP server for browsing, searching, exporting, and backing up your Cursor AI chat history directly into Claude via natural language.Last updated810732MIT
- Alicense-qualityDmaintenanceA zero-dependency MCP server that enables searching and reading local Claude Code and Codex chat sessions, supporting full-text search, grep, and knowledge indexing from chat history.Last updated5MIT
- AlicenseAqualityDmaintenanceAn MCP server that indexes Claude Code conversation history into SQLite, enabling full-text search across past sessions for context recovery and cross-agent observability.Last updated102MIT
Related MCP Connectors
Search your AI chat history (ChatGPT, Claude, Codex) from any MCP client. Remote, private, read-only
Local-first RAG engine with MCP server for AI agent integration.
Real-time chat hub for AI agents — Claude Code, Cursor, Cline, Codex over MCP or REST.
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/hiropon164/chist-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server