An MCP server that gives a single, searchable view of your past coding-agent transcripts across every locally-installed ACP-compatible agent (Claude Code, Codex, Goose, …).
How it works. On startup, the server fetches the
ACP registry,
detects which registered agents are launchable on this machine (binary on
PATH, or npx/uvx available), and starts a background poller. Every
5 minutes it pulls each agent's session history into a local SQLite + FTS5
database. MCP tools query that index.
Two backends ship today:
- Filesystem (default wherever a parser exists). Reads the agent's on-disk
session store directly. Bundled parsers cover Claude Code, Codex CLI, Goose,
Cursor, Cline, Roo Code, Kilo Code, Zed, Gemini CLI, Qwen Code, Continue, and
Aider. Captures 100% of local history, fast, no subprocess churn.
Incremental scans are mtime- or
updated_at-gated depending on the store shape. Filesystem-only agents (Cursor, Cline-in-VS-Code, Zed, Continue) are auto-detected even when their CLI isn't installed — we just read their state files. - ACP (fallback for agents without a filesystem parser). Lazy-spawns each
agent as an ACP subprocess, calls
session/list+session/load, drains the replayedsession/updatenotifications. For agents whose ACP adapter filterssession/listby spawning cwd, cwd discovery iterates known project roots.
You can override the backend per agent in config.toml — see
Configuration below. The filesystem backend is the reason
indexed coverage is ~16× higher than ACP-only would deliver: most agent ACP
adapters expose only a small recent slice of session/list, while the
filesystem store is complete.
| Agent | Storage | Format |
|---|---|---|
| Claude Code | ~/.claude/projects/*/<uuid>.jsonl |
per-session JSONL |
| Codex CLI | ~/.codex/sessions/<y>/<m>/<d>/rollout-*.jsonl |
per-session JSONL |
| Goose | ~/.local/share/goose/sessions/sessions.db |
SQLite |
| Cursor | ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb |
SQLite (composer headers + per-bubble blobs; orphan composers also recovered) |
| Cline / Roo / Kilo | …/Code/User/globalStorage/<publisher>/tasks/<id>/api_conversation_history.json |
JSON (Anthropic-format) |
| Zed | ~/Library/Application Support/Zed/threads/threads.db |
SQLite (payloads may be Zstd) |
| Gemini CLI / Qwen Code | ~/.{gemini,qwen}/tmp/<projectHash>/chats/*.{json,jsonl} |
JSON / JSONL |
| Continue | ~/.continue/sessions/<id>.json |
JSON |
| Aider | <repo>/.aider.chat.history.md (per repo; needs project_roots in config) |
Markdown |
git clone <this-repo>
cd acp-memory-server
uv pip install -e . # or: pip install -e .acp-memory doctorThat prints the database path, the registry fetch result, the agents detected
locally, and per-agent indexed status. Filesystem-backed agents (the ones in
the table above) show ok as soon as their on-disk store is found — no
subprocess launch required. ACP-only agents may also show unsupported if
their adapter lacks loadSession, or needs_auth if session/list returns
401. For needs_auth, run that agent's normal login flow (e.g. claude login)
and call the refresh MCP tool or wait for the next poll.
Add to ~/.claude.json:
{
"mcpServers": {
"acp-memory": {
"command": "acp-memory",
"args": ["serve"]
}
}
}Restart Claude Code. Then ask it: "search my past sessions for 'database
migration'" — it will call search_memory and return hits across every
agent it indexed.
| Tool | Purpose |
|---|---|
search_memory(query, agent?, since?, limit?) |
FTS5 search across all indexed turns. since accepts 7d, 24h, 30m, or ISO-8601. |
list_agents() |
Detected agents and per-agent status. |
list_sessions(agent?, limit?) |
Recent sessions, sorted by latest turn time. |
get_session(agent, session_id, offset?, limit?, only_human?, roles?) |
Paginated transcript. only_human=true keeps just user turns; roles=["user","agent"] for human + assistant only. Returns total and has_more for paging. |
refresh(agent?) |
Force a poll cycle now. |
refresh_agents() |
Re-run discovery (registry + PATH). |
~/.config/acp-memory/config.toml (all keys optional):
poll_interval_seconds = 300
auto_discover = true
registry_url = "https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json"
# Define a custom agent the registry doesn't know about
[agents.my-custom-agent]
enabled = true
launch_cmd = "/usr/local/bin/my-acp-agent"
launch_args = ["--mode", "acp"]
launch_env = { FOO = "bar" }
# Force ACP polling instead of the default filesystem reader
[agents.claude-acp]
backend = "acp"
# Disable a registry agent without uninstalling it
[agents.codex-acp]
enabled = false
# ACP-only agent that needs cwd hints (override auto-discovery)
[agents.gemini]
cwds = ["/Users/me/code/foo", "/Users/me/code/bar"]
# Aider has no central session store — chat history lives next to each repo.
# Configure the project roots you want indexed.
[agents.aider]
project_roots = ["/Users/me/code/foo", "/Users/me/code/bar"]Per-agent backend values:
"filesystem"— read the agent's local session store. Bundled parsers exist forclaude-acp,codex-acp,goose,cursor,cline,roo-code,kilo,zed,gemini,qwen-code,continue, andaider."acp"— lazy-spawn the agent as an ACP subprocess and usesession/list+session/load.- omitted — auto: filesystem if a parser exists, else ACP.
- Database:
~/.local/share/acp-memory/db.sqlite(or$XDG_DATA_HOME/acp-memory) - Registry cache:
~/.cache/acp-memory/registry.json - Config:
~/.config/acp-memory/config.toml
The database is plain SQLite with FTS5; you can sqlite3 into it directly to
debug or run ad-hoc queries.
- ACP
session/loadis optional in the protocol spec. Agents that don't advertise theloadSessioncapability are flaggedunsupportedand skipped. Codex and Goose are partial today; their indexed coverage will grow as upstream support matures. - Some agents only expose process-local sessions over ACP (i.e. not the user's
CLI history). For those,
session/listmay return little or nothing —acp-memory doctorwill surface the empty result. - The poller is headless: it cannot drive interactive auth flows. Agents that
require
claude login/ equivalent must be authenticated manually first.
When the server spawns an agent, it sets ACP_MEMORY_DISABLE_RECURSION=1 in
the agent's environment. If that variable is set when the server itself
starts, the server runs in a degraded "no-poll" mode (still serves search
queries from the existing index) so a chain of nested ACP launches never
fans out.