Adding Custom MCP Tools to the MemPalace Server: A Complete Developer Guide

You add custom MCP tools to the MemPalace server by defining a Python handler function, creating a JSON Schema for input validation, and registering both in the TOOLS dictionary inside mempalace/mcp_server.py with the required mempalace_ prefix.

The MemPalace MCP server provides a JSON-RPC interface that exposes callable operations known as tools—functions that read, write, or maintain the palace state. According to the MemPalace source code, extending the server requires understanding the central registry where all tools are defined and how the dispatch loop validates and executes incoming requests.

Understanding the TOOLS Registry Architecture

All MCP tools are defined in the TOOLS dictionary located in mempalace/mcp_server.py (lines 2269-2275). This registry maps method names to their implementations using a strict structure that the dispatch loop depends on.

Each tool entry must contain three fields:

  • description — Human-readable text displayed in protocol documentation and client UIs.
  • input_schema — A JSON-Schema object describing expected arguments, types, and required fields.
  • handler — The Python callable that implements the tool’s logic.

When the MCP server receives a JSON-RPC request, the dispatch loop (around lines 2800-2810) looks up the method name in TOOLS, validates supplied parameters against input_schema, and executes the handler function. The server only exposes methods that begin with the mempalace_ prefix; any entry lacking this prefix will not be accessible to clients.

The Three-Step Implementation Process

Adding a custom tool requires completing three distinct steps before restarting the server.

Step 1: Write the Handler Function

The handler function must accept keyword arguments that match the keys defined in your JSON Schema. It should return a JSON-serializable Python object—typically a dictionary—and must never perform side effects outside the palace context (such as unauthorized network calls).

Place your handler function anywhere in mempalace/mcp_server.py, typically alongside other tool implementations. Ensure it performs input validation and returns explicit error messages for invalid inputs.

Step 2: Define the JSON Input Schema

Create a JSON Schema that describes your tool’s expected parameters. This schema is used both for client-side validation and for generating help text. Keep schemas simple, reuse existing types where possible, and explicitly mark required fields.

Step 3: Register in the TOOLS Dictionary

Insert your tool into the TOOLS dictionary using TOOLS.update() to avoid disturbing existing entries. The registration must occur before the server’s dispatch loop initializes—place it immediately after existing tool definitions around line 2270.

TOOLS.update(
    {
        "mempalace_custom_tool": {
            "description": "Human-readable description of what this tool does.",
            "input_schema": YOUR_SCHEMA,
            "handler": your_handler_function,
        }
    }
)

Complete Implementation Example

Below is a minimal, complete example that adds a tool named mempalace_echo. This tool accepts a message string and returns it converted to uppercase, demonstrating the handler, schema, and registration pattern.


# --- Handler Function --------------------------------------------------------

def tool_echo(message: str) -> dict:
    """
    Return the supplied `message` converted to uppercase.
    """
    if not isinstance(message, str):
        return {"error": "`message` must be a string"}
    return {"result": message.upper()}


# --- JSON Schema -------------------------------------------------------------

ECHO_SCHEMA = {
    "type": "object",
    "properties": {
        "message": {
            "type": "string",
            "description": "Text to be echoed back in uppercase",
        }
    },
    "required": ["message"],
    "additionalProperties": False,
}


# --- Registration (place inside TOOLS dict around line 2270) ------------------

TOOLS.update(
    {
        "mempalace_echo": {
            "description": "Echo a message back in uppercase – useful for testing the MCP pipeline.",
            "input_schema": ECHO_SCHEMA,
            "handler": tool_echo,
        }
    }
)

Testing and Validation

After editing mempalace/mcp_server.py, restart the server by running python -m mempalace.mcp_server … to load the new registration.

Test the tool using a standard JSON-RPC client. The request format follows the MCP protocol specification:

{
  "jsonrpc": "2.0",
  "method": "mempalace_echo",
  "params": {"message": "hello world"},
  "id": 1
}

The server responds with:

{
  "jsonrpc": "2.0",
  "result": {"result": "HELLO WORLD"},
  "id": 1
}

Safety, Logging, and Performance Considerations

Stdio Protection and Structured Logging

The MemPalace MCP server deliberately redirects stdout to stderr (see lines 26-33 in mempalace/mcp_server.py) to prevent stray print statements from breaking the JSON-RPC stream. Never use standard print() in your handler functions.

Instead, use the dedicated logger instance:

logger = logging.getLogger("mempalace_mcp")
logger.info("Processing echo request")
logger.error("Invalid input received")

This logger writes to stderr by default, maintaining protocol integrity.

Leveraging Cached Resources

Built-in tools rely on cached ChromaDB clients stored in _client_cache and _collection_cache. If your custom tool interacts with the vector store, reuse the helper functions _get_collection() or _get_client() to maintain cache coherency and avoid connection overhead.

For knowledge graph operations, import and call existing tools like tool_kg_add or tool_kg_query directly from your handler to ensure consistent data validation and storage.

Advanced Pattern: Wrapping Built-in Tools

You can create custom tools that modify behavior of existing functionality before delegating to the original handler. The following example creates mempalace_my_search, which wraps the built-in search tool but enforces a hard limit of 10 results:

def tool_my_search(query: str, limit: int = 5) -> dict:
    """Thin wrapper around the built-in search that caps results at 10."""
    limit = min(limit, 10)  # enforce ceiling

    return tool_search(query=query, limit=limit)

TOOLS.update(
    {
        "mempalace_my_search": {
            "description": "Custom search that caps results at 10.",
            "input_schema": {
                "type": "object",
                "properties": {
                    "query": {"type": "string"},
                    "limit": {"type": "integer", "minimum": 1}
                },
                "required": ["query"]
            },
            "handler": tool_my_search,
        }
    }
)

Key Files for Custom Tool Development

Understanding these source files ensures you follow established patterns when adding custom MCP tools to the MemPalace server:

  • mempalace/mcp_server.py — Core MCP server implementation containing the TOOLS dictionary, stdio protection, request dispatch loop, and helper functions for collection and knowledge-graph access (lines 2269-2275 and 2800-2810).
  • mempalace/searcher.py — Implements search_memories; reference this when building custom search-related tools.
  • mempalace/knowledge_graph.py — Provides the KnowledgeGraph API used by tools like tool_kg_add and tool_kg_query.
  • mempalace/backends/chroma.py — Low-level ChromaDB wrapper for direct vector-store operations.
  • mempalace/config.py — Central configuration class MempalaceConfig() for accessing palace paths and collection names consistently.

Summary

  • Register custom tools in the TOOLS dictionary inside mempalace/mcp_server.py before the dispatch loop starts.
  • Prefix all custom method names with mempalace_ to expose them via the JSON-RPC interface.
  • Provide three components: a handler function, a JSON Schema, and a human-readable description.
  • Restart the server after editing mcp_server.py to load new tool registrations.
  • Reuse built-in helpers like _get_collection() and existing tool handlers to maintain cache consistency and data integrity.
  • Avoid using print(); instead use the mempalace_mcp logger to prevent breaking the JSON-RPC stream.

Frequently Asked Questions

What file do I edit to add custom MCP tools to MemPalace?

You edit mempalace/mcp_server.py. This file contains the TOOLS dictionary (lines 2269-2275) where all tool metadata, schemas, and handlers are registered, and the dispatch loop (lines 2800-2810) that routes JSON-RPC requests to your custom implementations.

Why must custom tool names use the mempalace_ prefix?

The dispatch loop in mempalace/mcp_server.py explicitly filters the TOOLS dictionary to only expose methods beginning with mempalace_. This namespace protection prevents accidental exposure of internal helper functions and ensures compatibility with the MCP protocol expectations.

How do I access the ChromaDB vector store in my custom tool?

Import and call the helper functions _get_collection() or _get_client() from within your handler. These functions manage the internal _client_cache and _collection_cache, ensuring you reuse existing connections and respect cache invalidation rules established by the core server.

Can I modify existing built-in tools when adding custom functionality?

You should not modify existing tool definitions directly. Instead, write a wrapper handler that calls the original tool function (such as tool_search or tool_kg_add) and performs your custom logic (validation, transformation, or filtering) before or after the delegated call. This preserves the integrity of the core MemPalace API.

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 →