703edbe4a1
Added: - generate-config.py registers mempalace as a remote MCP endpoint when MEMPALACE_REMOTE_URL is set (MEMPALACE_REMOTE_TOKEN -> Bearer), else the local stdio command as before. Same env contract as pi-devbox's bridge. - docker-compose.mempalace.yml: optional shared server (mempalace-mcp --transport http), loopback-bound by default. - compose (both) + .env.example(.shared): MEMPALACE_REMOTE_URL/TOKEN + local-vs-external docs. Fixed: - validate.yml: skip validate-base/validate-omos on base-changing commits (base-change-warning now exports base_changed). Previously a commit that changed the base AND tightened smoke-test.sh in lockstep (v2.4.0 nano/micro) hard-failed against the stale base-latest until the release rebuilt it. actionlint clean. README + CHANGELOG (Unreleased).
85 lines
3.4 KiB
YAML
85 lines
3.4 KiB
YAML
# Shared MemPalace server (optional) — one palace for many clients.
|
|
#
|
|
# Runs `mempalace-mcp` over HTTP so several containers/harnesses (pi +
|
|
# opencode + native) can share ONE palace instead of each keeping its own.
|
|
# Point every client at it by setting, in that client's .env:
|
|
#
|
|
# MEMPALACE_REMOTE_URL=http://<reachable-host>:8765/mcp
|
|
#
|
|
# (see .env.example). When set, the client connects over HTTP and does NOT
|
|
# spawn its own local mempalace-mcp.
|
|
#
|
|
# Start: docker compose -f docker-compose.mempalace.yml up -d
|
|
# Stop: docker compose -f docker-compose.mempalace.yml down
|
|
# Logs: docker compose -f docker-compose.mempalace.yml logs -f
|
|
#
|
|
# Why reuse the devbox image? mempalace-mcp is already installed in it, and
|
|
# reusing it GUARANTEES the server's mempalace version matches the clients'
|
|
# (both are pinned by the same image build). Override with a slimmer image via
|
|
# MEMPALACE_SERVER_IMAGE if you prefer (it must provide `mempalace-mcp`).
|
|
#
|
|
# ⚠ SECURITY: mempalace-mcp's HTTP transport has NO authentication of its own.
|
|
# Do NOT expose port 8765 to an untrusted network. The default below binds to
|
|
# 127.0.0.1 (host loopback) only. To let sibling containers reach it, either
|
|
# attach them to the shared `mempalace-net` network (container-to-container, no
|
|
# host port needed — use http://mempalace-server:8765/mcp), or front it with a
|
|
# reverse proxy that enforces MEMPALACE_REMOTE_TOKEN as `Authorization: Bearer`.
|
|
|
|
name: mempalace-server
|
|
|
|
services:
|
|
mempalace:
|
|
image: ${MEMPALACE_SERVER_IMAGE:-joakimp/opencode-devbox:latest}
|
|
container_name: mempalace-server
|
|
# Bypass the devbox entrypoint (dev-shell/LAN/config setup) and run the
|
|
# HTTP MCP server directly. HOME + explicit --palace pin the data path so
|
|
# it does not depend on the image's default user/HOME. Runs as root so it
|
|
# can initialise the fresh named volume; the volume is dedicated to this
|
|
# server (clients reach it over HTTP, never by mounting it).
|
|
entrypoint: []
|
|
user: "0:0"
|
|
environment:
|
|
- HOME=/data
|
|
command:
|
|
- mempalace-mcp
|
|
- --transport
|
|
- http
|
|
- --host
|
|
- "0.0.0.0"
|
|
- --port
|
|
- "8765"
|
|
- --palace
|
|
- /data/.mempalace
|
|
restart: unless-stopped
|
|
# Loopback-only by default (see SECURITY note). Use "8765:8765" to expose on
|
|
# all host interfaces, or drop `ports:` entirely and rely on mempalace-net.
|
|
ports:
|
|
- "127.0.0.1:8765:8765"
|
|
volumes:
|
|
# The shared palace data — precious; back this up.
|
|
- mempalace-shared:/data/.mempalace
|
|
# Embedding-model cache (~79 MB, disposable) so search does not re-download.
|
|
- mempalace-shared-chroma:/data/.cache/chroma
|
|
networks:
|
|
- mempalace-net
|
|
healthcheck:
|
|
# A tools/list round-trip proves the server is answering MCP (python3 is
|
|
# always present — mempalace itself is a python tool in the image).
|
|
test:
|
|
- CMD
|
|
- python3
|
|
- -c
|
|
- "import urllib.request,json; d=json.dumps({'jsonrpc':'2.0','id':1,'method':'tools/list','params':{}}).encode(); r=urllib.request.Request('http://127.0.0.1:8765/mcp',data=d,headers={'Content-Type':'application/json','Accept':'application/json'}); urllib.request.urlopen(r,timeout=5).read()"
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 60s
|
|
|
|
volumes:
|
|
mempalace-shared:
|
|
mempalace-shared-chroma:
|
|
|
|
networks:
|
|
mempalace-net:
|
|
name: mempalace-net
|