The idle watchdog terminates the process with os._exit(0). systemd's
Restart=on-failure does not restart a unit that exits 0, so a server
installed from this template stops for good after the idle timeout
rather than restarting.
Switch the unit to Restart=always and disable the watchdog in the
server env template, since a dedicated always-on server is not the
per-session case the watchdog was added for.
* 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).