Built-in tool _webmcp_browser-info para ver navegadores conectados

Agrega metadata tracking de browsers (userAgent, URL, hostname,
idioma, resolucion, timestamp) y tool browser-info para consultarla.
This commit is contained in:
2026-02-13 00:36:51 -06:00
parent 2a07e89a17
commit 603c547bfe
9 changed files with 28745 additions and 31 deletions

View File

@@ -54,6 +54,9 @@ const wss = new WebSocketServer({
// Store active WebSocket connections by channel
const channels = {};
// Store browser metadata per WebSocket connection
const clientMetadata = new Map();
// Special channel paths
const MCP_PATH = '/mcp';
const REGISTER_PATH = '/register';
@@ -356,6 +359,14 @@ wss.on('connection', (ws, req) => {
handleClipboardCopy(data);
break;
case 'clientInfo':
handleClientInfo(ws, data);
break;
case 'clientInfoResponse':
handleToolResponse(data);
break;
case 'clearRegistry':
handleClearRegistry(ws, data);
break;
@@ -391,6 +402,9 @@ wss.on('connection', (ws, req) => {
ws.on('close', async () => {
console.error(`Client disconnected from path: ${clientChannel}`);
// Remove browser metadata
clientMetadata.delete(ws);
// Remove from channel
const channel = channels[clientChannel];
if (channel) {
@@ -468,6 +482,9 @@ wss.on('connection', (ws, req) => {
ws.on('error', (error) => {
console.error('WebSocket error:', error);
// Remove browser metadata
clientMetadata.delete(ws);
// Remove from channel
const channel = channels[clientChannel];
if (channel) {
@@ -814,6 +831,46 @@ function handleRemoveTool(ws, data) {
}
}
// Handle client info sent by browser on connect
function handleClientInfo(ws, data) {
const { userAgent, url, hostname, language, screenWidth, screenHeight, timestamp } = data;
clientMetadata.set(ws, { userAgent, url, hostname, language, screenWidth, screenHeight, timestamp });
console.error(`Client info stored for ${hostname}: ${url}`);
}
// Handle getClientInfo request - collect info from all connected browsers
function handleGetClientInfo(ws, callerChannel, data) {
const { id } = data;
const clients = [];
for (const [channelPath, channelClients] of Object.entries(channels)) {
if (channelPath === MCP_PATH || channelPath === REGISTER_PATH) continue;
for (const clientWs of channelClients) {
const meta = clientMetadata.get(clientWs) || {};
clients.push({
channel: channelPath,
userAgent: meta.userAgent || 'unknown',
url: meta.url || 'unknown',
hostname: meta.hostname || 'unknown',
language: meta.language || 'unknown',
screenWidth: meta.screenWidth || 0,
screenHeight: meta.screenHeight || 0,
connectedSince: meta.timestamp || 0
});
}
}
const text = clients.length > 0
? JSON.stringify(clients, null, 2)
: 'No hay navegadores conectados';
ws.send(JSON.stringify({
id,
type: 'toolResponse',
result: { content: [{ type: 'text', text }] }
}));
}
// Handle clearing all registries
function handleClearRegistry(ws, data) {
const {id} = data;