* feat(serve): turnkey secure remote MCP server (#1877) Add `mempalace serve`: a secure-by-default wrapper over the HTTP MCP transport so a team can stand up a shared central palace with one command. Server capabilities (mempalace/mcp_server.py): - Native TLS via --tls-cert/--tls-key (env MEMPALACE_MCP_TLS_CERT/_KEY): wraps the socket in a TLS 1.2+ context, validated before bind. Token is still required on a non-loopback bind (TLS != auth). - Read-only mode via --read-only (env MEMPALACE_MCP_READ_ONLY): the 24 mutating tools are hidden from tools/list and refused at dispatch (-32003), enforced before arg handling — not merely hidden. Turnkey command (mempalace/cli.py): - Auto-generates a strong bearer token for non-loopback binds, stored 0600 under ~/.mempalace/server/ and printed once; reused across restarts. Token rides in the child env, never argv, so it can't leak via ps. - Prints a ready-to-paste client config (scheme reflects TLS), then foreground-execs the real server so Docker/systemd own the lifecycle. Deployment (deploy/): - docker-compose.server.yml wires the server + Qdrant with a /healthz healthcheck and persistent volumes. - server.env.example documents the env surface. - mempalace-server.service is a hardened systemd unit template. Tests: TLS handshake (openssl-gated), read-only enforcement, token autogen/0600/reuse, token-not-in-argv, secure-by-default gates. Docs: remote-server guide now leads with `mempalace serve` plus Compose and systemd subsections. * test(serve): fix Windows — don't patch os.name; gate 0600 asserts to POSIX Patching os.name to 'posix' broke Path.home() on Windows (pathlib mixed POSIX home resolution with Windows drive parsing). Capture both exec branches (os.execve + subprocess.run) instead, and guard the POSIX permission-bit assertions behind os.name == 'posix' (Windows files report 0o666).
49 lines
1.7 KiB
Desktop File
49 lines
1.7 KiB
Desktop File
# MemPalace remote MCP server — systemd unit template.
|
|
#
|
|
# Install:
|
|
# sudo useradd --system --home /var/lib/mempalace --shell /usr/sbin/nologin mempalace
|
|
# sudo install -d -o mempalace -g mempalace -m 750 /var/lib/mempalace /etc/mempalace
|
|
# sudo cp deploy/server.env.example /etc/mempalace/server.env # then edit + chmod 600
|
|
# sudo install -m 600 -o mempalace -g mempalace /etc/mempalace/server.env /etc/mempalace/server.env
|
|
# # install mempalace into a venv on PATH, or adjust ExecStart to its absolute path
|
|
# sudo cp deploy/mempalace-server.service /etc/systemd/system/
|
|
# sudo systemctl daemon-reload && sudo systemctl enable --now mempalace-server
|
|
#
|
|
# This binds 0.0.0.0:8765 and requires MEMPALACE_MCP_HTTP_TOKEN (set in the
|
|
# EnvironmentFile). Front it with a TLS-terminating reverse proxy, or set
|
|
# MEMPALACE_MCP_TLS_CERT / _KEY in the EnvironmentFile for native TLS.
|
|
|
|
[Unit]
|
|
Description=MemPalace remote MCP server
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=exec
|
|
User=mempalace
|
|
Group=mempalace
|
|
EnvironmentFile=/etc/mempalace/server.env
|
|
ExecStart=mempalace serve --host 0.0.0.0 --port 8765
|
|
Restart=on-failure
|
|
RestartSec=2
|
|
|
|
# --- Hardening ---------------------------------------------------------------
|
|
NoNewPrivileges=true
|
|
ProtectSystem=strict
|
|
ProtectHome=true
|
|
PrivateTmp=true
|
|
PrivateDevices=true
|
|
ProtectKernelTunables=true
|
|
ProtectKernelModules=true
|
|
ProtectControlGroups=true
|
|
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
|
RestrictNamespaces=true
|
|
LockPersonality=true
|
|
MemoryDenyWriteExecute=false
|
|
# The palace and any local state live here; everything else is read-only.
|
|
ReadWritePaths=/var/lib/mempalace
|
|
StateDirectory=mempalace
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|