Debounce en notificaciones list_changed al registrar tools/prompts/resources

Cuando un browser se conecta y registra N tools de golpe, se enviaban
N notificaciones tools/list_changed en rapida sucesion. Claude Code
las ignoraba y no veia las herramientas hasta el siguiente cambio.
Ahora se agrupan con debounce de 500ms: una sola notificacion al final.
This commit is contained in:
2026-02-13 02:15:00 -06:00
parent 35e5605b31
commit 8b2253355f
3 changed files with 75 additions and 8 deletions

View File

@@ -24910,6 +24910,43 @@ var wsClient = null;
var MCP_PATH = "/mcp"; var MCP_PATH = "/mcp";
var pendingRequests = /* @__PURE__ */ new Map(); var pendingRequests = /* @__PURE__ */ new Map();
var requestIdCounter = 1; var requestIdCounter = 1;
var toolListChangedTimer = null;
var promptListChangedTimer = null;
var resourceListChangedTimer = null;
var LIST_CHANGED_DEBOUNCE_MS = 500;
function debouncedToolListChanged() {
if (toolListChangedTimer) clearTimeout(toolListChangedTimer);
toolListChangedTimer = setTimeout(async () => {
toolListChangedTimer = null;
try {
await mcpServer.sendToolListChanged();
} catch (e) {
console.error("Error sending tool list changed:", e);
}
}, LIST_CHANGED_DEBOUNCE_MS);
}
function debouncedPromptListChanged() {
if (promptListChangedTimer) clearTimeout(promptListChangedTimer);
promptListChangedTimer = setTimeout(async () => {
promptListChangedTimer = null;
try {
await mcpServer.sendPromptListChanged();
} catch (e) {
console.error("Error sending prompt list changed:", e);
}
}, LIST_CHANGED_DEBOUNCE_MS);
}
function debouncedResourceListChanged() {
if (resourceListChangedTimer) clearTimeout(resourceListChangedTimer);
resourceListChangedTimer = setTimeout(async () => {
resourceListChangedTimer = null;
try {
await mcpServer.sendResourceListChanged();
} catch (e) {
console.error("Error sending resource list changed:", e);
}
}, LIST_CHANGED_DEBOUNCE_MS);
}
async function handleWebSocketMessage(message) { async function handleWebSocketMessage(message) {
try { try {
const data = JSON.parse(message); const data = JSON.parse(message);
@@ -25006,11 +25043,11 @@ async function handleWebSocketMessage(message) {
console.error(`No pending request found for ID: ${id}`); console.error(`No pending request found for ID: ${id}`);
} }
} else if (data.type === "toolRegistered") { } else if (data.type === "toolRegistered") {
await mcpServer.sendToolListChanged(); debouncedToolListChanged();
} else if (data.type === "resourceRegistered") { } else if (data.type === "resourceRegistered") {
await mcpServer.sendResourceListChanged(); debouncedResourceListChanged();
} else if (data.type === "promptRegistered") { } else if (data.type === "promptRegistered") {
await mcpServer.sendPromptListChanged(); debouncedPromptListChanged();
} else if (data.type === "welcome") { } else if (data.type === "welcome") {
console.error(`Connected to path: ${data.channel}`); console.error(`Connected to path: ${data.channel}`);
} else if (data.type === "pong") { } else if (data.type === "pong") {

File diff suppressed because one or more lines are too long

View File

@@ -48,6 +48,36 @@ const MCP_PATH = '/mcp';
const pendingRequests = new Map(); const pendingRequests = new Map();
let requestIdCounter = 1; let requestIdCounter = 1;
// Debounce timers for list changed notifications
let toolListChangedTimer = null;
let promptListChangedTimer = null;
let resourceListChangedTimer = null;
const LIST_CHANGED_DEBOUNCE_MS = 500;
function debouncedToolListChanged() {
if (toolListChangedTimer) clearTimeout(toolListChangedTimer);
toolListChangedTimer = setTimeout(async () => {
toolListChangedTimer = null;
try { await mcpServer.sendToolListChanged(); } catch (e) { console.error('Error sending tool list changed:', e); }
}, LIST_CHANGED_DEBOUNCE_MS);
}
function debouncedPromptListChanged() {
if (promptListChangedTimer) clearTimeout(promptListChangedTimer);
promptListChangedTimer = setTimeout(async () => {
promptListChangedTimer = null;
try { await mcpServer.sendPromptListChanged(); } catch (e) { console.error('Error sending prompt list changed:', e); }
}, LIST_CHANGED_DEBOUNCE_MS);
}
function debouncedResourceListChanged() {
if (resourceListChangedTimer) clearTimeout(resourceListChangedTimer);
resourceListChangedTimer = setTimeout(async () => {
resourceListChangedTimer = null;
try { await mcpServer.sendResourceListChanged(); } catch (e) { console.error('Error sending resource list changed:', e); }
}, LIST_CHANGED_DEBOUNCE_MS);
}
// Function to handle WebSocket messages // Function to handle WebSocket messages
async function handleWebSocketMessage(message) { async function handleWebSocketMessage(message) {
try { try {
@@ -174,11 +204,11 @@ async function handleWebSocketMessage(message) {
console.error(`No pending request found for ID: ${id}`); console.error(`No pending request found for ID: ${id}`);
} }
} else if (data.type === 'toolRegistered') { } else if (data.type === 'toolRegistered') {
await mcpServer.sendToolListChanged(); debouncedToolListChanged();
} else if (data.type === 'resourceRegistered') { } else if (data.type === 'resourceRegistered') {
await mcpServer.sendResourceListChanged(); debouncedResourceListChanged();
} else if (data.type === 'promptRegistered') { } else if (data.type === 'promptRegistered') {
await mcpServer.sendPromptListChanged(); debouncedPromptListChanged();
} else if (data.type === 'welcome') { } else if (data.type === 'welcome') {
// Welcome message from the server, we're already connected to the MCP path // Welcome message from the server, we're already connected to the MCP path
console.error(`Connected to path: ${data.channel}`); console.error(`Connected to path: ${data.channel}`);