Conversation Search
FreeNot checkedFull-text search over Claude Code conversation history using SQLite FTS5, exposing indexed transcripts as MCP tools for searching, browsing, and reading turns.
About
Full-text search over Claude Code conversation history using SQLite FTS5, exposing indexed transcripts as MCP tools for searching, browsing, and reading turns.
README
FTS5 full-text search over Claude Code conversation history. Indexes JSONL transcripts from ~/.claude/projects/ into a persistent SQLite FTS5 database and exposes them as searchable memory. Available as both an MCP server and a CLI tool.
Based on Searchable Agent Memory in a Single File by Eric Tramel.
Development process
The initial implementation was produced by Claude Code following a structured pipeline:
- PRD (
ai-docs/features/001-conversation-search-mcp.md) — requirements and design decisions - Build spec (
specs/conversation-search-mcp.md) — generated from the PRD, containing exact function signatures, filtering rules, acceptance criteria, and validation commands - Implementation (
conversation_search.py) — written by Claude Code using the build spec as instructions
The search backend was later migrated from in-memory bm25s to SQLite FTS5 (specs/fts5-migration.md), peer-reviewed by Claude (Opus 4.6) and Codex (GPT-5.4), and executed as 5 sequential subagent tasks.
How it works
Claude Code stores conversation transcripts as JSONL files under ~/.claude/projects/<encoded-dir>/. This server:
- Discovers matching project directories via glob pattern
- Parses JSONL into turns (user message + assistant response + tool calls)
- Builds an SQLite FTS5 index stored at
~/.cache/conversation-search/index.db - On warm start, only reparses files whose mtime/size has changed (sub-second startup)
- Watches the filesystem for changes and reindexes (60s debounce)
- Serves 4 MCP tools via stdio (
serve) or SSE (daemon)
Requirements
- uv (Python >= 3.10 is resolved automatically)
No venv or manual install needed. uv run handles mcp, uvicorn, and watchdog automatically. No bm25s or other search library is required — SQLite FTS5 is part of the Python standard library.
Installation
Add to your MCP configuration — either project-level (.mcp.json) or global (~/.claude.json under the mcpServers key):
{
"mcpServers": {
"conversation-search": {
"command": "uvx",
"args": [
"--from", "git+https://github.com/gebeer/conversation-search.git",
"conversation-search", "connect"
]
}
}
}
connect starts a shared daemon on first use and reuses it across sessions (see Daemon Mode). For standalone stdio mode (one index per session), replace connect with serve.
The --pattern flag controls which project directories under ~/.claude/projects/ are indexed. It defaults to * (all projects) if omitted. Patterns containing / are treated as filesystem paths and auto-converted to the encoded directory name format.
| Pattern | Scope |
|---|---|
* |
All projects |
~/repos/openclaw |
Single project |
~/repos/* |
All repos projects |
~/repos/open* |
Projects starting with "open" |
--pattern="-home-claude-repos-*" |
Encoded format (requires = syntax for leading -) |
Restart Claude Code after changing MCP configuration.
CLI Usage
The tool can also be used directly from the command line for scripting and debugging:
uvx --from git+https://github.com/gebeer/conversation-search.git \
conversation-search search --query "heartbeat" --limit 5
conversation-search list --project "claude" --limit 10
conversation-search read-turn --session-id "<uuid>" --turn 5
conversation-search read-conv --session-id "<uuid>" --offset 0 --limit 10
After the first uvx invocation, the conversation-search command is cached and can be called directly. Alternatively, use uv run conversation_search.py <command> from a local clone.
All CLI commands output pretty-printed JSON to stdout. Index progress is printed to stderr. Use 2>/dev/null to suppress progress output when piping.
Daemon Mode (Recommended for Multiple Sessions)
When running multiple Claude Code sessions simultaneously, use daemon mode to share a single SQLite FTS5 index instead of opening separate DB connections per session.
Setup
The default installation config already uses connect, which enables daemon mode automatically. On first session start, connect launches the daemon in the background. Subsequent sessions reuse it. The daemon exits after 15 minutes of inactivity.
Manual daemon control
# Start daemon in foreground (useful for debugging)
conversation-search daemon
# Custom port and idle timeout
conversation-search daemon --port 9300 --idle-timeout 1800
# Stop daemon
kill $(cat ~/.cache/conversation-search/daemon.pid)
Configuration
| Flag | Default | Description |
|---|---|---|
--port |
9237 | Localhost port for the SSE server |
--idle-timeout |
900 | Seconds of inactivity before daemon exits |
Both flags work on daemon and connect subcommands.
How it works
Claude Code session A ──┐
Claude Code session B ──┼── connect (stdio↔SSE bridge) ──► daemon (SSE on localhost:9237)
Claude Code session C ──┘ │
• one FTS5 index (~10 MB)
• one filesystem watcher
• one reindex loop
Without daemon: N sessions each open the same SQLite DB (WAL mode handles concurrent reads). With daemon: Single writer/watcher; all sessions share one connection via SSE.
Tools
search_conversations
FTS5 full-text search across all indexed turns. All terms are implicitly ANDed.
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
str |
required | FTS5 search query. All terms must match (implicit AND). |
limit |
int |
10 |
Max results |
session_id |
str | None |
None |
Filter to one session |
project |
str | None |
None |
Substring filter on project name |
Returns ranked results with session_id, turn_number, score, snippet (context window with [[match]] markers), timestamp.
Query syntax
| Syntax | Example | Meaning |
|---|---|---|
| Keywords | heartbeat timer |
Both must match (implicit AND) |
| Phrase | "systemd timer" |
Exact phrase |
| Boolean | heartbeat AND NOT clawd |
Boolean operators |
| Prefix | buffer* |
Prefix matching |
| OR | heartbeat OR cron |
Either term |
| Grouping | (timer OR cron) AND heartbeat |
Grouped boolean |
| Literal | literal:foo.bar() |
Code-like query, skips FTS5 syntax parsing |
list_conversations
Browse indexed sessions with metadata.
| Parameter | Type | Default | Description |
|---|---|---|---|
project |
str | None |
None |
Substring filter on project name |
limit |
int |
50 |
Max results |
Returns sessions sorted by last_timestamp desc, with summary, turn_count, cwd, git_branch.
read_turn
Full-fidelity retrieval of a single turn. Re-parses the source JSONL (not the index).
| Parameter | Type | Description |
|---|---|---|
session_id |
str |
Session UUID |
turn_number |
int |
Zero-based turn index |
Returns complete user_text, assistant_text, and tools_used with rendered tool details.
read_conversation
Paginated reading of consecutive turns from a session.
| Parameter | Type | Default | Description |
|---|---|---|---|
session_id |
str |
required | Session UUID |
offset |
int |
0 |
Starting turn |
limit |
int |
10 |
Number of turns |
Usage pattern
The 4 tools are automatically exposed to the assistant via MCP — no extra instructions in CLAUDE.md, AGENTS.md, or similar files are needed. The server also provides instructions metadata through the MCP protocol to guide the assistant on effective usage.
Search wide, then read deep:
search_conversations("ProcessWire login redirect") -> find relevant turns
read_turn(session_id, turn_number) -> get full context
read_conversation(session_id, offset, limit) -> read surrounding turns
FTS5 requires all query terms to match (implicit AND). Use specific keywords for best results. For either-or matching, use explicit OR. For code-like queries with special characters, use the literal: prefix.
Install Conversation Search in Claude Desktop, Claude Code & Cursor
unyly install conversation-searchInstalls into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.
First time? Get the CLI: curl -fsSL https://unyly.org/install | sh
Or configure manually
Run in your terminal:
claude mcp add conversation-search -- uvx --from git+https://github.com/gebeer/conversation-search conversation-searchFAQ
Is Conversation Search MCP free?
Yes, Conversation Search MCP is free — one-click install via Unyly at no cost.
Does Conversation Search need an API key?
No, Conversation Search runs without API keys or environment variables.
Is Conversation Search hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Conversation Search in Claude Desktop, Claude Code or Cursor?
Open Conversation Search on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
wenb1n-dev/SmartDB_MCP
A universal database MCP server supporting simultaneous connections to multiple databases. It provides tools for database operations, health analysis, SQL optim
by wenb1n-devPostgres Server
This server enables interaction with PostgreSQL databases through the Model Context Protocol, optimized for the AWS Bedrock AgentCore Runtime. It provides tools
by madhurprashPostgres
Query your database in natural language
by AnthropicPostgreSQL
Read-only database access with schema inspection.
by modelcontextprotocolCompare Conversation Search with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All data MCPs
