MCP tool_search returns "Error finding id" when wing-scoped to a convos-mined wing (CLI works, unscoped MCP works)
Summary
MCP mempalace_search(query=..., wing=<convos-mined-wing>) fails with "Search error: Error executing plan: Internal error: Error finding id" for any wing that was created via mempalace mine ... --mode convos. The same query via CLI succeeds (mempalace search "..." --wing <wing>), and unscoped MCP search also succeeds and returns hits from the same wing mixed with others. Wing-scoped MCP search on projects-mined (code) wings is fine. The failure is specifically the combination of "MCP transport + wing filter + convos-mined wing".
Environment
- mempalace: 3.3.2 (from PyPI —
pip show mempalace→Version: 3.3.2, sdist+wheel from https://github.com/MemPalace/mempalace/releases/tag/v3.3.2) - Install command:
uv pip install --python $(pyenv which python3) mempalace(plugin hooks + MCP server need the systempython3on PATH to importmempalace;uv tool installisolates it and hooks fail) - Python: 3.12.11 via pyenv
- OS: macOS, Darwin 25.3 (macOS 15 series, arm64)
- Claude Code plugin:
MemPalace/mempalacemarketplace branchdevelop— plugin.claude-plugin/plugin.jsonv3.3.2, MCP server launched aspython3 -m mempalace.mcp_server - Vector store: ChromaDB (default, local PersistentClient, no custom tenant/collection config)
- Embedding model:
all-MiniLM-L6-v2(default) - Identity file:
~/.mempalace/identity.txtpresent - Palace location: default (
~/.mempalace/palace/)
What happens
Given a palace that contains:
- At least one
projects-mined wing (e.g.sample_repo, created viamempalace mine /path/to/repo) - At least one
convos-mined wing (e.g.chats_general, created viamempalace mine /path/to/chat-folder --mode convos --extract general --wing chats_generalwhere the folder contains Claude Code session JSONL files)
Then from an MCP client connected to python3 -m mempalace.mcp_server:
| Call | Result |
|---|---|
mempalace_search(query="decisions") — unscoped |
OK — returns hits from the convos wing mixed with others |
mempalace_search(query="decisions", wing="sample_repo") — scoped to projects wing |
OK — returns projects-wing hits |
mempalace_search(query="decisions", wing="chats_general") — scoped to convos wing |
FAILS with {"error": "Search error: Error executing plan: Internal error: Error finding id"} |
mempalace_search(query="decisions", wing="chats_general", room="decision") — scoped to convos wing + room |
FAILS with the same error |
mempalace search "decisions" --wing chats_general — CLI, same wing |
OK — returns convos-wing hits with good similarity scores |
Observed verbatim error payload returned by mempalace_search MCP tool:
{
"error": "Search error: Error executing plan: Internal error: Error finding id"
}No traceback is surfaced to the MCP client. The MCP server log (stderr of the launched python3 -m mempalace.mcp_server) shows no Python exception during the failing call — the error appears to originate from the underlying ChromaDB query engine and be wrapped by tool_search / search_memories.
Scope of failure
Reproducible on every convos-mined wing we have:
chats_general— wing for a folder of Claude Code session JSONLs, mined with--mode convos --extract generalclub_prontosu_contracts— separate convos-mined wing, also--mode convos --extract general
Not reproducible on any projects-mined wing.
Affects:
wingfilter alonewing+roomcombined filter- Error persists across
mempalace_reconnectMCP calls and across full MCP server process restarts
Minimal reproduction
# 1. Install
uv pip install --python $(pyenv which python3) mempalace
python3 -c "import mempalace; print(mempalace.__version__)" # should print 3.3.2
# 2. Identity
mkdir -p ~/.mempalace && echo "test-user" > ~/.mempalace/identity.txt
# 3. Projects-mined wing (control)
mkdir -p /tmp/sample_repo && echo "# sample" > /tmp/sample_repo/README.md
echo "def foo(): return 'decision: use async'" > /tmp/sample_repo/app.py
mempalace init /tmp/sample_repo --yes
mempalace mine /tmp/sample_repo
# → creates wing "sample_repo"
# 4. Convos-mined wing (the failing case)
mkdir -p /tmp/chat-folder
# place at least one Claude Code session JSONL here:
cp ~/.claude/projects/*/*.jsonl /tmp/chat-folder/ # pick any one
mempalace mine /tmp/chat-folder --mode convos --extract general --wing chats_general
# → creates wing "chats_general"
# 5. Start MCP server in another terminal
python3 -m mempalace.mcp_server
# 6. From any MCP client (Claude Code, mcp-cli, etc.):
# Call A — works:
# mempalace_search(query="decisions", wing="sample_repo")
# Call B — works:
# mempalace_search(query="decisions") # unscoped
# Call C — FAILS:
# mempalace_search(query="decisions", wing="chats_general")
# → {"error": "Search error: Error executing plan: Internal error: Error finding id"}
# 7. CLI control — works fine against the same palace/collection:
mempalace search "decisions" --wing chats_general
# → prints hits with similarity scores, exit status 0Command exit statuses observed in our run:
$ mempalace search "decisions" --wing chats_general ; echo "exit=$?"
... (hits printed) ...
exit=0
$ mempalace search "decisions" --wing sample_repo ; echo "exit=$?"
... (hits printed) ...
exit=0MCP tool call (from Claude Code, via mcp__plugin_mempalace_mempalace__mempalace_search):
mempalace_search(query="decisions", wing="chats_general")
→ {"error": "Search error: Error executing plan: Internal error: Error finding id"}
mempalace_search(query="decisions")
→ {"results": [...], "count": 5} ← includes hits from chats_generalThings tried that do NOT fix it
- Restarting the MCP server (kill + relaunch)
- Calling
mempalace_reconnectMCP tool - Varying the query text (
"decisions","auth token","bug", single-word, multi-word) - Swapping
--wingfor--room(room-only filter exhibits the same failure when the wing is a convos wing) - Combining
wing+roomfilters - Re-mining the convos folder from scratch after deleting the wing
- Re-creating the palace and re-mining
Hypothesis (unconfirmed)
This is speculation for the maintainer — happy to test patches.
tool_search at mempalace/mcp_server.py:428–477 calls search_memories(sanitized_query, palace_path=..., wing=wing, room=room, n_results=limit, max_distance=dist) — the same entry point the CLI mempalace search uses. The sanitization (_sanitize_optional_name) happens identically in both paths. Since CLI works and MCP doesn't with identical filter values against the same collection, the divergence must be either:
Something ChromaDB-side about the way the MCP server's long-lived
PersistentClient/ cached collection (see #608 for the same cache pattern) resolves IDs vs. a fresh CLI-opened client, specifically when the resulting filtered candidate set crosses from the HNSW index back into metadata lookup — and only for drawer IDs minted by the convos path.Or a drawer-ID / metadata mismatch that the fresh-per-call CLI tolerates and the cached-client MCP server does not.
The drawer-ID formats differ between the two miners:
Projects miner (mempalace/miner.py) uses a static
roominterpolated into the ID.Convos miner (mempalace/convo_miner.py:309–347) computes
chunk_room = chunk.get("memory_type", room) if extract_mode == "general" else room(line 336) and then interpolates that per-chunk into the drawer ID:drawer_id = f"drawer_{wing}_{chunk_room}_{hashlib.sha256((source_file + str(chunk['chunk_index'])).encode()).hexdigest()[:24]}"So a single convos mine produces drawers whose ID segments include room values like
decision,emotional,code, etc. — not a single static room. Metadata storesroom=chunk_roomtoo. If MCP's internalError finding idpath (ChromaDB's plan executor failing to resolve an id during result assembly) is sensitive to the id vs. metadata shape in a way the fresh CLI client isn't, that would explain the reproducible asymmetry.
Whatever the root cause, the contract that "wing filter works identically via CLI and MCP" is broken for convos-mined wings.
Impact
Wing-scoped MCP retrieval is broken for all convos-mined wings. This blocks the most useful search pattern the tool enables: "give me the decisions we made about X in project Y," where Y is a per-project chat wing mined from Claude Code sessions. You can either:
- Search unscoped (mixing all projects → noisy results), or
- Shell out to CLI (no MCP integration benefits)
For users who structure their palace around one-convos-wing-per-project, this effectively disables per-project memory retrieval via MCP.
Current workaround
- Use unscoped
mempalace_searchand accept cross-wing noise, or - Shell out to
mempalace search ... --wing <wing>via a Bash tool call from the MCP client
Both are strictly worse than wing-scoped MCP search working correctly.
Relevant source (v3.3.2)
tool_search(MCP entrypoint): https://github.com/MemPalace/mempalace/blob/v3.3.2/mempalace/mcp_server.py#L428-L477search_memoriesimported from.searcher: https://github.com/MemPalace/mempalace/blob/v3.3.2/mempalace/mcp_server.py#L62- Convos miner drawer-ID construction: https://github.com/MemPalace/mempalace/blob/v3.3.2/mempalace/convo_miner.py#L309-L347
- Projects miner (for comparison): https://github.com/MemPalace/mempalace/blob/v3.3.2/mempalace/miner.py
Not related to
- #1049 (missing
mempalace-mcpentry point on PyPI 3.3.2) — our MCP server is running fine viapython3 -m mempalace.mcp_server; unscoped search works; only the wing-filtered convos-wing path fails. - #608 (stale-cache HNSW) — our results aren't stale, they're an outright error; also the CLI and unscoped MCP both succeed concurrently.
Happy to collect additional diagnostics (stderr logs from the MCP process, ChromaDB debug logs, sample palace) if helpful.
Source: MemPalace/mempalace