Team and remote¶
You don't need this for local use. The default
pmb connect <agent>keeps PMB local. Supported local clients use one warm daemon on127.0.0.1; stdio-only clients such as Codex reach it throughpmb mcp proxy. This page is only for sharing one memory across several machines or people.
PMB's memory is a SQLite file plus a vector index. By default it lives next to you and only your local agent talks to it. If you want one shared memory - a team on the same workspace, or your own laptop + desktop - you run the MCP server once over HTTP and point every agent at its URL.
Local versus shared¶
| Mode | Use it when | Transport |
|---|---|---|
| Local default | One developer on one machine, even with several agents | Local daemon on 127.0.0.1; Codex uses pmb mcp proxy to bridge stdio to the daemon. |
| Local stdio fallback | A host cannot use the daemon/proxy path | One MCP server process per client. |
| Team / multi-machine | Several machines or people need one memory | One pmb mcp serve process over streamable HTTP with a bearer token. |
When you'd want it¶
| Situation | Why HTTP |
|---|---|
| A team of 5-15 on one workspace | One person records "don't touch X", everyone sees it |
| Your own multiple machines | Work laptop + home desktop on one memory |
| Memory on a server / NAS | One persistent process; agents connect from anywhere |
If none of these apply, stop here and use the normal local daemon/proxy setup.
Run the shared server¶
One persistent process, living next to the SQLite file (a homelab box, a Tailscale node, a small VM):
pmb mcp serve --transport streamable-http --host 0.0.0.0 --port 8765 \
--bearer-token "$(openssl rand -hex 32)"
Then on each developer's machine:
Same MCP, same tools, one shared memory.
Why the bearer token is required¶
Over local stdio there is no network surface. Over the local daemon, PMB keeps
the server bound to 127.0.0.1 and uses its own local token/proxy wiring.
Over HTTP the moment you open a port, anyone who can reach it can read and write your memory. The bearer token is the only thing separating "my agent" from "a random host on the network / mesh". So in HTTP mode it isn't optional hardening - it's the boundary.
PMB does a constant-time comparison (hmac.compare_digest) so a leaked log
line can't side-channel a partial match. CORS preflights (OPTIONS) and the
health endpoint (/healthz, /) pass through unauthenticated; everything
else needs Authorization: Bearer <token>.
Config via environment¶
pmb mcp serve sets these env vars before handing off to the MCP server. If
you run pmb-mcp directly from a systemd unit or Docker image, set them
yourself:
| Env | Default | Meaning |
|---|---|---|
PMB_MCP_TRANSPORT |
stdio in pmb-mcp; pmb mcp serve sets streamable-http by default |
streamable-http for the shared server |
PMB_MCP_HOST |
127.0.0.1 |
0.0.0.0 to accept LAN / mesh |
PMB_MCP_PORT |
8765 |
bind port (don't collide with pmb dashboard) |
PMB_MCP_PATH |
/mcp |
mount path |
PMB_MCP_BEARER_TOKEN |
(empty) | shared secret; empty = unauthenticated |
Heads-up:
pmb dashboardalso defaults to port 8765. If you run both on one host, give one of them a different port.
Tests¶
The auth contract is pinned in tests/integration/test_http_bearer_auth.py: no
token returns 401 when auth is configured, a wrong token returns 401, the
correct token returns 200, preflight and health pass through, and an empty token
disables the gate.