- Resolve service_healthy deadlock by using service_started instead - Fix 172.28.0.0/16 network collision by removing ipam config - Add HybridGiteaClient (mcp → rest → bash fallback) - Create .kilo/rules/process-continuity.md with 5 operator-free principles: 1. No service_healthy conditions 2. No hardcoded networks 3. Automatic fallback chains 4. Pre-flight validation 5. Self-documenting failures - Update docker-compose.yml with resilient config: - start_period: 60s, retries: 5, restart: on-failure:3 - /tools healthcheck (guaranteed endpoint) - tmpfs for Node.js /tmp - Resource limits: 256M RAM, 0.5 CPU - MCP/REST integration test passed (issue #109) Refs: Milestone #67, Issues #107, #109
88 lines
2.7 KiB
YAML
88 lines
2.7 KiB
YAML
# GNS-2: MCP Gitea Integration Container
|
|
# Operator-Free Design — lessons learned from Phase 8 failures
|
|
# See: .kilo/rules/process-continuity.md
|
|
#
|
|
# FIXED: No service_healthy deadlock, no hardcoded IP, no SSE-only transport
|
|
# Uses Hybrid MCP↔REST client with automatic fallback
|
|
# MCP SSE supported for clients that support it; REST fallback for shell
|
|
|
|
services:
|
|
mcp-gitea:
|
|
build:
|
|
context: https://github.com/Sqcows/forgejo-mcp.git#main
|
|
dockerfile: Dockerfile
|
|
container_name: mcp-gitea
|
|
environment:
|
|
# Gitea/Forgejo instance config
|
|
FORGEJO_URL: https://git.softuniq.eu
|
|
# Fallback dummy token allows container startup; replace in .env
|
|
FORGEJO_TOKEN: ${FORGEJO_TOKEN:-dummy-fallback-token}
|
|
# MCP server HTTP mode
|
|
PORT: 3001
|
|
FORGEJO_MCP_API_KEY: ${FORGEJO_MCP_API_KEY:-changeme}
|
|
RATE_LIMIT_MAX: 1000
|
|
RATE_LIMIT_WINDOW_MS: 60000
|
|
LOG_LEVEL: info
|
|
ports:
|
|
- "3001:3001"
|
|
networks:
|
|
- gns-network
|
|
# Resilience: on-failure with generous start window
|
|
restart: on-failure:3
|
|
stop_grace_period: 10s
|
|
healthcheck:
|
|
# /tools is always available (list of 103 tools)
|
|
test: ["CMD", "wget", "-qO-", "http://localhost:3001/tools"]
|
|
interval: 15s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 60s
|
|
# Security: non-root user built into Dockerfile; no new privileges
|
|
cap_drop:
|
|
- ALL
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
# tmpfs for Node.js /tmp needs (read-write, but noexec)
|
|
tmpfs:
|
|
- /tmp:noexec,nosuid,size=50m
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
cpus: '0.5'
|
|
memory: 256M
|
|
reservations:
|
|
cpus: '0.25'
|
|
memory: 128M
|
|
|
|
# Optional metrics sidecar — NO service_health dependency
|
|
# Starts even if main container unhealthy; checks periodically
|
|
mcp-gitea-health:
|
|
image: busybox:latest
|
|
container_name: mcp-gitea-health
|
|
command: >
|
|
sh -c "
|
|
sleep 30; # Wait for main container to start
|
|
while true; do
|
|
if wget -qO- http://mcp-gitea:3001/tools > /dev/null 2>&1; then
|
|
echo '$(date -u +%Y-%m-%dT%H:%M:%SZ) MCP Gitea: HEALTHY';
|
|
else
|
|
echo '$(date -u +%Y-%m-%dT%H:%M:%SZ) MCP Gitea: UNHEALTHY';
|
|
fi;
|
|
sleep 30;
|
|
done
|
|
"
|
|
networks:
|
|
- gns-network
|
|
depends_on:
|
|
mcp-gitea:
|
|
condition: service_started # Just wait for start, not healthy
|
|
restart: on-failure:3
|
|
|
|
networks:
|
|
gns-network:
|
|
driver: bridge
|
|
|
|
# --- Operator check after start ---
|
|
# Run: docker compose -f docker/mcp-gitea/docker-compose.yml logs -f mcp-gitea
|
|
# Look for: "HTTP server listening on port 3001"
|
|
# Then test: curl http://localhost:3001/tools | head |