Architecture
Data Flow & Observability
Understanding Hatago’s data flow makes troubleshooting and performance tuning much easier.
Basic Data Flow
Section titled “Basic Data Flow”Minimal setup
Section titled “Minimal setup”Observation points
Section titled “Observation points”Point | What you see | Typical errors | How to see it |
---|---|---|---|
📍1: Hub input | Request payload, timestamps | JSON parse, auth | --verbose |
📍2: Server I/O | Forwarded req, latency | timeout, connect | --verbose |
📍3: Hub output | Aggregated response | transform errors | --verbose |
Message Flow (tools/list)
Section titled “Message Flow (tools/list)”Error Flow (layers)
Section titled “Error Flow (layers)”Observability
Section titled “Observability”1) Log levels
Section titled “1) Log levels”hatago serve # default log level is roughly "info"
Typical output: server start/stop, major errors, connection state changes.
hatago serve --verbose
Shows request/response details, env expansion, config parsing, and timing markers.
2) Real‑time monitoring
Section titled “2) Real‑time monitoring”# Mirror logs and keep a filehatago serve --verbose 2>&1 | tee hatago.log
# Watch for warnings and timeoutshatago serve --verbose 2>&1 | grep -E "(ERROR|WARN|timeout)"
# Timestamp each line (requires moreutils `ts`)hatago serve --verbose 2>&1 | ts '[%Y-%m-%d %H:%M:%S]'
3) Minimal metrics (HTTP mode, opt‑in)
Section titled “3) Minimal metrics (HTTP mode, opt‑in)”Enable with HATAGO_METRICS=1
, then fetch /metrics
.
HATAGO_METRICS=1 hatago serve --http --port 3535curl -s http://127.0.0.1:3535/metrics | jq .
Example: micro metrics collector
Section titled “Example: micro metrics collector”const { spawn } = require('child_process');const readline = require('readline');
const metrics = { requests: 0, responses: 0, errors: 0, totalTime: 0 };const hatago = spawn('npx', ['@himorishige/hatago-mcp-hub', 'serve', '--verbose'], { stdio: ['pipe','pipe','pipe'] });const rl = readline.createInterface({ input: hatago.stderr, crlfDelay: Infinity });
rl.on('line', (line) => { if (line.includes('Received request')) metrics.requests++; if (line.includes('Response sent')) metrics.responses++; if (line.includes('ERROR')) metrics.errors++; const m = line.match(/\((\d+)ms\)/); if (m) metrics.totalTime += parseInt(m[1]); if (metrics.requests && metrics.requests % 10 === 0) { console.log({ ...metrics, avgMs: metrics.totalTime / (metrics.responses || 1) }); }});
Failure Layers — quick diagnosis
Section titled “Failure Layers — quick diagnosis”Layer | Symptom | Command | First action |
---|---|---|---|
1. Startup | command not found | which hatago | Check PATH or use npx @.../hatago-mcp-hub |
2. Config | Invalid config | `cat hatago.config.json | jq .` |
3. Env | ${VAR} not found | echo $VAR | Export or set in .env |
4. Server spawn | spawn ENOENT | which npx | Use absolute path if needed |
5. Network | ECONNREFUSED | curl -I <url> | Verify URL/firewall |
6. Auth | 401 Unauthorized | echo $API_TOKEN | Refresh token / scopes |
7. Timeout | Request timeout | time curl <url> | Increase timeout / retry |
Performance: quick timing
Section titled “Performance: quick timing”# Extract timing markers from verbose logshatago serve --verbose 2>&1 \ | grep -oE '\\(([^)]*)ms\\)' \ | grep -oE '[0-9]+' \ | awk '{sum+=$1; n++} END{print "avg:", (n?sum/n:0) "ms"}'
Visualizing where time goes
Section titled “Visualizing where time goes”Troubleshooting helper
Section titled “Troubleshooting helper”#!/usr/bin/env bash
echo "🔍 Hatago diagnose"echo "Node.js: $(node --version)"echo "npm: $(npm --version)"echo "Hatago: $(npx @himorishige/hatago-mcp-hub --version 2>/dev/null || echo 'Not installed')"
echo "\n📄 Config:"if [ -f hatago-config.json ]; then jq . hatago-config.json >/dev/null 2>&1 && echo "✅ Valid JSON" || echo "❌ Invalid JSON" echo "Servers: $(jq '.mcpServers | length' hatago-config.json)"else echo "❌ hatago-config.json not found"fi
echo "\n🌐 Quick check:"echo '{"jsonrpc":"2.0","method":"resources/read","id":1,"params":{"uri":"hatago://servers"}}' \ | timeout 5 npx @himorishige/hatago-mcp-hub serve --stdio 2>/dev/null \ | jq -r '.result.contents[0].text' \ | jq -r '.total' \ | grep -Eq '^[0-9]+$' && echo "✅ Hub is responding" || echo "❌ Hub not responding"
Related
Section titled “Related”Troubleshooting
Config Reference