From 94d004338abcf3c8d95a76f8aaba6554385e068d Mon Sep 17 00:00:00 2001 From: B Harper Date: Sun, 26 Oct 2025 16:40:44 +1100 Subject: [PATCH] Implement version-based cache invalidation for MCP tool definitions - Added serverVersion property to McpServerDefinitionProvider that updates on override reloads - VS Code now refreshes cached tool definitions when server version changes - Fixed tool override caching issue where old descriptions persisted - Removed unnecessary delay in notification system - Added debug endpoint /debug/tools for inspecting server-side tool definitions Progress: Startup override loading now works correctly, investigating override reload hang in VS Code --- response-debug.txt | 4 +++ src/extension.ts | 12 ++++++-- src/mcp/server.ts | 46 +++++++++++++++++++++++++++++- src/webview/chatWebviewProvider.ts | 9 +++--- 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/response-debug.txt b/response-debug.txt index 20698cc..2708b31 100644 --- a/response-debug.txt +++ b/response-debug.txt @@ -46,3 +46,7 @@ 2025-10-26T04:35:24.503Z - RESPONSE ENDPOINT CALLED - RequestID: 8-1761453324492 2025-10-26T04:35:34.152Z - RESPONSE ENDPOINT CALLED - RequestID: 9-1761453327469 2025-10-26T04:35:59.241Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1761453262457 +2025-10-26T04:37:02.349Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1761453363480 +2025-10-26T04:37:38.418Z - RESPONSE ENDPOINT CALLED - RequestID: 10-1761453337063 +2025-10-26T04:58:25.162Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761454660214 +2025-10-26T04:59:00.155Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1761454713902 diff --git a/src/extension.ts b/src/extension.ts index cd808ee..0b3a84b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -17,6 +17,7 @@ let serverManager: ServerManager; class HumanAgentMcpProvider implements vscode.McpServerDefinitionProvider { private _onDidChangeMcpServerDefinitions = new vscode.EventEmitter(); readonly onDidChangeMcpServerDefinitions = this._onDidChangeMcpServerDefinitions.event; + private serverVersion: string = Date.now().toString(); constructor(private sessionId: string) {} @@ -24,13 +25,20 @@ class HumanAgentMcpProvider implements vscode.McpServerDefinitionProvider { // Use separate endpoint for MCP tools to avoid SSE conflicts with webview const serverUrl = `http://127.0.0.1:3737/mcp-tools?sessionId=${this.sessionId}`; const serverUri = vscode.Uri.parse(serverUrl); - const server = new vscode.McpHttpServerDefinition('HumanAgent MCP', serverUri); - console.log('HumanAgent MCP: Using separate MCP tools endpoint to avoid SSE conflicts'); + const server = new vscode.McpHttpServerDefinition('HumanAgent MCP', serverUri, {}, this.serverVersion); + console.log(`HumanAgent MCP: Using separate MCP tools endpoint to avoid SSE conflicts (version: ${this.serverVersion})`); return [server]; } + // Update version to force VS Code to refresh cached tool definitions + updateServerVersion(): void { + this.serverVersion = Date.now().toString(); + console.log(`HumanAgent MCP: Updated server version to ${this.serverVersion} to force tool cache refresh`); + } + // Method to fire the change event when override files are reloaded notifyServerDefinitionsChanged(): void { + this.updateServerVersion(); // Force VS Code to refresh cached tool definitions console.log('HumanAgent MCP: Firing onDidChangeMcpServerDefinitions event'); this._onDidChangeMcpServerDefinitions.fire(); } diff --git a/src/mcp/server.ts b/src/mcp/server.ts index e025191..e5f78c4 100644 --- a/src/mcp/server.ts +++ b/src/mcp/server.ts @@ -553,7 +553,7 @@ export class McpServer extends EventEmitter { // Web interface for multi-session chat await this.handleWebInterface(req, res); return; - } else if (req.url?.startsWith('/sessions') || req.url === '/response' || req.url?.startsWith('/tools') || req.url === '/reload' || req.url?.startsWith('/messages/')) { + } else if (req.url?.startsWith('/sessions') || req.url === '/response' || req.url?.startsWith('/tools') || req.url?.startsWith('/debug') || req.url === '/reload' || req.url?.startsWith('/messages/')) { // Session management, response, tools, reload, messages, and chat endpoints await this.handleSessionEndpoint(req, res); return; @@ -1012,6 +1012,39 @@ export class McpServer extends EventEmitter { const finalTools = Array.from(toolMap.values()); res.end(JSON.stringify({ tools: finalTools, merged: true })); } + } else if (req.method === 'GET' && url.pathname.startsWith('/debug/tools')) { + // Debug endpoint to inspect tools for a specific session + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + + const sessionId = url.searchParams.get('sessionId'); + + if (!sessionId) { + res.end(JSON.stringify({ + error: 'sessionId parameter required', + usage: '/debug/tools?sessionId=', + availableSessions: Array.from(this.activeSessions) + })); + return; + } + + const sessionTools = this.sessionTools.get(sessionId); + const defaultTools = Array.from(this.tools.values()); + const tools = this.getAvailableTools(sessionId); + + res.end(JSON.stringify({ + sessionId, + hasSessionTools: sessionTools !== undefined, + sessionToolCount: sessionTools ? sessionTools.size : 0, + sessionToolNames: sessionTools ? Array.from(sessionTools.keys()) : [], + defaultToolCount: defaultTools.length, + finalToolCount: tools.length, + humanAgentChatTool: tools.find(t => t.name === 'HumanAgent_Chat'), + debugInfo: { + sessionExists: this.activeSessions.has(sessionId), + sessionToolsRegistered: this.sessionTools.has(sessionId) + } + })); } else if (req.method === 'POST' && url.pathname === '/reload') { // Reload workspace overrides let body = ''; @@ -1809,6 +1842,7 @@ export class McpServer extends EventEmitter { this.debugLogger.log('TOOLS', `tools/list request - Extension sessionId: ${this.sessionId}, Message params: ${JSON.stringify(message.params)}`); this.debugLogger.log('TOOLS', `Final sessionIdToUse: ${sessionIdToUse || 'default'}`); + this.debugLogger.log('TOOLS', `Available session tools: ${Array.from(this.sessionTools.keys()).join(', ')}`); const tools = this.getAvailableTools(sessionIdToUse); @@ -1818,9 +1852,19 @@ export class McpServer extends EventEmitter { const sessionTools = this.sessionTools.get(sessionIdToUse); if (sessionTools) { this.debugLogger.log('TOOLS', `Session tools found: ${Array.from(sessionTools.keys()).join(', ')}`); + // Log the actual HumanAgent_Chat tool description + const chatTool = sessionTools.get('HumanAgent_Chat'); + if (chatTool) { + this.debugLogger.log('TOOLS', `HumanAgent_Chat description: ${chatTool.description.substring(0, 100)}...`); + } } } else { this.debugLogger.log('TOOLS', `Using default tools (no session ID available)`); + // Also log default tool description for comparison + const defaultChatTool = this.tools.get('HumanAgent_Chat'); + if (defaultChatTool) { + this.debugLogger.log('TOOLS', `Default HumanAgent_Chat description: ${defaultChatTool.description.substring(0, 100)}...`); + } } return { diff --git a/src/webview/chatWebviewProvider.ts b/src/webview/chatWebviewProvider.ts index dd87a45..52e2843 100644 --- a/src/webview/chatWebviewProvider.ts +++ b/src/webview/chatWebviewProvider.ts @@ -322,6 +322,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider { } // Fire VS Code native MCP event to refresh tools + // The version update will force VS Code to refresh cached tool definitions if (this.mcpProvider) { this.mcpProvider.notifyServerDefinitionsChanged(); console.log('Fired onDidChangeMcpServerDefinitions event to refresh VS Code tools'); @@ -988,12 +989,10 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider { // Update status text based on configuration const statusElement = document.getElementById('server-status-text'); if (statusElement && message.data.configType) { - if (message.data.configType === 'workspace') { - statusElement.textContent = 'HumanAgent MCP Server (Workspace)'; - } else if (message.data.configType === 'global') { - statusElement.textContent = 'HumanAgent MCP Server (Global)'; + if (message.data.configType === 'native') { + statusElement.textContent = 'HumanAgent MCP Server (Connected)'; } else { - statusElement.textContent = 'HumanAgent MCP Server (Not Configured)'; + statusElement.textContent = 'HumanAgent MCP Server (Unknown)'; } } console.log('Server status:', message.data);