-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
190 lines (185 loc) · 8.87 KB
/
Copy pathdocker-compose.yml
File metadata and controls
190 lines (185 loc) · 8.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# MemBerry local infrastructure — self-contained.
#
# Brings up everything MemBerry needs (Neo4j + Redis) with compose-managed
# volumes, so a fresh clone works with no external setup (no ~/infra dependency,
# no pre-created named volumes).
#
# Passwords default to clearly-non-production values and can be overridden via a
# local .env file:
# NEO4J_PASSWORD=... (also put it in NEO4J_PASSWORD for the MCP server)
# REDIS_PASSWORD=... (must match the password in REDIS_URL)
# See .env.example.
services:
neo4j:
image: neo4j:5-community
container_name: memberry-neo4j
ports:
- "127.0.0.1:7474:7474"
- "127.0.0.1:7687:7687"
volumes:
- neo4j_data:/data
- neo4j_plugins:/plugins
environment:
NEO4J_AUTH: neo4j/${NEO4J_PASSWORD:-memberry-local-dev}
NEO4J_PLUGINS: '["apoc", "graph-data-science"]'
NEO4J_dbms_security_procedures_unrestricted: "apoc.*,gds.*"
NEO4J_dbms_memory_heap_initial__size: "256m"
NEO4J_dbms_memory_heap_max__size: "512m"
NEO4J_dbms_memory_pagecache_size: "256m"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:7474 >/dev/null 2>&1 || exit 1"]
interval: 10s
timeout: 5s
retries: 12
start_period: 30s
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: memberry-redis
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD:-memberry-local-dev}", "--appendonly", "yes"]
ports:
- "127.0.0.1:6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli -a \"${REDIS_PASSWORD:-memberry-local-dev}\" ping | grep -q PONG"]
interval: 10s
timeout: 5s
retries: 12
start_period: 10s
restart: unless-stopped
# The MemBerry MCP server. Opt-in via the "app" profile so a plain
# `docker compose up` brings up only the databases (handy when you run the
# server yourself, e.g. via systemd). Full turnkey stack:
# docker compose --profile app up -d --build
# Connects to Neo4j/Redis over the compose network (service DNS), so its
# connection URLs differ from the host-facing ones in .env.
mcp:
profiles: ["app"]
build:
context: .
dockerfile: Dockerfile
image: memberry:local
container_name: memberry-mcp
depends_on:
neo4j:
condition: service_healthy
redis:
condition: service_healthy
environment:
# Container-network connection URLs (override the localhost values in .env).
NEO4J_URI: bolt://neo4j:7687
NEO4J_USER: ${NEO4J_USER:-neo4j}
NEO4J_PASSWORD: ${NEO4J_PASSWORD:-memberry-local-dev}
REDIS_URL: redis://:${REDIS_PASSWORD:-memberry-local-dev}@redis:6379
MCP_PORT: "3101"
# Bind host INSIDE the container. Default 0.0.0.0 so the server is reachable
# through Docker's port proxy; access is restricted at the publish layer
# (the host port binding below), not inside the container.
MEMBERRY_HOST: ${MEMBERRY_BIND_HOST:-0.0.0.0}
# App config — sourced from .env (compose interpolation), safe defaults otherwise.
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
MEMBERRY_API_TOKEN: ${MEMBERRY_API_TOKEN:-}
MEMBERRY_API_TOKENS: ${MEMBERRY_API_TOKENS:-}
MEMBERRY_ALLOW_UNAUTHENTICATED: ${MEMBERRY_ALLOW_UNAUTHENTICATED:-}
MEMBERRY_READONLY: ${MEMBERRY_READONLY:-}
MEMBERRY_REDACT_ON_INGEST: ${MEMBERRY_REDACT_ON_INGEST:-}
MEMBERRY_EMBEDDING_DIM: ${MEMBERRY_EMBEDDING_DIM:-}
MEMBERRY_MODEL_EXTRACTION: ${MEMBERRY_MODEL_EXTRACTION:-}
MEMBERRY_MODEL_SYNTHESIS: ${MEMBERRY_MODEL_SYNTHESIS:-}
MEMBERRY_MODEL_DREAM: ${MEMBERRY_MODEL_DREAM:-}
# Multi-tenant isolation (opt-in). Empty = current single-tenant behavior.
MEMBERRY_TENANT_TOKENS: ${MEMBERRY_TENANT_TOKENS:-}
MEMBERRY_TENANT_DATASTORES: ${MEMBERRY_TENANT_DATASTORES:-}
# When multi-tenant is on, non-tenant tokens are rejected (fail-closed).
# Set true ONLY to restore the legacy default-tenant fallback for a global
# MEMBERRY_API_TOKEN / per-actor MEMBERRY_API_TOKENS in multi-tenant mode.
MEMBERRY_ALLOW_DEFAULT_TENANT: ${MEMBERRY_ALLOW_DEFAULT_TENANT:-}
# Ingest/compile/index path confinement. This is a path INSIDE the
# container; it is mounted read-only from the host below (see volumes).
# Defaults to /workspace so code indexing / ingest / compile have a real
# host-backed root out of the box.
MEMBERRY_INGEST_ALLOW_DIR: ${MEMBERRY_INGEST_ALLOW_DIR:-/workspace}
# gap-15 (T10): OPT-IN wiki autorefresh. When truthy, the MCP server
# recompiles the served wiki (gap-3, port 3200) after store/bootstrap/ingest
# into the shared wiki_output volume mounted at /app/wiki below. Empty
# (default) = OFF = no recompile, behavior unchanged. The wiki viewer's
# fs.watch on /app/wiki then picks up the regenerated markdown.
MEMBERRY_WIKI_AUTOREFRESH: ${MEMBERRY_WIKI_AUTOREFRESH:-}
# Output dir MCP compiles into; must match the wiki viewer's served dir.
MEMBERRY_WIKI_OUTPUT_DIR: ${MEMBERRY_WIKI_OUTPUT_DIR:-/app/wiki}
volumes:
# Host directory exposed read-only to the MCP server for code indexing /
# ingest / compile, confined to /workspace via MEMBERRY_INGEST_ALLOW_DIR.
# Override the host path with MEMBERRY_WORKSPACE_HOST_PATH (default: ./).
- ${MEMBERRY_WORKSPACE_HOST_PATH:-./}:/workspace:ro
# gap-15 (T10): shared wiki output volume. MCP WRITES compiled markdown here
# (when MEMBERRY_WIKI_AUTOREFRESH is on); the wiki service mounts the SAME
# named volume at /app/wiki and serves/watches it. Read-write here (MCP is
# the refresh-time writer); see the wiki service for the reader side.
- wiki_output:/app/wiki
ports:
# Host publish address restricts reachability: 127.0.0.1 = local-only,
# 0.0.0.0 = LAN/server. The container itself binds all interfaces (see
# MEMBERRY_HOST above); this line is the actual access gate.
- "${MEMBERRY_PUBLISH_HOST:-127.0.0.1}:${MCP_PORT:-3101}:3101"
restart: unless-stopped
# The MemBerry wiki viewer. Opt-in via the "wiki" profile so it ships only when
# asked for (setup.sh --with-wiki, or `docker compose --profile wiki up -d`).
# Reuses the same memberry:local image as mcp (so --profile wiki builds/reuses
# one image) and compiles the graph into a browsable wiki served on :3200.
wiki:
profiles: ["wiki"]
image: memberry:local
build:
context: .
dockerfile: Dockerfile
container_name: memberry-wiki
depends_on:
neo4j:
condition: service_healthy
redis:
condition: service_healthy
environment:
NEO4J_URI: bolt://neo4j:7687
NEO4J_USER: ${NEO4J_USER:-neo4j}
NEO4J_PASSWORD: ${NEO4J_PASSWORD:-memberry-local-dev}
REDIS_URL: redis://:${REDIS_PASSWORD:-memberry-local-dev}@redis:6379
# Optional public-URL label for the wiki (e.g. host:3200). Empty by default.
MEMBERRY_WIKI_PUBLIC_LABEL: ${MEMBERRY_WIKI_PUBLIC_LABEL:-}
# The wiki service ALWAYS self-builds (`build` = compile + serve + fs.watch)
# so it works with autorefresh OFF. gap-15 (T10) caveat: when
# MEMBERRY_WIKI_AUTOREFRESH is ON, MCP also writes /app/wiki on refresh events,
# so there are briefly two writers at startup. That's safe — both perform a
# FULL whole-dir recompile (never a partial project set) and the fs.watch
# below re-reads after writes settle. The command is intentionally NOT made
# conditional on the env var (compose can't express that cleanly).
command: ["node_modules/.bin/tsx", "packages/wiki/src/cli.ts", "build", "--output", "/app/wiki", "--port", "3200"]
volumes:
# gap-15 (T10): shared wiki output volume — the SAME named volume the mcp
# service mounts. The wiki service writes it at startup and serves/watches
# it; MCP rewrites it on refresh events when autorefresh is on.
- wiki_output:/app/wiki
ports:
# Same publish-host gating as the mcp service (gap-1): 127.0.0.1 local, 0.0.0.0 server.
- "${MEMBERRY_PUBLISH_HOST:-127.0.0.1}:3200:3200"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3200/wiki/_index >/dev/null 2>&1 || exit 1"]
interval: 30s
timeout: 5s
retries: 3
# OPT-23b: the build compiles the FULL graph BEFORE opening port 3200, and a
# cold full-graph compile can exceed 60s — so a 60s start_period could mark the
# service unhealthy and trigger a restart loop before the port is ever served.
# Widen to a safer cold-compile window.
start_period: 180s
restart: unless-stopped
volumes:
neo4j_data:
neo4j_plugins:
redis_data:
# gap-15 (T10): shared between the mcp (writer on refresh) and wiki (writer at
# startup + reader/watcher) services so MCP-side recompiles surface in the
# served wiki. Only materializes when the wiki profile (and optionally the app
# profile) is up; harmless otherwise.
wiki_output: