Set Up the MCP Server¶
The ZettelForge MCP server exposes the full memory system as tools through the Model Context Protocol (MCP). Any MCP-compatible AI agent — Claude Code, OpenClaw, Cline, or a custom client — can call zettelforge_remember, zettelforge_recall, and five other tools over stdio transport.
Prerequisites¶
- ZettelForge installed (
pip install zettelforge) - Python 3.12+
- For Claude Code: the
claudeCLI installed and authenticated - Embedding and LLM models available (downloaded automatically on first tool call)
Steps¶
1. Verify the server starts¶
Run the server directly to confirm it accepts stdin and writes JSON-RPC responses to stdout:
Expected output (one line):
{"jsonrpc": "2.0", "id": 0, "result": {"protocolVersion": "2024-11-05", "capabilities": {"tools": {"listChanged": false}}, "serverInfo": {"name": "zettelforge", "version": "2.0.0"}}}
If you see this response, the server is functional.
2. List available tools¶
Send a tools/list request to verify all seven tools are registered:
Seven tools are returned:
| Tool | Purpose |
|---|---|
zettelforge_remember |
Store threat intelligence with entity extraction and memory evolution |
zettelforge_recall |
Search memory with blended vector + graph retrieval |
zettelforge_synthesize |
Generate RAG-synthesized answers (direct_answer, brief, timeline, relationship map) |
zettelforge_entity |
Fast entity lookup by type (actor, cve, tool, campaign, person, location) |
zettelforge_graph |
Traverse the STIX 2.1 knowledge graph from an entity |
zettelforge_stats |
Get memory system statistics (note count, entity index, retrievals) |
zettelforge_sync |
Trigger OpenCTI sync (requires enterprise package) |
3. Wire into Claude Code¶
Create or edit .claude.json in your project root (or ~/.claude/.claude.json for global access):
If ZettelForge is installed in a virtual environment, use the full path to that Python interpreter:
{
"mcpServers": {
"zettelforge": {
"command": "/home/user/.venvs/zettelforge/bin/python",
"args": ["-m", "zettelforge.mcp"]
}
}
}
4. Verify the integration¶
Start Claude Code and check that the tools are available:
Inside the Claude Code session, ask:
Claude Code should list the seven tools. Test a simple recall:
If the memory store is empty, store a fact first:
Use zettelforge_remember to store this intelligence:
"APT28 (Fancy Bear) deployed Cobalt Strike against NATO networks in Q1 2026."
5. Configure backend storage (optional)¶
The MCP server defaults to SQLite. Set the environment variable before starting Claude Code or the server to change this:
Supported backends: sqlite (default), jsonl, typedb, lancedb.
6. Customize the memory directory¶
If your memory store is at a non-default location, set ZETTELFORGE_HOME:
Test each tool manually¶
You can send raw JSON-RPC requests to verify each tool's behaviour. Use a memory store with existing content for meaningful results.
zettelforge_remember¶
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"zettelforge_remember","arguments":{"content":"APT28 used CVE-2024-3094 against NATO targets.","domain":"cti","source":"manual-test","evolve":true}}}' | python -m zettelforge.mcp
zettelforge_recall¶
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"zettelforge_recall","arguments":{"query":"What tools does APT28 use?","k":5}}}' | python -m zettelforge.mcp
zettelforge_entity¶
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"zettelforge_entity","arguments":{"type":"actor","value":"apt28","k":3}}}' | python -m zettelforge.mcp
zettelforge_graph¶
echo '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"zettelforge_graph","arguments":{"type":"actor","value":"apt28","max_depth":2}}}' | python -m zettelforge.mcp
zettelforge_stats¶
echo '{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"zettelforge_stats","arguments":{}}}' | python -m zettelforge.mcp
Troubleshooting¶
Server starts but no tools appear in Claude Code.
Make sure the virtual environment Python is the one specified in .claude.json. Test by running the initialize handshake directly (step 1).
"ModuleNotFoundError: No module named 'zettelforge'".
ZettelForge is not installed in the Python environment used by the MCP server. Run pip install zettelforge or point the command to the correct venv Python.
Backward-compatible tool names.
If you have existing workflows using threatrecall_remember, threatrecall_recall, etc., those names still work — the server transparently rewrites threatrecall_* to zettelforge_*.
The zettelforge_sync tool returns an error.
OpenCTI sync requires the zettelforge-enterprise package. It is not available in the open-source (MIT) distribution.
LLM Quick Reference¶
Task: Wire ZettelForge into an MCP-compatible AI agent (Claude Code, Cline, OpenClaw).
Server entrypoint: python -m zettelforge.mcp runs the stdio server. It reads JSON-RPC 2.0 requests from stdin and writes responses to stdout.
Configuration file: .claude.json (project or home directory) with mcpServers.zettelforge.command and mcpServers.zettelforge.args.
Seven tools: remember, recall, synthesize, entity, graph, stats, sync. The sync tool requires the enterprise package.
Lazy singleton: MemoryManager is not instantiated on import — only on the first tool call (or the first JSON-RPC request). Importing zettelforge.mcp to inspect the TOOLS list has no side effects on the backend.
Backend default: SQLite. Override with ZETTELFORGE_BACKEND=jsonl or ZETTELFORGE_BACKEND=typedb.
Protocol: JSON-RPC 2.0 over stdio. Initialize handshake first, then tools/list and tools/call. Notifications (notifications/initialized) produce no response. Unknown methods return error code -32601.