Files
mempalace/website/guide/remote-server.md
T
mvalentsev bd439ae54f fix(mcp): refuse config and ack writes in read-only mode (#2101)
Read-only gated on _MUTATING_TOOLS, which is the palace-write set the
peer-writer lease consults to decide which calls need the palace mine
lock. Two tools change state without touching the palace, so they are
correctly absent from that set and were served on a --read-only server
anyway: mempalace_hook_settings rewrites ~/.mempalace/config.json via
MempalaceConfig.set_hook_setting, and mempalace_memories_filed_away
unlinks ~/.mempalace/hook_state/last_checkpoint on both branches.

Add _READ_ONLY_REFUSED_TOOLS and point the dispatch gate and the
tools/list filter at it. _MUTATING_TOOLS and the peer-writer path are
unchanged: adding the two names there instead would put a config-only
tool under the palace lease, so a server that lost the lease to a peer
would answer -32001 for a call the lease has no say over.

mempalace_reconnect stays reachable on purpose and the comment records
why, since clearing ChromaBackend._quarantined_paths lets the reopen
rename a segment directory. The two --read-only help strings and the
matching row in the remote-server guide said "the mutating tools",
which now names the narrower set.
2026-07-29 19:32:37 +05:00

9.0 KiB

Remote / Team Server

Run MemPalace as a central memory service that a whole team connects to: one host stores the palace, does the embedding (optionally on a GPU), and serves MCP over HTTP. Every teammate's AI reads and writes the same shared memory instead of a palace on each laptop.

This is built from three pieces that already ship in MemPalace:

::: warning This is a deliberate step away from single-machine local-first By default MemPalace keeps everything on your own machine. A central server is still your infrastructure — no telemetry, nothing phones home — but your verbatim memory now lives on a server you operate and travels over your network. If you choose a managed backend such as Zilliz Cloud, that backend also receives the vectors and text by design. Run every self-hosted component (Milvus, Qdrant, Postgres, the MCP host) on hardware you control, put it on a private network or VPN, and treat the bearer token and TLS setup below as mandatory, not optional. Embeddings are still produced locally on the server by MemPalace. :::

Architecture

  Teammate A ─┐
  Teammate B ─┤  MCP over HTTP        ┌─ mempalace-mcp --transport http
  Teammate C ─┴──(bearer token, TLS)─▶│   (one host: embedding + GPU)
                                      └─────────────┬───────────────
                                                    │ vectors + verbatim text
                                                    ▼
                                              Milvus / Qdrant / pgvector
                                              (central storage)

1. Central storage

Pick a networked backend so all clients share one palace. Milvus can point at a self-hosted Milvus server or Zilliz Cloud. Milvus Lite is still local to one palace directory, so use a server URI for team mode.

Install the optional Milvus driver on the server host:

pip install mempalace[milvus]

Point MemPalace at the shared Milvus endpoint:

export MEMPALACE_BACKEND=milvus
export MEMPALACE_MILVUS_URI=https://your-cluster.api.region.zillizcloud.com
export MEMPALACE_MILVUS_TOKEN=your-token

Prefer Qdrant? It needs no extra Python package — MemPalace talks to its REST API directly.

Run Qdrant (Docker shown; use a managed/self-hosted instance you control):

docker run -d --name qdrant -p 6333:6333 \
  -v "$HOME/qdrant_storage:/qdrant/storage" \
  qdrant/qdrant

Point MemPalace at it on the server host:

export MEMPALACE_BACKEND=qdrant
export MEMPALACE_QDRANT_URL=http://localhost:6333
export MEMPALACE_QDRANT_API_KEY=your-qdrant-api-key   # if your Qdrant requires one
Variable Default Purpose
MEMPALACE_BACKEND chroma Set to milvus, qdrant, or pgvector to select the backend
MEMPALACE_MILVUS_URI per-palace Milvus Lite Milvus server / Zilliz Cloud URI
MEMPALACE_MILVUS_TOKEN (none) Token for Milvus server / Zilliz Cloud
MEMPALACE_MILVUS_DB_NAME (none) Optional Milvus database name
MEMPALACE_MILVUS_NAMESPACE (none) Optional Milvus collection namespace prefix
MEMPALACE_MILVUS_CONSISTENCY_LEVEL Strong Milvus consistency level
MEMPALACE_QDRANT_URL http://localhost:6333 Qdrant REST endpoint
MEMPALACE_QDRANT_API_KEY (none) Sent as the api-key header when set
MEMPALACE_QDRANT_NAMESPACE (none) Optional collection namespace prefix
MEMPALACE_QDRANT_TIMEOUT backend default REST request timeout (seconds)

The backend can also be set with --backend milvus (or qdrant / pgvector) on any mempalace / mempalace-mcp command, or with "backend": "milvus" in config.json.

Prefer Postgres? Install pip install mempalace[pgvector], point MEMPALACE_BACKEND=pgvector at a database with the vector extension, and the rest of this guide applies unchanged.

2. GPU embedding (optional)

Embedding is the heaviest step; running it on the server's GPU keeps recall fast for everyone. Install one acceleration extra and select the device:

pip install mempalace[gpu]            # NVIDIA CUDA (onnxruntime-gpu)
export MEMPALACE_EMBEDDING_DEVICE=cuda

Other targets: mempalace[dml] + MEMPALACE_EMBEDDING_DEVICE=dml (DirectML, Windows AMD/Intel/NVIDIA), mempalace[coreml] + =coreml (Apple Neural Engine), or =auto to pick the best available provider. CPU is the default and needs no extra.

3. Serve MCP over HTTP

One command — mempalace serve — runs the server with secure defaults. On a network-exposed (0.0.0.0) bind it auto-generates a strong bearer token (stored 0600 under ~/.mempalace/server/, printed once), prints a ready-to-paste client config, and runs in the foreground so Docker/systemd own the lifecycle.

mempalace serve --host 0.0.0.0 --port 8765 --backend milvus

Output includes the token and the exact client command. Useful flags:

Flag Default Purpose
--host 127.0.0.1 Bind address (0.0.0.0 to accept remote clients)
--port 8765 Listen port
--backend config/env Storage backend (e.g. qdrant)
--tls-cert / --tls-key (none) PEM cert + key to terminate TLS natively (server speaks https)
--read-only off Expose recall only — the tools that change state are hidden and refused
--token auto Use a specific bearer token instead of the generated one
--allow-insecure off Permit a non-loopback bind with no token (only behind a trusted proxy)

The token always travels via the environment, never the command line, so it can't leak through ps. Binding to a non-loopback host with no token and no --allow-insecure refuses to start. The server also guards against DNS-rebinding with a Host allowlist and an Origin loopback check, and serializes concurrent writes — so multiple teammates can write to the shared palace at once over HTTP.

::: tip TLS Pass --tls-cert/--tls-key to terminate TLS in the server itself (https://…). Otherwise the server is plaintext and you should front it with a TLS-terminating reverse proxy (nginx/Caddy/Traefik) — never expose plaintext /mcp beyond a trusted private network. :::

The underlying server is mempalace-mcp --transport http (the same flags exist there if you'd rather wire the token/TLS yourself); mempalace serve is the turnkey wrapper over it.

4. Connect a client

Point each teammate's MCP client at the server's /mcp endpoint with the shared token. For Claude Code:

claude mcp add --transport http mempalace https://memory.example.com/mcp \
  --header "Authorization: Bearer $MEMPALACE_MCP_HTTP_TOKEN"

Other MCP clients use the same two ingredients — the …/mcp URL and an Authorization: Bearer <token> header. Verify connectivity from any host:

curl https://memory.example.com/healthz        # -> ok

Once connected, all of MemPalace's MCP tools operate against the shared palace — searches and saved memories are visible to the whole team.

Operating notes

  • Mining still happens via the CLI (mempalace mine …) on the server host against the same backend, so the central palace stays populated.
  • One writer-lease per process: a single mempalace-mcp --transport http process safely handles concurrent reads and writes. Don't point two server processes at the same backend collection.
  • Health checks: GET /healthz returns 200 ok without a token, so it works as a load-balancer/Kubernetes liveness probe.
  • Backups are now your storage backend's responsibility (Milvus / Zilliz Cloud backups, Qdrant snapshots, or Postgres backups) rather than a single laptop's palace directory.

One-command deployments

The repo ships ready-to-edit deployment files under deploy/:

Docker Compose (server + Qdrant):

cp deploy/server.env.example deploy/.env      # set MEMPALACE_MCP_HTTP_TOKEN
docker compose -f deploy/docker-compose.server.yml --env-file deploy/.env up -d

This brings up a Qdrant container and a MemPalace server running serve --host 0.0.0.0 --backend qdrant, with a /healthz healthcheck and persistent volumes. Embeddings stay local to the MemPalace container.

systemd:

deploy/mempalace-server.service is a hardened unit template (NoNewPrivileges, ProtectSystem=strict, dedicated user) that runs mempalace serve with its config from /etc/mempalace/server.env. Install steps are in the file's header comment.

See also