How the MemPalace MCP Server Implements I-9 Tools for Reading, Writing, and Maintaining the Palace
The MemPalace MCP server centralizes all data access through a single JSON-RPC dispatcher that validates, logs, and executes a suite of schema-enforced I-9 tools defined in mempalace/mcp_server.py.
The MemPalace/mempalace repository provides a memory-palace storage system where the MCP server implements a comprehensive set of operations for reading, writing, and maintaining the palace. According to the source code in mempalace/mcp_server.py, these capabilities surface as I-9 tools—a named collection of high-level Python functions registered in a central dictionary and invoked through a unified request handler.
I-9 Tool Architecture and Registration
All I-9 tools are implemented as regular Python functions inside mempalace/mcp_server.py and gathered into the TOOLS dictionary at lines 1060–1085. Each entry maps a tool name to its executable function, while the companion TOOL_SPECS object stores jsonschema definitions that enforce type constraints at request time.
This design guarantees that callers receive clear validation errors rather than internal tracebacks when parameters are malformed.
Request Routing and Tool Dispatch
When a client submits a JSON-RPC payload, handle_request() at line 2760 extracts the method and params fields. It validates the arguments against TOOL_SPECS, looks up the corresponding function in TOOLS, executes it, and returns a formatted response. Any unhandled exception is caught by _internal_tool_error() near line 2740 to ensure the server always emits stable JSON.
Behind the scenes, _parse_args() at line 159 builds the CLI interface and registers --tool sub-commands, while _init_logging() at line 93 configures a rotating file logger. The imported stdio_protect utility prevents accidental writes to the MCP process’s stdout and stderr streams.
Backend Setup and Helper Resolution
Before tools touch storage, lazy helpers resolve the correct backends. _get_client(), _get_collection(), and _get_kg() instantiate the chosen storage layer—typically ChromaDB for vector embeddings—and the SQLite knowledge graph. These helpers ensure that read and write tools do not instantiate expensive connections until they are actually invoked.
The Three Functional Groups
The I-9 tools are organized into read/query, write/mutate, and maintenance categories.
Read and Query Tools
These functions retrieve palace state without changing it. Representatives include:
tool_get_drawer(line 1576) – Loads a drawer by UUID and returns its stored text and metadata via_fetch_all_metadata().tool_list_drawers– Enumerates drawers filtered by wing or room.tool_search– Performs semantic or keyword search against the vector store.tool_kg_query(line 1738) – Executes temporal graph queries against the SQLite knowledge graph, supportingas_offiltering and directional traversal.tool_diary_read(line 1991) – Retrieves the most recentlast_ndiary entries for an agent by querying theDiaryEntryentity type.
Write and Mutate Tools
These functions change palace state and automatically record their actions for recovery:
tool_add_drawer(line 1368) – Generates a UUID, inserts a row into thedrawerstable throughpalace.py, and writes the content embedding via_collection_upsert().tool_update_drawer(line 1666) – Performs an in-place update; ifcontentis supplied it overwrites the vector embedding, otherwise it mutates only taxonomy fields such aswingorroom. Every call is logged via_wal_log()before committing.tool_delete_drawer(line 1505) – Removes a drawer from both the SQLite index and the vector store. The operation is idempotent, returning a “not found” status if the UUID is already absent.tool_diary_write(line 1867) – Persists a free-form diary entry as a drawer tagged with a topic, recordingagent_nameas theadded_bymetadata for auditing.tool_kg_add(line 1753) – Inserts a new triple into the knowledge graph, automatically handling temporal fields (started,ended), validating against duplicates, and writing to the WAL.tool_kg_invalidate– Marks a knowledge-graph edge as no longer valid.
Maintenance Tools
These functions keep the palace consistent and repair indexes:
tool_sync(line 1538) – Scans a project directory viaminer.py, detects new or modified files, updates existing drawers, and optionally prunes orphaned drawers when source files are deleted or added to.gitignore. It returns a detailed dry-run report unlessapply=True.tool_reconnect– Re-establishes dropped backend connections.tool_memories_filed_away– Verifies that archived memories remain reachable.tool_hook_settings– Adjusts runtime configuration hooks.tool_graph_stats– Returns structural statistics about the knowledge graph.
Core Implementations in Depth
Adding and Retrieving Drawers
The tool_add_drawer(content, wing, room, tags=[]) function is the primary entry point for creating new drawers—the lowest-level storage units in MemPalace. It delegates the SQLite row insertion to palace.py and persists the vector embedding to the Chroma collection. Conversely, tool_get_drawer(drawer_id) reconstructs the drawer payload by querying metadata and content from both the relational and vector stores.
Updating and Deleting Drawers
tool_update_drawer(drawer_id, content=None, wing=None, room=None) offers partial or full updates. Supplying content triggers a full re-embedding, while omitting it limits the mutation to taxonomy fields. Before the database commits, _wal_log() at line 479 appends an operation record to a write-ahead log file. This record underpins the recovery subsystem implemented in mempalace/repair.py.
Knowledge Graph and Diary Operations
tool_kg_query(entity, as_of=None, direction="both") resolves an entity identifier, filters by validity dates, and follows edges in the requested direction. tool_kg_add(subject, predicate, object, started=None, ended=None) performs the complementary write, ensuring duplicate triples are rejected and temporal boundaries are honored.
For agent audit trails, tool_diary_write(agent_name, entry, topic="general", wing="") stores entries as specialized drawers, while tool_diary_read(agent_name, last_n=10, wing="") queries them through the knowledge graph’s DiaryEntry entity interface.
Invoking I-9 Tools: JSON-RPC and CLI Examples
Clients interact with the I-9 tools through JSON-RPC over HTTP or via the first-party CLI.
Adding a Drawer over JSON-RPC
import json, urllib.request
payload = {
"jsonrpc": "2.0",
"method": "add_drawer",
"params": {
"content": "Remember to backup the database every Sunday.",
"wing": "operations",
"room": "2024-09-01",
"tags": ["reminder", "backup"]
},
"id": 1
}
req = urllib.request.Request(
"http://127.0.0.1:8000/",
data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"}
)
print(json.loads(urllib.request.urlopen(req).read()))
The response contains the new drawer’s UUID and a status: "ok" field.
Reading a Drawer from the CLI
mempalace --tool get_drawer --drawer-id 7e3a5c9b-2f1d-4c6a-9143-1b5f2a5d9c8e
This prints the stored text together with its metadata, including wing, room, and tags.
Syncing a Project Directory
mempalace --tool sync --project-dir ~/my_project --wing development --apply
tool_sync scans ~/my_project, creates or updates drawers for every source file, and removes drawers whose source files have been deleted or added to .gitignore. Without --apply, it emits a dry-run report.
Adding a Knowledge-Graph Triple
mempalace --tool kg_add \
--subject "Alice" \
--predicate "works_at" \
--object "AcmeCorp" \
--started "2022-01-01"
The new edge is persisted in the SQLite graph and becomes available to subsequent kg_query calls.
Summary
- The MemPalace MCP server exposes all operations through the I-9 tool suite, a registered collection of Python functions in
mempalace/mcp_server.py. handle_request()at line 2760 serves as the single JSON-RPC dispatcher, validating inputs againstTOOL_SPECSbefore executing the matching function from theTOOLSdictionary.- Tools are grouped into read/query, write/mutate, and maintenance categories, covering everything from drawer CRUD to knowledge-graph traversal and filesystem synchronization.
- Every mutating operation is recorded via
_wal_log()at line 479, enabling crash recovery throughmempalace/repair.pyand guaranteeing auditable state changes. - Clients invoke tools uniformly via JSON-RPC or the CLI, with strict schema validation preventing invalid data from entering the palace.
Frequently Asked Questions
What does I-9 mean in the MemPalace codebase?
The developers named the tool suite after the U.S. Employment-Eligibility Form I-9. The name emphasizes that these functions are the official, auditable entry points for any data entering the palace, and strict schema validation must pass before any write is accepted.
How does the MCP server validate incoming tool requests?
The server validates every JSON-RPC request against TOOL_SPECS, a set of jsonschema definitions stored directly in mempalace/mcp_server.py. This check occurs inside handle_request() before the matching tool function is invoked, ensuring type-safe parameters and clear error messages.
What happens if a write operation crashes before it finishes?
Every mutating tool calls _wal_log() at line 479 to append an operation record to a write-ahead log. If the server crashes mid-operation, mempalace/repair.py can replay or reconcile these records, preventing partial writes and keeping the SQLite index consistent with the vector store.
How can I synchronize an external project with MemPalace?
Use the CLI command mempalace --tool sync --project-dir <path> --wing <name> --apply. Under the hood, tool_sync at line 1538 invokes miner.py to scan the directory, then creates, updates, or prunes drawers to match the current filesystem state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →