New packaging/mother/node-register-mcp accepts JSON-RPC tools/call, inserts hw_profile into mother_hive.usb_nodes, and returns the row with auto-derived capabilities (derive_capabilities trigger fires). Requires one-time PostgreSQL setup on mother: CREATE ROLE colibri WITH LOGIN; GRANT CONNECT ON DATABASE mother_hive TO colibri; GRANT INSERT, UPDATE ON usb_nodes TO colibri; GRANT USAGE ON SEQUENCE usb_nodes_id_seq TO colibri; Also updates docs to reflect 0.12 daemon behavior: hw-probe is collected by the daemon (not the agent) and passed via CLAWDIE_HW_PROFILE env var. COLIBRI_AUTOSPAWN_ARGS default is binary-dependent (zot->rpc, others->--mode json).
66 lines
2.7 KiB
Bash
Executable file
66 lines
2.7 KiB
Bash
Executable file
#!/bin/sh
|
|
# node-register MCP tool — register a USB node's hardware profile in PostgreSQL.
|
|
#
|
|
# Accepts a JSON-RPC tools/call request on stdin, inserts the hw_profile into
|
|
# mother_hive.usb_nodes, and returns the result to stdout. The
|
|
# derive_capabilities() trigger auto-computes has_gpu, gpu_vendor,
|
|
# can_run_local_llm, has_wifi, etc. on INSERT.
|
|
#
|
|
# Expected input:
|
|
# {"jsonrpc":"2.0","method":"tools/call","id":1,"params":{"name":"node_register","arguments":{"hostname":"clawdie-usb","hw_profile":{...}}}}
|
|
#
|
|
# Output on success:
|
|
# {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"registered\":true,\"hostname\":\"clawdie-usb\",\"capabilities\":{...}}"}]}}
|
|
#
|
|
# PostgreSQL access: peer auth for the 'colibri' OS user. The operator must run
|
|
# once on mother (as postgres):
|
|
# CREATE ROLE colibri WITH LOGIN;
|
|
# GRANT CONNECT ON DATABASE mother_hive TO colibri;
|
|
# GRANT INSERT, UPDATE ON usb_nodes TO colibri;
|
|
# GRANT USAGE ON SEQUENCE usb_nodes_id_seq TO colibri;
|
|
set -eu
|
|
|
|
DB="mother_hive"
|
|
|
|
# Read JSON-RPC from stdin
|
|
INPUT=$(cat)
|
|
ID=$(echo "$INPUT" | jq -r '.id // "1"')
|
|
HOSTNAME=$(echo "$INPUT" | jq -r '.params.arguments.hostname // ""')
|
|
HW_PROFILE=$(echo "$INPUT" | jq -c '.params.arguments.hw_profile // {}')
|
|
|
|
if [ -z "$HOSTNAME" ]; then
|
|
printf '{"jsonrpc":"2.0","id":%s,"error":{"code":-1,"message":"missing required argument: hostname"}}\n' "$ID"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$HW_PROFILE" = "{}" ]; then
|
|
printf '{"jsonrpc":"2.0","id":%s,"error":{"code":-1,"message":"missing required argument: hw_profile"}}\n' "$ID"
|
|
exit 1
|
|
fi
|
|
|
|
# Escape for psql string literal: double any single quotes, wrap in E'...'
|
|
HW_ESCAPED=$(printf '%s' "$HW_PROFILE" | sed "s/'/''/g")
|
|
HOST_ESCAPED=$(printf '%s' "$HOSTNAME" | sed "s/'/''/g")
|
|
|
|
# Insert/update. The derive_capabilities() trigger fires on INSERT and
|
|
# UPDATE OF hw_profile, so capabilities are always fresh.
|
|
SQL="INSERT INTO usb_nodes (hostname, hw_profile, status, last_seen)
|
|
VALUES (E'${HOST_ESCAPED}', E'${HW_ESCAPED}'::jsonb, 'online', now())
|
|
ON CONFLICT (hostname) DO UPDATE
|
|
SET hw_profile = EXCLUDED.hw_profile,
|
|
status = 'online',
|
|
last_seen = now()"
|
|
|
|
RESULT=$(psql -d "$DB" -tAc "BEGIN; $SQL; SELECT json_build_object(
|
|
'registered', true,
|
|
'hostname', hostname,
|
|
'capabilities', capabilities
|
|
) FROM usb_nodes WHERE hostname = E'${HOST_ESCAPED}'; COMMIT;" 2>&1) || {
|
|
printf '{"jsonrpc":"2.0","id":%s,"error":{"code":-1,"message":"psql failed: %s"}}\n' \
|
|
"$ID" "$(printf '%s' "$RESULT" | sed 's/"/\\"/g' | tr '\n' ' ')"
|
|
exit 1
|
|
}
|
|
|
|
# RESULT is the JSON object from json_build_object
|
|
printf '{"jsonrpc":"2.0","id":%s,"result":{"content":[{"type":"text","text":"%s"}]}}\n' \
|
|
"$ID" "$(printf '%s' "$RESULT" | sed 's/"/\\"/g')"
|