Files
ewoooc/docker-compose.mcp.yml
OoO 4e82acc0f5 feat(p10)+docs(adr): MCP 自建 Stack docker-compose + ADR-031
Operation Ollama-First v5.0 / Phase 10 + Phase 12 收尾

docker-compose.mcp.yml — 4+3 容器 MCP stack
- postgres-mcp (port 3001): Claude 直連 momo_pro DB read-only RBAC
- mcp-omnisearch (3003): Tavily 主 + Exa 備(取代 Gemini Grounding)
  避開 Brave(2026-02 取消免費 tier)
- firecrawl-self (3002): 自建爬蟲,SPA 反爬蟲
- filesystem-mcp (3004): 跨主機檔案 read-only

護欄 #2 落地(Owen v5.0 鐵律 / ADR-033):
  firecrawl-self mem_limit:2g + cpus:1.5
  PLAYWRIGHT_BROWSER_POOL_MAX=3
  chrome-reaper sidecar 每小時清 Chrome zombies

安全設計:
- 全部 127.0.0.1 暴露(不外網)
- read-only volume mount(filesystem 只能讀)
- postgres-mcp RBAC mcp_readonly role 限 SELECT 6 熱表
- API key 全走 env var 不寫死

ADR-031 — MCP 自建 Stack 治理決策
- 取代 Gemini Grounding 唯一通路(多供應商策略)
- 預期 70%+ grounding 流量走免費 Tavily
- 188 主機資源 +4-5GB RAM 可控
- Migration Plan:6 步驟(含 Tavily/Exa key 申請 + mcp_readonly role 預建)

啟用前置(待統帥):
1. .env 加 TAVILY_API_KEY / EXA_API_KEY / MCP_POSTGRES_PASSWORD / FIRECRAWL_AUTH_KEY
2. momo-db 建 mcp_readonly role + GRANT SELECT
3. ssh wooo@110 → ssh ollama@188 → docker compose -f docker-compose.mcp.yml up -d

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 09:02:07 +08:00

183 lines
8.2 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# Operation Ollama-First v5.0 / Phase 10 — MCP 自建 Stack
# =============================================================================
# 部署位置188 主機,與既有 momo-pro 容器共存
# 啟動方式docker compose -f docker-compose.mcp.yml up -d
# 啟用前置:
# 1. .env 加 TAVILY_API_KEYTavily 1000 free credits/月)
# 2. .env 加 EXA_API_KEYExa 備援)
# 3. 確認 188 防火牆 allow 172.x docker bridge 對外firecrawl 抓網頁)
#
# 4 個 MCP server 對應 ADR-031 (Phase 10) 規格:
# - postgres-mcp: Claude 直連 momo_pro DBread-only RBAC
# - mcp-omnisearch: 取代 Gemini GroundingTavily 主 + Exa 備
# - firecrawl-self: 自建爬蟲(含 Owen v5.0 護欄 #2 mem_limit:2g + chrome-reaper
# - filesystem-mcp: 跨主機檔案操作
#
# 護欄一覽ADR-033
# #2 Firecrawl mem_limit:2g + chrome-reaper sidecar + 1.8GB 告警
#
# 部署後驗收(給統帥):
# curl http://localhost:3001/health # postgres-mcp
# curl http://localhost:3002/health # firecrawl
# curl http://localhost:3003/health # omnisearch
# curl http://localhost:3004/health # filesystem
# =============================================================================
services:
# ─────────────────────────────────────────────────────────────────────────
# postgres-mcp: Claude 直連 momo_pro DBread-only
# ─────────────────────────────────────────────────────────────────────────
postgres-mcp:
image: mcp/postgres:latest
container_name: momo-mcp-postgres
restart: unless-stopped
init: true
ports:
- "127.0.0.1:3001:3000" # 僅 localhost 暴露(避免外網直連 DB
environment:
- POSTGRES_HOST=momo-db
- POSTGRES_PORT=5432
- POSTGRES_USER=mcp_readonly # 須在 momo-db 預先建 read-only role
- POSTGRES_PASSWORD=${MCP_POSTGRES_PASSWORD}
- POSTGRES_DB=momo_pro
# RBAC限制 SELECT 到熱表
- ALLOWED_TABLES=ai_insights,ai_calls,mcp_calls,daily_sales_snapshot,competitor_prices,products
networks:
- momo-shared
deploy:
resources:
limits:
memory: 256m
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
# ─────────────────────────────────────────────────────────────────────────
# mcp-omnisearch: 統一搜尋Tavily 主 + Exa 備)
# ─────────────────────────────────────────────────────────────────────────
mcp-omnisearch:
image: ghcr.io/spences10/mcp-omnisearch:latest
container_name: momo-mcp-omnisearch
restart: unless-stopped
init: true
ports:
- "127.0.0.1:3003:3000"
environment:
# 排除 Brave2026-02 已取消免費 tier
- TAVILY_API_KEY=${TAVILY_API_KEY} # 1000 free credits/月(主)
- EXA_API_KEY=${EXA_API_KEY} # 1000 free credits/月(備援)
- SEARCH_PROVIDER_ORDER=tavily,exa # fallback 順序
deploy:
resources:
limits:
memory: 512m
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
# ─────────────────────────────────────────────────────────────────────────
# firecrawl-self: 自建爬蟲(含 Owen v5.0 護欄 #2
# ─────────────────────────────────────────────────────────────────────────
firecrawl-self:
image: firecrawl/firecrawl:latest
container_name: momo-mcp-firecrawl
restart: unless-stopped
init: true
ports:
- "127.0.0.1:3002:3002"
environment:
- REDIS_URL=redis://firecrawl-redis:6379
- PLAYWRIGHT_MICROSERVICE_URL=http://firecrawl-playwright:3000
- PLAYWRIGHT_BROWSER_POOL_MAX=3 # ⭐ 護欄 #2瀏覽器池上限
- SCRAPE_TIMEOUT_MS=30000
- BULL_AUTH_KEY=${FIRECRAWL_AUTH_KEY:-momo-internal-only}
depends_on:
- firecrawl-redis
- firecrawl-playwright
deploy:
resources:
limits:
memory: 2g # ⭐ Owen v5.0 護欄 #2 硬上限
cpus: '1.5'
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3002/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
firecrawl-redis:
image: redis:7-alpine
container_name: momo-mcp-firecrawl-redis
restart: unless-stopped
deploy:
resources:
limits:
memory: 128m
firecrawl-playwright:
image: firecrawl/playwright:latest
container_name: momo-mcp-firecrawl-playwright
restart: unless-stopped
deploy:
resources:
limits:
memory: 1.5g
cpus: '1.0'
# ─────────────────────────────────────────────────────────────────────────
# chrome-reaper: 護欄 #2 — 每小時清 Chrome 殘留
# ─────────────────────────────────────────────────────────────────────────
chrome-reaper:
image: alpine:3
container_name: momo-mcp-chrome-reaper
restart: unless-stopped
command: |
sh -c '
apk add --no-cache docker-cli;
while true; do
echo "[reaper] $(date) cleaning Chrome zombies...";
docker exec momo-mcp-firecrawl-playwright \
sh -c "pkill -f \"chrome.*--type=zygote\" 2>/dev/null || true;
pkill -f \"chrome.*--type=renderer\" 2>/dev/null || true" \
2>/dev/null || true;
sleep 3600;
done
'
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# ─────────────────────────────────────────────────────────────────────────
# filesystem-mcp: 跨主機檔案操作(限本地)
# ─────────────────────────────────────────────────────────────────────────
filesystem-mcp:
image: mcp/filesystem:latest
container_name: momo-mcp-filesystem
restart: unless-stopped
init: true
ports:
- "127.0.0.1:3004:3000"
environment:
- ALLOWED_PATHS=/data,/logs # 限制存取範圍
volumes:
- ./data:/data:ro # ⚠️ ro 唯讀,避免 LLM 改檔
- ./logs:/logs:ro
deploy:
resources:
limits:
memory: 128m
# ─────────────────────────────────────────────────────────────────────────────
# 與既有 momo-pro 共用 network讓 postgres-mcp 連 momo-db
# ─────────────────────────────────────────────────────────────────────────────
networks:
momo-shared:
external: true
name: momo-pro_default # 既有 docker-compose.yml 的 default network