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, supporting as_of filtering and directional traversal.
  • tool_diary_read (line 1991) – Retrieves the most recent last_n diary entries for an agent by querying the DiaryEntry entity 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 the drawers table through palace.py, and writes the content embedding via _collection_upsert().
  • tool_update_drawer (line 1666) – Performs an in-place update; if content is supplied it overwrites the vector embedding, otherwise it mutates only taxonomy fields such as wing or room. 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, recording agent_name as the added_by metadata 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 via miner.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 unless apply=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 against TOOL_SPECS before executing the matching function from the TOOLS dictionary.
  • 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 through mempalace/repair.py and 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →