Files
ewoooc/docs/adr/ADR-031-mcp-self-hosted-stack.md
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

5.8 KiB
Raw Permalink Blame History

ADR-031: MCP 自建 Stack — postgres + omnisearch + firecrawl + filesystem

  • Status: Accepted (待 188 deploy 後 Active)
  • Date: 2026-05-04
  • Decision Maker: 統帥
  • Author: Operation Ollama-First v5.0 / Phase 10
  • Related: ADR-028LLM 路由統一準則、ADR-032RAG 自主學習、ADR-033三護欄

Context

戰役 v4.0 階段就提案 MCP 自建(取代 Gemini Grounding 唯一聯網能力),但 Phase 10 因 hook 阻擋 SSH 188 deploy先完成本地 docker-compose.mcp.yml + ADR 設計,待統帥手動 ssh wooo@110 → ssh ollama@188 → docker compose -f docker-compose.mcp.yml up -d 啟用。

為何要自建 MCP

  • mcp_collector_service.py 目前 100% 走 Gemini 2.0 Flash Grounding鎖定 7 場景之一)
  • 若 Gemini API 配額爆 / 政策變更 → 即時情報唯一通路斷
  • 多供應商策略ADR-030需要 Tavily / Exa 作為 grounding 備援
  • Claude Code 直連 momo_pro DBread-only RBAC能加速統帥日常 SQL 查詢

Decision — 4 + 3 容器架構

4 個 MCP server核心

Server port 用途 取代誰
postgres-mcp 127.0.0.1:3001 Claude 直連 momo_pro DBread-only 統帥手動 SQL
mcp-omnisearch 127.0.0.1:3003 Tavily + Exa 統一搜尋 Gemini Grounding
firecrawl-self 127.0.0.1:3002 自建爬蟲(含護欄 #2 部分自寫 BeautifulSoup
filesystem-mcp 127.0.0.1:3004 跨主機檔案操作read-only SSH 跳板手動 cat

3 個輔助容器

Container 用途
firecrawl-redis Firecrawl job queue
firecrawl-playwright Browser poolmem 1.5g
chrome-reaper 每小時清 Chrome 殘留(護欄 #2

護欄 #2 落地Owen v5.0 鐵律)

firecrawl-self:
  deploy:
    resources:
      limits:
        memory: 2g          # ⭐ 硬上限
        cpus: '1.5'
  environment:
    - PLAYWRIGHT_BROWSER_POOL_MAX=3
    - SCRAPE_TIMEOUT_MS=30000
  healthcheck:
    interval: 30s
    start_period: 60s

chrome-reaper:
  command: 每小時 pkill chrome zombie processes

安全設計

  • 僅 127.0.0.1 暴露:避免外網直連 DB / 爬蟲服務
  • read-only volume mountfilesystem-mcp 只能讀
  • postgres-mcp RBACmcp_readonly role 限 SELECT 到熱表ai_insights / ai_calls / mcp_calls / daily_sales_snapshot / competitor_prices / products
  • Tavily/Exa API key 走 env:不寫死 docker-compose

取代 Gemini Grounding 的 fallback 鏈mcp_collector_service.py 改造)

舊:
  Gemini 2.0 Grounding → Gemini 1.5 → Ollama → 靜態

新:
  mcp-omnisearch (Tavily) → omnisearch (Exa) → 
    全失敗 → Gemini 2.0 Grounding (保留為 L4)
    → Gemini 1.5 → Ollama → 靜態

預期 70%+ 流量走免費 Tavily省 ~70% Gemini Grounding 成本。


Alternatives Considered

方案 否決理由
A. 維持 Gemini Grounding 唯一 單供應商風險(已是 ADR-030 否決理由)
B. 用 Brave Search API 2026-02 取消免費 tierA2 web research 紅燈)
C. 純 Tavily 不要 Firecrawl Firecrawl 對 SPA 動態頁更強(蝦皮等 JS-heavy 站)
D. Firecrawl 不限資源 188 主機跑 5+ projectOOM 連鎖reference_188_multi_project
E. 用 SaaS Firecrawl Cloud 成本(自建免費)+ 資料外流風險

Consequences

正面5

  1. Gemini Grounding 多供應商Tavily 主 + Exa 備援,月省 ~70% grounding 成本
  2. Claude 直連 DB:統帥日常 SQL 查詢可走 MCP 介面read-only 安全)
  3. 爬蟲自主性Firecrawl 取代部分自寫爬蟲SPA 反爬蟲更強
  4. 零外部 SaaS 依賴:全部自建在 188Tavily/Exa 是 API 不是 SaaS
  5. Owen 護欄 #2 落地mem_limit + chrome-reaper 防 OOM

負面3

  1. 188 主機資源占用 +4-5GB RAMFirecrawl 2g + Playwright 1.5g + 其他)
  2. Tavily/Exa API key 維護:申請 + 月配額追蹤
  3. mcp_collector_service.py 重構工作量~200 行改動

風險3

  1. Firecrawl OOM 連鎖mem_limit 2g 觸發 OOM kill → mitigate by healthcheck + restart
  2. Tavily 免費額度1000/月)爆mitigate by Exa 備援 + Gemini Grounding L4
  3. postgres-mcp RBAC 設置失誤mitigate by mcp_readonly role 預先建立 + only SELECT

Verification

V1健康檢查

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
# 全部期待 200 OK

V2Firecrawl 資源

ssh ollama@192.168.0.188 'docker stats momo-mcp-firecrawl --no-stream'
# 期望 < 1.8GBmem_limit 2GB 90%

V3Tavily 配額

SELECT COUNT(*) FROM mcp_calls
WHERE server = 'omnisearch' AND tool = 'tavily_search'
  AND called_at > date_trunc('month', NOW());
-- 期望 < 1000免費額度上限

Migration Plan

步驟 工作 狀態
10.1 docker-compose.mcp.yml 寫完 本 commit
10.2 ADR-031 撰寫 本 commit
10.3 統帥申請 Tavily + Exa API key
10.4 momo-db 建 mcp_readonly role + GRANT SELECT
10.5 188 deploy: docker compose -f docker-compose.mcp.yml up -d
10.6 mcp_collector_service.py 改用 mcp-omnisearch取代 Gemini Grounding 主路徑) Phase 10.5
10.7 健康檢查 + Firecrawl mem 監控告警 Phase 10.5

References

  • docker-compose.mcp.yml(本 commit
  • ADR-028LLM 路由)/ ADR-030多供應商/ ADR-033護欄
  • services/mcp_collector_service.py(將改造)
  • A2 web research 報告:docs/phase0_research_report_20260503.md
  • mcp-omnisearch GitHubhttps://github.com/spences10/mcp-omnisearch