2026-06-23 16:46:18 +02:00
|
|
|
# Setup: USB → Mother MCP Connection
|
|
|
|
|
|
|
|
|
|
2026-06-23 | Step-by-step | Tested on OSA + 0.11 USB
|
|
|
|
|
|
|
|
|
|
Connects a booted Clawdie USB to the mother node (OSA) via MCP over SSH.
|
|
|
|
|
After setup, `clawdie-hw-probe` runs on the USB, the hardware profile is
|
2026-06-24 10:10:09 +02:00
|
|
|
sent to mother, and stored in PostgreSQL `mother_hive.hive_nodes`.
|
2026-06-23 16:46:18 +02:00
|
|
|
|
|
|
|
|
## Hosts used in this guide
|
|
|
|
|
|
2026-06-24 11:19:21 +02:00
|
|
|
| Host | IP (Tailscale) | User for MCP | Role |
|
|
|
|
|
| ---------------------- | ------------------------ | ------------ | ----------------------------------------------- |
|
|
|
|
|
| `mother` (OSA) | `<mother-tailscale-ip>` | `colibri` | Mother — runs PostgreSQL, external MCP servers |
|
|
|
|
|
| `clawdie-usb` (USB) | `<node-tailscale-ip>` | `clawdie` | Operator workstation — sends hw-probe to mother |
|
2026-06-23 16:46:18 +02:00
|
|
|
|
|
|
|
|
## How it works
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
┌─ USB ────────────────────────────────────────────────────────┐
|
|
|
|
|
│ │
|
|
|
|
|
│ colibri-daemon │
|
|
|
|
|
│ │ │
|
2026-06-24 11:04:36 +02:00
|
|
|
│ │ external-mcp.json (baked): │
|
2026-06-23 16:46:18 +02:00
|
|
|
│ │ "mother": { │
|
|
|
|
|
│ │ "command": "ssh", │
|
2026-06-24 11:19:21 +02:00
|
|
|
│ │ "args": ["-i", "/var/db/colibri/.ssh/mother-mcp", │
|
|
|
|
|
│ │ "mother"] │
|
2026-06-23 16:46:18 +02:00
|
|
|
│ │ } │
|
|
|
|
|
│ │ │
|
2026-06-24 11:04:36 +02:00
|
|
|
│ │ spawns persistent SSH child (no remote command) │
|
2026-06-23 16:46:18 +02:00
|
|
|
│ │ JSON-RPC flows over stdin/stdout ──────────────────────┐ │
|
|
|
|
|
│ │ │ │
|
|
|
|
|
│ │ clawdie-hw-probe → JSON → │ │
|
|
|
|
|
│ │ colibri_external_mcp_call_tool( │ │
|
2026-06-24 11:19:21 +02:00
|
|
|
│ │ server="mother", tool="node_register", ...) ──────┤ │
|
2026-06-23 16:46:18 +02:00
|
|
|
│ │ │ │
|
|
|
|
|
└────┼─────────────────────────────────────────────────────────┘ │
|
|
|
|
|
│ │
|
|
|
|
|
│ Tailscale (WireGuard encrypted) │
|
|
|
|
|
│ │
|
|
|
|
|
┌────┼─────────────────────────────────────────────────────────┐ │
|
|
|
|
|
│ ▼ Mother (OSA) │ │
|
|
|
|
|
│ │ │
|
|
|
|
|
│ /var/db/colibri/.ssh/authorized_keys: │ │
|
|
|
|
|
│ command="/usr/local/bin/colibri-mcp-ssh",restrict,... ◄────┘ │
|
|
|
|
|
│ │
|
2026-06-24 11:04:36 +02:00
|
|
|
│ colibri-mcp-ssh → starts colibri-mcp in stdio MCP mode │
|
2026-06-23 16:46:18 +02:00
|
|
|
│ │
|
2026-06-24 10:10:09 +02:00
|
|
|
│ PostgreSQL mother_hive.hive_nodes ← hw-probe JSON stored │
|
2026-06-23 16:46:18 +02:00
|
|
|
│ │
|
|
|
|
|
└───────────────────────────────────────────────────────────────┘
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Step 1: SSH key + config (on USB)
|
|
|
|
|
|
|
|
|
|
Copy the `mother-mcp` private key to the USB. The public key is already
|
|
|
|
|
authorized on mother. For production: the seed partition places this
|
|
|
|
|
automatically. For testing: scp from OSA or copy manually.
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# === ON USB, as clawdie ===
|
|
|
|
|
|
|
|
|
|
mkdir -p ~/.ssh
|
|
|
|
|
chmod 700 ~/.ssh
|
|
|
|
|
|
|
|
|
|
# Create the private key — replace with real key content
|
|
|
|
|
# This key is authorized on mother as:
|
|
|
|
|
# command="/usr/local/bin/colibri-mcp-ssh",restrict,no-pty,...
|
2026-06-24 11:19:21 +02:00
|
|
|
cat > ~/.ssh/mother-mcp << 'KEY'
|
2026-06-23 16:46:18 +02:00
|
|
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
2026-06-24 11:19:21 +02:00
|
|
|
<your-private-key-here>
|
2026-06-23 16:46:18 +02:00
|
|
|
-----END OPENSSH PRIVATE KEY-----
|
|
|
|
|
KEY
|
2026-06-24 11:19:21 +02:00
|
|
|
chmod 600 ~/.ssh/mother-mcp
|
2026-06-23 16:46:18 +02:00
|
|
|
|
2026-06-24 11:19:21 +02:00
|
|
|
# SSH config — use Tailscale IP so it works without DNS.
|
|
|
|
|
# The Host alias "mother" must match the external-mcp.json entry
|
|
|
|
|
# baked into the ISO. The real IP lives only on the seed, never in the repo.
|
2026-06-23 16:46:18 +02:00
|
|
|
cat > ~/.ssh/config << 'SSH'
|
2026-06-24 11:19:21 +02:00
|
|
|
Host mother
|
|
|
|
|
HostName <mother-tailscale-ip>
|
|
|
|
|
User colibri
|
|
|
|
|
IdentityFile ~/.ssh/mother-mcp
|
2026-06-23 16:46:18 +02:00
|
|
|
IdentitiesOnly yes
|
|
|
|
|
StrictHostKeyChecking accept-new
|
|
|
|
|
SSH
|
|
|
|
|
chmod 600 ~/.ssh/config
|
|
|
|
|
|
|
|
|
|
# Test the connection:
|
2026-06-24 11:19:21 +02:00
|
|
|
ssh mother 'tools' 2>&1 | head -5
|
2026-06-23 16:46:18 +02:00
|
|
|
# Expected output:
|
|
|
|
|
# colibri_status Get Colibri daemon status...
|
|
|
|
|
# colibri_snapshot Get Glasspane snapshot...
|
|
|
|
|
# ...
|
|
|
|
|
```
|
|
|
|
|
|
2026-06-24 11:19:21 +02:00
|
|
|
## Step 2: External MCP calls + registry (baked into ISO)
|
2026-06-23 16:46:18 +02:00
|
|
|
|
2026-06-24 11:19:21 +02:00
|
|
|
`COLIBRI_MCP_EXTERNAL_CALL=1` and the mother `external-mcp.json` entry
|
|
|
|
|
are pre-configured in the ISO image by `scripts/stage-colibri-iso.sh`.
|
|
|
|
|
No manual steps are needed — the daemon picks up both on first boot.
|
2026-06-23 16:46:18 +02:00
|
|
|
|
2026-06-24 11:19:21 +02:00
|
|
|
## Step 3: Install clawdie-hw-probe (on USB)
|
2026-06-23 16:46:18 +02:00
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# === ON USB, as clawdie ===
|
|
|
|
|
|
|
|
|
|
# From the 0.12 feature branch (already committed):
|
|
|
|
|
# Option A — from local repo (if unshallowed):
|
|
|
|
|
cd /home/clawdie/ai/clawdie-iso
|
|
|
|
|
git fetch origin feature/0.12.0
|
|
|
|
|
git show origin/feature/0.12.0:live/operator-session/clawdie-hw-probe \
|
|
|
|
|
| sudo tee /usr/local/bin/clawdie-hw-probe > /dev/null
|
|
|
|
|
sudo chmod 755 /usr/local/bin/clawdie-hw-probe
|
|
|
|
|
|
2026-06-24 11:19:21 +02:00
|
|
|
# Option B — scp from mother:
|
|
|
|
|
# scp colibri@mother:/home/clawdie/ai/clawdie-iso/live/operator-session/clawdie-hw-probe \
|
2026-06-23 16:46:18 +02:00
|
|
|
# /tmp/ && sudo install -m 755 /tmp/clawdie-hw-probe /usr/local/bin/
|
|
|
|
|
|
|
|
|
|
# Test:
|
|
|
|
|
sudo clawdie-hw-probe 2>/dev/null | python3.11 -m json.tool | head -10
|
|
|
|
|
# Expected: JSON with hostname, ram_gb, cpu_model, disks, network_interfaces...
|
|
|
|
|
```
|
|
|
|
|
|
2026-06-24 11:19:21 +02:00
|
|
|
## Step 4: Restart daemon + verify (on USB)
|
2026-06-23 16:46:18 +02:00
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# === ON USB, as clawdie ===
|
|
|
|
|
|
|
|
|
|
# Restart the daemon so it picks up external-mcp.json and the env var
|
|
|
|
|
sudo service colibri_daemon restart
|
|
|
|
|
# Expected: Starting colibri_daemon.
|
|
|
|
|
# colibri-daemon socket ready after 1s
|
|
|
|
|
|
|
|
|
|
# Verify external MCP tools are visible
|
|
|
|
|
colibri-mcp tools 2>&1 | grep external
|
|
|
|
|
# Expected:
|
|
|
|
|
# colibri_external_mcp_servers List configured external MCP servers...
|
|
|
|
|
# colibri_external_mcp_list_tools List tools exposed by...
|
|
|
|
|
# colibri_external_mcp_call_tool Call a tool on an external MCP server...
|
|
|
|
|
|
|
|
|
|
# List mother's registered tools
|
|
|
|
|
colibri-mcp --external-config /usr/local/etc/colibri/external-mcp.json \
|
|
|
|
|
--external-call tools 2>&1 | head -10
|
|
|
|
|
# Expected: tools registered on mother (colibri_status, geodesic_dome, etc.)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## End-to-end test
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# === ON USB ===
|
|
|
|
|
|
|
|
|
|
# 1. Run hw-probe, capture JSON
|
|
|
|
|
HW_JSON=$(sudo clawdie-hw-probe 2>/dev/null)
|
|
|
|
|
|
|
|
|
|
# 2. View what would be sent to mother
|
|
|
|
|
echo "$HW_JSON" | python3.11 -m json.tool | head -15
|
|
|
|
|
|
2026-06-24 10:10:09 +02:00
|
|
|
# 3. Send to mother via MCP (node_register tool lives in the colibri repo: packaging/mother/node-register-mcp)
|
2026-06-24 09:07:48 +02:00
|
|
|
# The 0.12 daemon collects hw-probe at autospawn time and passes it to agents
|
|
|
|
|
# via CLAWDIE_HW_PROFILE env var. For manual testing, pipe JSON-RPC directly:
|
|
|
|
|
printf '{"jsonrpc":"2.0","method":"tools/call","id":1,"params":{"name":"node_register","arguments":{"hostname":"%s","hw_profile":%s}}}\n' \
|
2026-06-24 11:19:21 +02:00
|
|
|
"$(hostname)" "$HW_JSON" | ssh mother 'cat - | /usr/local/bin/node-register-mcp'
|
2026-06-23 16:46:18 +02:00
|
|
|
|
|
|
|
|
# 4. Verify on mother
|
2026-06-24 11:19:21 +02:00
|
|
|
ssh mother 'sudo -u postgres psql -d mother_hive \
|
2026-06-24 10:10:09 +02:00
|
|
|
-c "SELECT hostname, status, capabilities FROM hive_nodes;"'
|
2026-06-23 16:46:18 +02:00
|
|
|
# Expected: both osa.smilepowered.org and clawdie-usb listed
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## What happens after (future — 0.12+)
|
|
|
|
|
|
|
|
|
|
Once the daemon is restarted with `COLIBRI_AUTOSPAWN=YES` and
|
|
|
|
|
`COLIBRI_AUTOSPAWN_BINARY=zot`:
|
|
|
|
|
|
|
|
|
|
1. **zot autospawns** — DeepSeek API key from seed partition
|
2026-06-24 09:07:48 +02:00
|
|
|
2. **Daemon collects hw-probe** — runs `clawdie-hw-probe` at spawn time, passes result
|
|
|
|
|
to zot as `CLAWDIE_HW_PROFILE` env var (zot doesn't run hw-probe itself in 0.12)
|
2026-06-24 11:19:21 +02:00
|
|
|
3. **zot reads env var and calls mother**: `colibri_external_mcp_call_tool(server="mother", tool="node_register", arguments={hostname:..., hw_profile:...})`
|
2026-06-23 16:46:18 +02:00
|
|
|
4. **Mother stores** the hardware profile in PostgreSQL
|
|
|
|
|
5. **Capability trigger fires** — derives `has_gpu`, `ram_gb`, `cpu_cores`, `geodesic_dome_mcp` etc.
|
|
|
|
|
6. **Mother returns capabilities** — zot now knows what this node can do
|
|
|
|
|
7. **zot logs**: "node registered — 12GB RAM, 6 cores, no GPU, geodesic_dome_mcp=true"
|
|
|
|
|
|
|
|
|
|
## Troubleshooting
|
|
|
|
|
|
2026-06-23 18:08:58 +02:00
|
|
|
| Symptom | Likely cause | Fix |
|
|
|
|
|
| ----------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
2026-06-24 11:19:21 +02:00
|
|
|
| `ssh mother` hangs | Tailscale not up | `sudo tailscale up` on USB |
|
|
|
|
|
| `Permission denied (publickey)` | Key not in authorized_keys on mother | Verify: `cat /var/db/colibri/.ssh/authorized_keys` on mother |
|
|
|
|
|
| `Permission denied (publickey)` | Key permissions wrong on USB | `chmod 600 /var/db/colibri/.ssh/mother-mcp` (daemon user) or `~/.ssh/mother-mcp` (clawdie user) |
|
2026-06-23 18:08:58 +02:00
|
|
|
| `daemon: open: Permission denied` | Log file ownership wrong | `chown clawdie: /var/log/colibri/daemon.log` |
|
|
|
|
|
| Daemon starts but no external tools | `COLIBRI_MCP_EXTERNAL_CALL` not set | Check provider.env, restart daemon |
|
2026-06-24 11:19:21 +02:00
|
|
|
| Daemon starts, external tools visible, but calls fail | SSH key path wrong in external-mcp.json | Baked path: `/var/db/colibri/.ssh/mother-mcp` |
|
|
|
|
|
| `error: unrecognized subcommand` | SSH wrapper getting non-allowlisted command | Wrapper only allows `""` (stdio) and `"tools"`; `ssh mother tools` is correct |
|