From e09671cdcb9b11d59d41710b7dd6f9d6089543d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:16:58 +0100 Subject: [PATCH] feat: broadcast system notifications on MCP server register/unregister Peers now receive [system] notifications when MCP servers join or leave the mesh, with tool names and hosting peer info. Co-Authored-By: Claude Sonnet 4.6 --- apps/broker/src/index.ts | 38 ++++++++++++++++++++++++++++++++++++++ apps/cli/src/mcp/server.ts | 5 +++++ 2 files changed, 43 insertions(+) diff --git a/apps/broker/src/index.ts b/apps/broker/src/index.ts index bb1f607..217438e 100644 --- a/apps/broker/src/index.ts +++ b/apps/broker/src/index.ts @@ -2487,6 +2487,25 @@ function handleConnection(ws: WebSocket): void { toolCount: mr.tools.length, ...(_reqId ? { _reqId } : {}), }); + // Broadcast to all peers: new MCP server available + const mcpJoinMsg: WSServerMessage = { + type: "push", + subtype: "system", + event: "mcp_registered", + eventData: { serverName: mr.serverName, description: mr.description, tools: mr.tools.map(t => t.name), hostedBy: conn.displayName }, + messageId: crypto.randomUUID(), + meshId: conn.meshId, + senderPubkey: "system", + priority: "low", + nonce: "", + ciphertext: "", + createdAt: new Date().toISOString(), + }; + for (const [pid, peer] of connections) { + if (pid === presenceId) continue; + if (peer.meshId !== conn.meshId) continue; + sendToPeer(pid, mcpJoinMsg); + } log.info("ws mcp_register", { presence_id: presenceId, server: mr.serverName, @@ -2500,6 +2519,25 @@ function handleConnection(ws: WebSocket): void { const entry = mcpRegistry.get(unregKey); if (entry && entry.presenceId === presenceId) { mcpRegistry.delete(unregKey); + // Broadcast: MCP server removed + const mcpLeaveMsg: WSServerMessage = { + type: "push", + subtype: "system", + event: "mcp_unregistered", + eventData: { serverName: mu.serverName, hostedBy: conn.displayName }, + messageId: crypto.randomUUID(), + meshId: conn.meshId, + senderPubkey: "system", + priority: "low", + nonce: "", + ciphertext: "", + createdAt: new Date().toISOString(), + }; + for (const [pid, peer] of connections) { + if (pid === presenceId) continue; + if (peer.meshId !== conn.meshId) continue; + sendToPeer(pid, mcpLeaveMsg); + } } log.info("ws mcp_unregister", { presence_id: presenceId, diff --git a/apps/cli/src/mcp/server.ts b/apps/cli/src/mcp/server.ts index adca709..d1e1290 100644 --- a/apps/cli/src/mcp/server.ts +++ b/apps/cli/src/mcp/server.ts @@ -1354,6 +1354,11 @@ Your message mode is "${messageMode}". content = `[system] Peer "${data.name ?? "unknown"}" joined the mesh`; } else if (eventName === "peer_left") { content = `[system] Peer "${data.name ?? "unknown"}" left the mesh`; + } else if (eventName === "mcp_registered") { + const tools = Array.isArray(data.tools) ? (data.tools as string[]).join(", ") : ""; + content = `[system] New MCP server available: "${data.serverName}" (hosted by ${data.hostedBy}). Tools: ${tools}. Use mesh_tool_call to invoke.`; + } else if (eventName === "mcp_unregistered") { + content = `[system] MCP server "${data.serverName}" removed (was hosted by ${data.hostedBy})`; } else { content = `[system] ${eventName}: ${JSON.stringify(data)}`; }