fix(cloud_init): fix opensandbox-mcp binding, registration endpoint, and port check
- Write launcher.py to VM and mount into container instead of relying on
FASTMCP_HOST env var (which FastMCP ignores — host= is passed explicitly
at __init__ time, overriding env). Launcher monkey-patches FastMCP.__init__
default to 0.0.0.0 before import so the server binds on all interfaces.
- Fix _osb_wait_mcp to run python3 socket check via docker exec inside the
container (port 8000 is never mapped to host, so nc -z localhost 8000 always
failed).
- Fix jq path: .id → .server.id (API response is {"server": {"id": "..."}}).
- Fix install endpoint: POST .../install/$agentId → POST .../install with
body {"agentId": "$_AID"} (PUT path returned 404 in validation run).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
94a41356e2
commit
ff4c1c14b3
@@ -172,16 +172,28 @@ chmod 644 "$SWARM_DIR/fluent-bit/fluent-bit.conf" "$SWARM_DIR/fluent-bit/parsers
|
||||
for i in range(1, worker_count(record) + 1)
|
||||
]
|
||||
all_agent_ids = " ".join([lead_id] + worker_ids)
|
||||
osb_domain, osb_protocol = osb
|
||||
opensandbox_register_block = f"""
|
||||
# ── opensandbox-mcp launcher: monkey-patch FastMCP host default to 0.0.0.0 ──
|
||||
# FastMCP.__init__ hard-codes host='127.0.0.1'; FASTMCP_HOST env is ignored
|
||||
# because the value is passed explicitly at construction time. We monkey-patch
|
||||
# the default before import so the server binds on all interfaces inside the
|
||||
# container and is reachable from peer containers in the compose network.
|
||||
cat > "$SWARM_DIR/opensandbox-mcp-launch.py" <<'PYEOF'
|
||||
import os, mcp.server.fastmcp as _fm
|
||||
_orig = _fm.FastMCP.__init__
|
||||
def _p(self, *a, host="0.0.0.0", **k): _orig(self, *a, host=host, **k)
|
||||
_fm.FastMCP.__init__ = _p
|
||||
from opensandbox.config import ConnectionConfig
|
||||
from opensandbox_mcp.server import create_server
|
||||
import anyio
|
||||
mcp = create_server(connection_config=ConnectionConfig(
|
||||
domain=os.environ["OSB_DOMAIN"], protocol=os.environ["OSB_PROTOCOL"]))
|
||||
anyio.run(mcp.run_streamable_http_async)
|
||||
PYEOF
|
||||
chmod 644 "$SWARM_DIR/opensandbox-mcp-launch.py"
|
||||
|
||||
# ── Register opensandbox MCP server for all agents ──────────────────────────
|
||||
_osb_wait_port() {{
|
||||
# $1=host $2=port; poll up to 5 min (100 × 3s)
|
||||
for _i in $(seq 1 100); do
|
||||
nc -z "$1" "$2" 2>/dev/null && return 0
|
||||
sleep 3
|
||||
done
|
||||
return 1
|
||||
}}
|
||||
_osb_wait_api() {{
|
||||
for _i in $(seq 1 60); do
|
||||
curl -sf "http://localhost:{s.swarm_api_port}/health" >/dev/null 2>&1 && return 0
|
||||
@@ -189,18 +201,31 @@ _osb_wait_api() {{
|
||||
done
|
||||
return 1
|
||||
}}
|
||||
# Port check runs inside the opensandbox-mcp container (127.0.0.1 inside =
|
||||
# 0.0.0.0 listener; host-side port is not mapped).
|
||||
_osb_wait_mcp() {{
|
||||
for _i in $(seq 1 100); do
|
||||
docker exec swarm-opensandbox-mcp-1 python3 -c \
|
||||
"import socket; s=socket.socket(); s.settimeout(1); s.connect(('localhost',8000)); s.close()" \
|
||||
2>/dev/null && return 0
|
||||
sleep 3
|
||||
done
|
||||
return 1
|
||||
}}
|
||||
|
||||
echo "[swarm-bootstrap] waiting for swarm API and opensandbox-mcp …"
|
||||
if _osb_wait_api && _osb_wait_port localhost 8000; then
|
||||
if _osb_wait_api && _osb_wait_mcp; then
|
||||
_OSB_SERVER_ID=$(curl -sf -X POST "http://localhost:{s.swarm_api_port}/api/mcp-servers" \\
|
||||
-H "Authorization: Bearer {api_key}" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{{"name":"opensandbox","description":"OpenSandbox isolated code execution","transport":"http","scope":"swarm","url":"http://opensandbox-mcp:8000/mcp"}}' \\
|
||||
| jq -r '.id // empty')
|
||||
| jq -r '.server.id // empty')
|
||||
if [ -n "$_OSB_SERVER_ID" ]; then
|
||||
for _AID in {all_agent_ids}; do
|
||||
curl -sf -X POST "http://localhost:{s.swarm_api_port}/api/mcp-servers/$_OSB_SERVER_ID/install/$_AID" \\
|
||||
-H "Authorization: Bearer {api_key}" >/dev/null 2>&1 || true
|
||||
curl -sf -X POST "http://localhost:{s.swarm_api_port}/api/mcp-servers/$_OSB_SERVER_ID/install" \\
|
||||
-H "Authorization: Bearer {api_key}" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d "{{\\"agentId\\":\\"$_AID\\"}}" >/dev/null 2>&1 || true
|
||||
done
|
||||
echo "[swarm-bootstrap] opensandbox MCP server registered id=$_OSB_SERVER_ID agents={all_agent_ids}"
|
||||
else
|
||||
@@ -448,11 +473,11 @@ def _compose_yaml(settings: Settings, record: DeploymentRecord) -> str:
|
||||
pull_policy: always
|
||||
stop_grace_period: 10s
|
||||
environment:
|
||||
- FASTMCP_HOST=0.0.0.0
|
||||
- FASTMCP_PORT=8000
|
||||
command: >-
|
||||
sh -c "pip install --quiet --no-cache-dir opensandbox-mcp &&
|
||||
opensandbox-mcp --domain {osb_domain} --protocol {osb_protocol} --transport streamable-http"
|
||||
- OSB_DOMAIN={osb_domain}
|
||||
- OSB_PROTOCOL={osb_protocol}
|
||||
volumes:
|
||||
- /opt/swarm/opensandbox-mcp-launch.py:/launch.py:ro
|
||||
command: sh -c "pip install --quiet --no-cache-dir opensandbox-mcp && python3 /launch.py"
|
||||
restart: unless-stopped
|
||||
"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user