#!/usr/bin/env python3 """Keep-alive client for MCP bridge - polls for messages and updates heartbeat""" import sys import json import argparse import sqlite3 from datetime import datetime from pathlib import Path def update_heartbeat(db_path: str, conversation_id: str, token: str) -> bool: """Update session heartbeat and check for new messages""" try: if not Path(db_path).exists(): print(f"⚠️ Database not found: {db_path}", file=sys.stderr) print(f"💡 Tip: Orchestrator must create conversations first", file=sys.stderr) return False conn = sqlite3.connect(db_path) conn.row_factory = sqlite3.Row # Verify conversation exists cursor = conn.execute( "SELECT role_a, role_b FROM conversations WHERE id = ?", (conversation_id,) ) conv = cursor.fetchone() if not conv: print(f"❌ Conversation {conversation_id} not found", file=sys.stderr) return False # Check for unread messages cursor = conn.execute( """SELECT COUNT(*) as unread FROM messages WHERE conversation_id = ? AND read_by_b = 0""", (conversation_id,) ) unread_count = cursor.fetchone()['unread'] # Update heartbeat (create session_status table if it doesn't exist) conn.execute( """CREATE TABLE IF NOT EXISTS session_status ( conversation_id TEXT PRIMARY KEY, session_id TEXT NOT NULL, last_heartbeat TEXT NOT NULL, status TEXT DEFAULT 'active' )""" ) conn.execute( """INSERT OR REPLACE INTO session_status (conversation_id, session_id, last_heartbeat, status) VALUES (?, 'session_b', ?, 'active')""", (conversation_id, datetime.utcnow().isoformat()) ) conn.commit() print(f"✅ Heartbeat updated | Unread messages: {unread_count}") if unread_count > 0: print(f"📨 {unread_count} new message(s) available - worker should check") conn.close() return True except sqlite3.OperationalError as e: print(f"❌ Database error: {e}", file=sys.stderr) return False except Exception as e: print(f"❌ Error: {e}", file=sys.stderr) return False if __name__ == "__main__": parser = argparse.ArgumentParser(description="MCP Bridge Keep-Alive Client") parser.add_argument("--conversation-id", required=True, help="Conversation ID") parser.add_argument("--token", required=True, help="Worker token") parser.add_argument("--db-path", default="/tmp/claude_bridge_coordinator.db", help="Database path") args = parser.parse_args() success = update_heartbeat(args.db_path, args.conversation_id, args.token) sys.exit(0 if success else 1)