Persistent cross-session, cross-agent memory for Agent Zero containers. Whatever your Agent Zero instance is doing — research, file courier, code execution, autonomous loops — it remembers across restarts and shares memory with your other agents.
Agent Zero ships with native MCP client support via its mcp_servers setting. We use that path: the bridge runs inside the Agent Zero container, agent zero invokes it as an MCP tool when the LLM decides to.
- Agent Zero running in Docker (image
agent0ai/agent-zeroor compatible) - A running Mnemo Cortex server — see the main install guide
- The Agent Zero container can reach
MNEMO_URL— easy if Mnemo is on the same host (usehost.docker.internal:50001); over Tailscale if Mnemo is remote (Tailscale on the host extends to containers via host networking on Windows/Mac, on Linux you may need explicit DNS or--add-host) - A tool-capable LLM chosen for the agent. Qwen3 (any size), GPT-4/4o, Claude 3.5+, and Mistral 7B v0.3 are confirmed tool-callers. See Gotchas.
You have two options. Pick one:
A. Clone inside the container (simplest):
docker exec <container-name> bash -c "
cd /a0/usr &&
git clone https://github.com/GuyMannDude/mnemo-cortex.git &&
cd mnemo-cortex/integrations/mcp-bridge &&
npm install
"B. Mount the host clone into the container:
Recreate the container with -v /host/path/to/mnemo-cortex:/a0/usr/mnemo-cortex:ro. Saves disk if you run multiple Agent Zero instances on one host.
Either way, you end up with /a0/usr/mnemo-cortex/integrations/mcp-bridge/server.js reachable from inside the container.
Agent Zero stores config at /a0/usr/settings.json inside the container. Find the mcp_servers field (it's a JSON-encoded string) and add the mnemo-cortex entry:
{
"mcp_servers": "{\"mcpServers\": {\"mnemo-cortex\": {\"command\": \"node\", \"args\": [\"/a0/usr/mnemo-cortex/integrations/mcp-bridge/server.js\"], \"env\": {\"MNEMO_URL\": \"http://YOUR_MNEMO_HOST:50001\", \"MNEMO_AGENT_ID\": \"your-agent-name\", \"MNEMO_SHARE\": \"separate\"}}}}"
}Note the double-encoding:
mcp_serversis a string containing JSON, not a nested object. That's how Agent Zero stores it.
A clean Python patch script that handles this without escape-hell:
# patch-settings.py — run inside the container or as a one-shot
import json
p = "/a0/usr/settings.json"
d = json.load(open(p))
d["mcp_servers"] = json.dumps({
"mcpServers": {
"mnemo-cortex": {
"command": "node",
"args": ["/a0/usr/mnemo-cortex/integrations/mcp-bridge/server.js"],
"env": {
"MNEMO_URL": "http://YOUR_MNEMO_HOST:50001",
"MNEMO_AGENT_ID": "your-agent-name",
"MNEMO_SHARE": "separate"
}
}
}
})
d.setdefault("mcp_client_init_timeout", 10)
d.setdefault("mcp_client_tool_timeout", 120)
json.dump(d, open(p, "w"), indent=2)
print("patched")Replace YOUR_MNEMO_HOST with where your Mnemo server is reachable from inside the container (often host.docker.internal on Mac/Windows, the Tailscale hostname for remote, or the explicit IP). Replace your-agent-name with a unique ID per agent (bw, cliff, research-bot, etc.).
docker restart <container-name>Agent Zero reads settings.json at startup. Settings changes do NOT hot-reload reliably — restart is the safe path.
Once the container is back up, run a smoke test of the bridge from inside:
docker exec <container-name> bash -c "
cd /a0/usr/mnemo-cortex/integrations/mcp-bridge &&
( echo '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-11-25\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1\"}}}'
sleep 1
echo '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\",\"params\":{}}'
sleep 2 ) | MNEMO_URL=http://YOUR_MNEMO_HOST:50001 MNEMO_AGENT_ID=your-agent-name node server.js 2>&1 | head -10
"Expected output: [mnemo-mcp] Connected to Mnemo Cortex (N memories, share: separate) followed by an MCP tools listing. If you see "Connected" you're good.
For a full round-trip test: open the Agent Zero UI (port 80 inside the container, mapped to whatever host port you assigned), give the agent a task that involves remembering something, and ask it to recall in a fresh session. If it finds the memory, you're wired.
Same warning as every Mnemo integration: non-tool-capable models will narrate fake save IDs without actually calling the tool. Confirmed working: Qwen3 (any size), GPT-4/4o, Claude 3.5+, Mistral 7B Instruct v0.3, Nemotron-120B-free. Avoid older Llama 3.1 variants for memory tasks.
MNEMO_URL=http://localhost:50001 from inside an Agent Zero container points at the container's localhost, not your host. Use:
- Mnemo on the same host (Mac/Windows Docker):
http://host.docker.internal:50001 - Mnemo on the same host (Linux Docker): add
--add-host=host.docker.internal:host-gatewayat container create, or use the host's LAN IP - Mnemo elsewhere via Tailscale: install Tailscale on the host; on Mac/Windows the container inherits Tailnet routing, on Linux you may need explicit DNS or routing
- Mnemo on the public internet: use the public hostname; auth is on you
Verify before fighting Agent Zero config:
docker exec <container> curl -s http://YOUR_MNEMO_HOST:50001/healthAgent Zero's settings.json stores mcp_servers as a JSON-encoded string containing the full server config. Not a nested object. Trips a lot of people on first edit. The Python patch script above handles it correctly.
Each container is its own Mnemo agent. Pick distinct MNEMO_AGENT_ID values per container so memories don't collide. Example pattern (Project Sparks naming): bw for the research agent, cliff for the file courier, cleo for the code-runner — each gets its own memory lane in Mnemo.
Agent Zero has its own embedding-based memory at /a0/tmp/memory/ using HuggingFace sentence-transformers or Ollama embeddings (whatever you've configured). That's separate from Mnemo. Adding Mnemo MCP doesn't replace Agent Zero's local memory — they coexist. Local memory is fast and private to that agent. Mnemo is cross-session, cross-agent. Use both.
| Mode | MNEMO_SHARE= |
Behavior |
|---|---|---|
| Separate (default) | separate |
Each agent sees only its own Mnemo memories |
| Always | always |
Cross-agent search always on |
| Never | never |
Cross-agent search permanently off |
Use always if you have a trusted team of agents that should learn from each other (research bot reads what code bot shipped, etc.). Use separate for clean isolation.
| Variable | Default | Description |
|---|---|---|
MNEMO_URL |
http://localhost:50001 |
Mnemo Cortex API address (often http://host.docker.internal:50001 from a container) |
MNEMO_AGENT_ID |
openclaw (rename per agent) |
Unique identity in the memory system |
MNEMO_SHARE |
separate |
Cross-agent sharing mode |
BRAIN_DIR |
~/mnemo-plan/brain |
Optional — enables brain-file tools when pointed at an existing dir inside the container |
WIKI_DIR |
unset | Optional — enables wiki tools when pointed at an existing dir |
[Agent Zero Web UI on container :80]
│ (LLM decides to use a memory tool)
▼
[Agent Zero MCP client] ──spawns via stdio──▶ [mcp-bridge/server.js (in-container)]
│
│ HTTP POST to /writeback, /context
▼
[Mnemo Cortex API at MNEMO_URL]
│
▼
[Mnemo memory under agent_id=YOURS]
The bridge runs as a child process of Agent Zero, connected via stdio. Each tool call from the LLM becomes a JSON-RPC message to the bridge, which translates to a REST call to Mnemo. Embeddings happen server-side — no embedding-model mismatch is possible from this client.
See the Session Guide. Same patterns apply whether your agent is autonomous or human-driven.
Read THE-LANE-PROTOCOL.md to learn the session ritual that makes Mnemo actually work.
MIT
Part of Mnemo Cortex by Project Sparks