mirror of
https://github.com/wassname/HumanAgent-MCP.git
synced 2026-09-09 11:14:27 +08:00
Fix SSE connection conflicts between webview and extension
- Added separate /mcp-tools endpoint for VS Code extension MCP protocol - Maintained /mcp endpoint for webview SSE connections (heartbeats, messages) - Eliminated competing SSE connections that caused message delivery failures - Enhanced SSE connection health monitoring with detailed diagnostics - Added connection state management to prevent race conditions - Fixed sendToSession() to use proper health checking instead of raw writes - Improved logging to track connection conflicts and message delivery - Maintains proper session separation between different VS Code workspaces This resolves the issue where VS Code webview received heartbeats but not tool call messages due to competing SSE connections overwriting each other.
This commit is contained in:
Vendored
-644
@@ -1,644 +0,0 @@
|
||||
[2025-10-24 20:43:48.111] [DEBUG] Debug logging started at 2025-10-24T09:43:48.111Z
|
||||
[2025-10-24 20:43:48.111] [DEBUG] Current system time: Fri Oct 24 2025 20:43:48 GMT+1100 (Australian Eastern Daylight Time)
|
||||
[2025-10-24 20:43:48.111] [DEBUG] Log file: /Users/benharper/Coding/HumanAgent-MCP/.vscode/HumanAgent-server.log
|
||||
[2025-10-24 20:43:48.111] [DEBUG] Working directory: /Users/benharper/Coding/HumanAgent-MCP
|
||||
[2025-10-24 20:43:48.111] [DEBUG] Logging level set to: DEBUG
|
||||
[2025-10-24 20:43:48.111] [CHAT] [INFO] ChatManager initialized with max 50 messages per session
|
||||
[2025-10-24 20:43:48.111] [INFO] McpServer initialized with centralized chat manager
|
||||
[2025-10-24 20:43:48.112] [TEST] This is a test log message to verify DebugLogger is working
|
||||
[2025-10-24 20:43:48.112] [INFO] === MCP SERVER STARTING ===
|
||||
[2025-10-24 20:43:48.112] [INFO] Starting HTTP server on port 3737...
|
||||
[2025-10-24 20:43:48.116] [INFO] MCP HTTP server running on http://127.0.0.1:3737/mcp
|
||||
[2025-10-24 20:43:48.823] [HTTP] GET /mcp
|
||||
[2025-10-24 20:43:48.823] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:48.824] [HTTP] Handling GET request to /mcp
|
||||
[2025-10-24 20:43:48.824] [HTTP] Setting up SSE stream for GET request
|
||||
[2025-10-24 20:43:48.824] [SSE] === SSE CONNECTION ATTEMPT ===
|
||||
[2025-10-24 20:43:48.824] [SSE] Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:48.824] [SSE] URL:
|
||||
"/mcp"
|
||||
[2025-10-24 20:43:48.824] [SSE] No sessionId in SSE request (tried URL param and Mcp-Session-Id header)
|
||||
[2025-10-24 20:43:48.824] [SSE] Request headers: {"host":"localhost:3737","connection":"keep-alive","sec-ch-ua-platform":"\"macOS\"","cache-control":"no-cache","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36","accept":"text/event-stream","sec-ch-ua":"\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"","sec-ch-ua-mobile":"?0","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"http://localhost:3737/HumanAgent","accept-encoding":"gzip, deflate, br, zstd","accept-language":"en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6","cookie":"csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"}
|
||||
[2025-10-24 20:43:48.824] [SSE] Request URL: /mcp
|
||||
[2025-10-24 20:43:48.824] [SSE] Using default sessionId: default-sse-session
|
||||
[2025-10-24 20:43:48.824] [SSE] SSE headers set for session default-sse-session, adding to connections...
|
||||
[2025-10-24 20:43:48.824] [HTTP] Added SSE connection for session default-sse-session. Total connections: 1
|
||||
[2025-10-24 20:43:48.824] [SSE] SSE connection added for session default-sse-session. Total: 1
|
||||
[2025-10-24 20:43:48.825] [SSE] Sent initial SSE message:
|
||||
"data: {\"type\":\"connection\",\"status\":\"established\",\"sessionId\":\"default-sse-session\"}"
|
||||
[2025-10-24 20:43:48.831] [HTTP] GET /sessions/session-a8f49eee-068c-42f1-b611-14651fa5ccc6/messages
|
||||
[2025-10-24 20:43:48.831] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"accept": "*/*",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:52.685] [HTTP] GET /HumanAgent
|
||||
[2025-10-24 20:43:52.685] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"cache-control": "max-age=0",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"sec-fetch-site": "none",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-user": "?1",
|
||||
"sec-fetch-dest": "document",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:52.686] [HTTP] Serving web interface at /HumanAgent
|
||||
[2025-10-24 20:43:52.691] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:52.691] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:52.691] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:52.691] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:52.696] [HTTP] GET /sessions//messages
|
||||
[2025-10-24 20:43:52.696] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"accept": "*/*",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:52.704] [HTTP] GET /mcp
|
||||
[2025-10-24 20:43:52.704] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:52.704] [HTTP] Handling GET request to /mcp
|
||||
[2025-10-24 20:43:52.704] [HTTP] Setting up SSE stream for GET request
|
||||
[2025-10-24 20:43:52.704] [SSE] === SSE CONNECTION ATTEMPT ===
|
||||
[2025-10-24 20:43:52.704] [SSE] Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:52.704] [SSE] URL:
|
||||
"/mcp"
|
||||
[2025-10-24 20:43:52.704] [SSE] No sessionId in SSE request (tried URL param and Mcp-Session-Id header)
|
||||
[2025-10-24 20:43:52.704] [SSE] Request headers: {"host":"localhost:3737","connection":"keep-alive","sec-ch-ua-platform":"\"macOS\"","cache-control":"no-cache","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36","accept":"text/event-stream","sec-ch-ua":"\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"","sec-ch-ua-mobile":"?0","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"http://localhost:3737/HumanAgent","accept-encoding":"gzip, deflate, br, zstd","accept-language":"en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6","cookie":"csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"}
|
||||
[2025-10-24 20:43:52.704] [SSE] Request URL: /mcp
|
||||
[2025-10-24 20:43:52.704] [SSE] Using default sessionId: default-sse-session
|
||||
[2025-10-24 20:43:52.704] [SSE] SSE headers set for session default-sse-session, adding to connections...
|
||||
[2025-10-24 20:43:52.704] [HTTP] Added SSE connection for session default-sse-session. Total connections: 1
|
||||
[2025-10-24 20:43:52.704] [SSE] SSE connection added for session default-sse-session. Total: 1
|
||||
[2025-10-24 20:43:52.705] [SSE] Sent initial SSE message:
|
||||
"data: {\"type\":\"connection\",\"status\":\"established\",\"sessionId\":\"default-sse-session\"}"
|
||||
[2025-10-24 20:43:53.571] [HTTP] GET /HumanAgent
|
||||
[2025-10-24 20:43:53.572] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"cache-control": "max-age=0",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"sec-fetch-site": "none",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-user": "?1",
|
||||
"sec-fetch-dest": "document",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:53.572] [HTTP] Serving web interface at /HumanAgent
|
||||
[2025-10-24 20:43:53.575] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:53.575] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:53.575] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:53.575] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:53.584] [HTTP] GET /sessions//messages
|
||||
[2025-10-24 20:43:53.584] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"accept": "*/*",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:53.592] [HTTP] GET /mcp
|
||||
[2025-10-24 20:43:53.592] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:53.592] [HTTP] Handling GET request to /mcp
|
||||
[2025-10-24 20:43:53.592] [HTTP] Setting up SSE stream for GET request
|
||||
[2025-10-24 20:43:53.592] [SSE] === SSE CONNECTION ATTEMPT ===
|
||||
[2025-10-24 20:43:53.592] [SSE] Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:53.592] [SSE] URL:
|
||||
"/mcp"
|
||||
[2025-10-24 20:43:53.593] [SSE] No sessionId in SSE request (tried URL param and Mcp-Session-Id header)
|
||||
[2025-10-24 20:43:53.593] [SSE] Request headers: {"host":"localhost:3737","connection":"keep-alive","sec-ch-ua-platform":"\"macOS\"","cache-control":"no-cache","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36","accept":"text/event-stream","sec-ch-ua":"\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"","sec-ch-ua-mobile":"?0","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"http://localhost:3737/HumanAgent","accept-encoding":"gzip, deflate, br, zstd","accept-language":"en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6","cookie":"csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"}
|
||||
[2025-10-24 20:43:53.593] [SSE] Request URL: /mcp
|
||||
[2025-10-24 20:43:53.593] [SSE] Using default sessionId: default-sse-session
|
||||
[2025-10-24 20:43:53.593] [SSE] SSE headers set for session default-sse-session, adding to connections...
|
||||
[2025-10-24 20:43:53.593] [HTTP] Added SSE connection for session default-sse-session. Total connections: 1
|
||||
[2025-10-24 20:43:53.593] [SSE] SSE connection added for session default-sse-session. Total: 1
|
||||
[2025-10-24 20:43:53.593] [SSE] Sent initial SSE message:
|
||||
"data: {\"type\":\"connection\",\"status\":\"established\",\"sessionId\":\"default-sse-session\"}"
|
||||
[2025-10-24 20:43:54.386] [HTTP] GET /HumanAgent
|
||||
[2025-10-24 20:43:54.386] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"cache-control": "max-age=0",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"sec-fetch-site": "none",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-user": "?1",
|
||||
"sec-fetch-dest": "document",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:54.386] [HTTP] Serving web interface at /HumanAgent
|
||||
[2025-10-24 20:43:54.390] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:54.390] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:54.390] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:54.390] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:54.401] [HTTP] GET /sessions//messages
|
||||
[2025-10-24 20:43:54.401] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"accept": "*/*",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:54.407] [HTTP] GET /mcp
|
||||
[2025-10-24 20:43:54.407] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:54.407] [HTTP] Handling GET request to /mcp
|
||||
[2025-10-24 20:43:54.407] [HTTP] Setting up SSE stream for GET request
|
||||
[2025-10-24 20:43:54.407] [SSE] === SSE CONNECTION ATTEMPT ===
|
||||
[2025-10-24 20:43:54.407] [SSE] Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:54.407] [SSE] URL:
|
||||
"/mcp"
|
||||
[2025-10-24 20:43:54.407] [SSE] No sessionId in SSE request (tried URL param and Mcp-Session-Id header)
|
||||
[2025-10-24 20:43:54.407] [SSE] Request headers: {"host":"localhost:3737","connection":"keep-alive","sec-ch-ua-platform":"\"macOS\"","cache-control":"no-cache","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36","accept":"text/event-stream","sec-ch-ua":"\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"","sec-ch-ua-mobile":"?0","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"http://localhost:3737/HumanAgent","accept-encoding":"gzip, deflate, br, zstd","accept-language":"en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6","cookie":"csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"}
|
||||
[2025-10-24 20:43:54.407] [SSE] Request URL: /mcp
|
||||
[2025-10-24 20:43:54.407] [SSE] Using default sessionId: default-sse-session
|
||||
[2025-10-24 20:43:54.407] [SSE] SSE headers set for session default-sse-session, adding to connections...
|
||||
[2025-10-24 20:43:54.407] [HTTP] Added SSE connection for session default-sse-session. Total connections: 1
|
||||
[2025-10-24 20:43:54.407] [SSE] SSE connection added for session default-sse-session. Total: 1
|
||||
[2025-10-24 20:43:54.407] [SSE] Sent initial SSE message:
|
||||
"data: {\"type\":\"connection\",\"status\":\"established\",\"sessionId\":\"default-sse-session\"}"
|
||||
[2025-10-24 20:43:56.550] [HTTP] GET /HumanAgent
|
||||
[2025-10-24 20:43:56.550] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"cache-control": "max-age=0",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"sec-fetch-site": "none",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-user": "?1",
|
||||
"sec-fetch-dest": "document",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:56.550] [HTTP] Serving web interface at /HumanAgent
|
||||
[2025-10-24 20:43:56.557] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:56.557] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:56.557] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:56.557] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:56.565] [HTTP] GET /sessions//messages
|
||||
[2025-10-24 20:43:56.565] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"accept": "*/*",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:56.568] [HTTP] GET /mcp
|
||||
[2025-10-24 20:43:56.568] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:56.568] [HTTP] Handling GET request to /mcp
|
||||
[2025-10-24 20:43:56.568] [HTTP] Setting up SSE stream for GET request
|
||||
[2025-10-24 20:43:56.568] [SSE] === SSE CONNECTION ATTEMPT ===
|
||||
[2025-10-24 20:43:56.568] [SSE] Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:56.568] [SSE] URL:
|
||||
"/mcp"
|
||||
[2025-10-24 20:43:56.568] [SSE] No sessionId in SSE request (tried URL param and Mcp-Session-Id header)
|
||||
[2025-10-24 20:43:56.568] [SSE] Request headers: {"host":"localhost:3737","connection":"keep-alive","sec-ch-ua-platform":"\"macOS\"","cache-control":"no-cache","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36","accept":"text/event-stream","sec-ch-ua":"\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"","sec-ch-ua-mobile":"?0","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"http://localhost:3737/HumanAgent","accept-encoding":"gzip, deflate, br, zstd","accept-language":"en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6","cookie":"csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"}
|
||||
[2025-10-24 20:43:56.568] [SSE] Request URL: /mcp
|
||||
[2025-10-24 20:43:56.568] [SSE] Using default sessionId: default-sse-session
|
||||
[2025-10-24 20:43:56.568] [SSE] SSE headers set for session default-sse-session, adding to connections...
|
||||
[2025-10-24 20:43:56.568] [HTTP] Added SSE connection for session default-sse-session. Total connections: 1
|
||||
[2025-10-24 20:43:56.568] [SSE] SSE connection added for session default-sse-session. Total: 1
|
||||
[2025-10-24 20:43:56.568] [SSE] Sent initial SSE message:
|
||||
"data: {\"type\":\"connection\",\"status\":\"established\",\"sessionId\":\"default-sse-session\"}"
|
||||
[2025-10-24 20:43:58.232] [HTTP] GET /HumanAgent
|
||||
[2025-10-24 20:43:58.232] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"cache-control": "max-age=0",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"sec-fetch-site": "none",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-user": "?1",
|
||||
"sec-fetch-dest": "document",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:58.233] [HTTP] Serving web interface at /HumanAgent
|
||||
[2025-10-24 20:43:58.237] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:58.238] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:58.238] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:58.238] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:58.246] [HTTP] GET /sessions//messages
|
||||
[2025-10-24 20:43:58.246] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"accept": "*/*",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:58.250] [HTTP] GET /mcp
|
||||
[2025-10-24 20:43:58.250] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:58.250] [HTTP] Handling GET request to /mcp
|
||||
[2025-10-24 20:43:58.250] [HTTP] Setting up SSE stream for GET request
|
||||
[2025-10-24 20:43:58.250] [SSE] === SSE CONNECTION ATTEMPT ===
|
||||
[2025-10-24 20:43:58.250] [SSE] Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:58.250] [SSE] URL:
|
||||
"/mcp"
|
||||
[2025-10-24 20:43:58.250] [SSE] No sessionId in SSE request (tried URL param and Mcp-Session-Id header)
|
||||
[2025-10-24 20:43:58.250] [SSE] Request headers: {"host":"localhost:3737","connection":"keep-alive","sec-ch-ua-platform":"\"macOS\"","cache-control":"no-cache","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36","accept":"text/event-stream","sec-ch-ua":"\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"","sec-ch-ua-mobile":"?0","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"http://localhost:3737/HumanAgent","accept-encoding":"gzip, deflate, br, zstd","accept-language":"en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6","cookie":"csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"}
|
||||
[2025-10-24 20:43:58.250] [SSE] Request URL: /mcp
|
||||
[2025-10-24 20:43:58.250] [SSE] Using default sessionId: default-sse-session
|
||||
[2025-10-24 20:43:58.250] [SSE] SSE headers set for session default-sse-session, adding to connections...
|
||||
[2025-10-24 20:43:58.250] [HTTP] Added SSE connection for session default-sse-session. Total connections: 1
|
||||
[2025-10-24 20:43:58.250] [SSE] SSE connection added for session default-sse-session. Total: 1
|
||||
[2025-10-24 20:43:58.250] [SSE] Sent initial SSE message:
|
||||
"data: {\"type\":\"connection\",\"status\":\"established\",\"sessionId\":\"default-sse-session\"}"
|
||||
[2025-10-24 20:43:58.406] [HTTP] GET /HumanAgent
|
||||
[2025-10-24 20:43:58.406] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"cache-control": "max-age=0",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"sec-fetch-site": "none",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-user": "?1",
|
||||
"sec-fetch-dest": "document",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:58.406] [HTTP] Serving web interface at /HumanAgent
|
||||
[2025-10-24 20:43:58.411] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:58.411] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:58.411] [HTTP] SSE connection closed for session default-sse-session
|
||||
[2025-10-24 20:43:58.411] [HTTP] Removed SSE connection for session default-sse-session. Total connections: 0
|
||||
[2025-10-24 20:43:58.420] [HTTP] GET /sessions//messages
|
||||
[2025-10-24 20:43:58.420] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"accept": "*/*",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:58.425] [HTTP] GET /mcp
|
||||
[2025-10-24 20:43:58.425] [HTTP] Request Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:58.425] [HTTP] Handling GET request to /mcp
|
||||
[2025-10-24 20:43:58.425] [HTTP] Setting up SSE stream for GET request
|
||||
[2025-10-24 20:43:58.425] [SSE] === SSE CONNECTION ATTEMPT ===
|
||||
[2025-10-24 20:43:58.425] [SSE] Headers:
|
||||
{
|
||||
"host": "localhost:3737",
|
||||
"connection": "keep-alive",
|
||||
"sec-ch-ua-platform": "\"macOS\"",
|
||||
"cache-control": "no-cache",
|
||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
|
||||
"accept": "text/event-stream",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-dest": "empty",
|
||||
"referer": "http://localhost:3737/HumanAgent",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6",
|
||||
"cookie": "csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"
|
||||
}
|
||||
[2025-10-24 20:43:58.425] [SSE] URL:
|
||||
"/mcp"
|
||||
[2025-10-24 20:43:58.425] [SSE] No sessionId in SSE request (tried URL param and Mcp-Session-Id header)
|
||||
[2025-10-24 20:43:58.425] [SSE] Request headers: {"host":"localhost:3737","connection":"keep-alive","sec-ch-ua-platform":"\"macOS\"","cache-control":"no-cache","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36","accept":"text/event-stream","sec-ch-ua":"\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"","sec-ch-ua-mobile":"?0","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"http://localhost:3737/HumanAgent","accept-encoding":"gzip, deflate, br, zstd","accept-language":"en,en-US;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6","cookie":"csrftoken=ZAgfvccRW3GTeUh5I2OhLyXWqlCkYBLh"}
|
||||
[2025-10-24 20:43:58.425] [SSE] Request URL: /mcp
|
||||
[2025-10-24 20:43:58.425] [SSE] Using default sessionId: default-sse-session
|
||||
[2025-10-24 20:43:58.425] [SSE] SSE headers set for session default-sse-session, adding to connections...
|
||||
[2025-10-24 20:43:58.425] [HTTP] Added SSE connection for session default-sse-session. Total connections: 1
|
||||
[2025-10-24 20:43:58.425] [SSE] SSE connection added for session default-sse-session. Total: 1
|
||||
[2025-10-24 20:43:58.425] [SSE] Sent initial SSE message:
|
||||
"data: {\"type\":\"connection\",\"status\":\"established\",\"sessionId\":\"default-sse-session\"}"
|
||||
Vendored
-8
@@ -10,14 +10,6 @@
|
||||
"6000"
|
||||
],
|
||||
"env": {}
|
||||
},
|
||||
"humanagent-mcp": {
|
||||
"type": "http",
|
||||
"url": "http://127.0.0.1:3737/mcp?sessionId=session-a8f49eee-068c-42f1-b611-14651fa5ccc6",
|
||||
"notifications": {
|
||||
"enableSound": true,
|
||||
"enableFlashing": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": []
|
||||
|
||||
@@ -1,314 +0,0 @@
|
||||
# HumanAgent MCP - VS Code Extension
|
||||
|
||||
# HumanAgent MCP
|
||||
|
||||
A VS Code extension that enables AI agents to communicate directly with developers through an integrated chat interface. Built on the Model Context Protocol (MCP) standard.
|
||||
|
||||
## What it does
|
||||
|
||||
When AI assistants like Claude or Cursor need clarification, approval, or input from you, they can use the HumanAgent_Chat tool to send messages directly to your VS Code interface. You see their questions in real-time and can respond immediately, creating a seamless collaborative workflow.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Open VS Code
|
||||
2. Install the HumanAgent MCP extension from the marketplace
|
||||
3. The extension automatically starts an MCP server on port 3737
|
||||
4. Configure your AI assistant to use the MCP server at `http://127.0.0.1:3737/mcp`
|
||||
|
||||
## Usage
|
||||
|
||||
### VS Code Interface
|
||||
|
||||
After installation, you'll see:
|
||||
- **Chat Sessions** view in the Explorer panel showing active conversations
|
||||
- **HumanAgent Chat** panel (dockable) for the main chat interface
|
||||
- Audio notifications when new messages arrive (configurable)
|
||||
|
||||
### Basic Workflow
|
||||
|
||||
1. AI assistant calls the `HumanAgent_Chat` tool when it needs human input
|
||||
2. Message appears in your VS Code chat interface with optional sound notification
|
||||
3. You respond through the chat interface
|
||||
4. AI assistant receives your response and continues working
|
||||
|
||||
### Commands
|
||||
|
||||
- **Create New Chat Session** - Start a fresh conversation
|
||||
- **Configure MCP Server** - Set up workspace or global MCP registration
|
||||
- **Show Status** - View server status and active sessions
|
||||
|
||||
## Configuration
|
||||
|
||||
### MCP Server Registration
|
||||
|
||||
The extension can register the MCP server in two ways:
|
||||
|
||||
**Workspace Registration** (Recommended)
|
||||
- Creates `.vscode/mcp.json` in your current workspace
|
||||
- Server only available to this workspace
|
||||
- Automatic session management per workspace
|
||||
|
||||
**Global Registration**
|
||||
- Registers in VS Code's global MCP settings
|
||||
- Available to all workspaces
|
||||
- Manual session management
|
||||
|
||||
### Settings
|
||||
|
||||
Access via VS Code Settings (search for "HumanAgent"):
|
||||
|
||||
- `humanagent-mcp.logging.enabled` - Enable debug logging to `.vscode` directory (default: false)
|
||||
- `humanagent-mcp.logging.level` - Log level: ERROR, WARN, INFO, DEBUG (default: INFO)
|
||||
|
||||
### Tool Customization
|
||||
|
||||
Create `.vscode/override-prompt.md` in your workspace to customize how the AI tool behaves:
|
||||
|
||||
```markdown
|
||||
# Custom HumanAgent_Chat Tool
|
||||
|
||||
## Description
|
||||
Your custom description here
|
||||
|
||||
## Properties
|
||||
- message: Custom message field description
|
||||
- timeout: Response timeout in seconds (optional)
|
||||
```
|
||||
|
||||
## Web Interface
|
||||
|
||||
Access the web interface at `http://127.0.0.1:3737/` to:
|
||||
- View chat sessions from any browser
|
||||
- Send messages from outside VS Code
|
||||
- Monitor active conversations
|
||||
|
||||
## Requirements
|
||||
|
||||
- VS Code 1.105.0 or higher
|
||||
- Network access to localhost port 3737
|
||||
- AI assistant configured to use MCP (Claude, Cursor, etc.)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Extension not starting**
|
||||
- Check VS Code Developer Console for errors
|
||||
- Verify port 3737 is not in use by another application
|
||||
|
||||
**AI can't connect**
|
||||
- Ensure MCP server is registered (use Configure MCP Server command)
|
||||
- Check the server URL includes your session ID: `http://127.0.0.1:3737/mcp?sessionId=your-session-id`
|
||||
|
||||
**No audio notifications**
|
||||
- Check VS Code notification settings
|
||||
- Test notifications using the Configure panel
|
||||
|
||||
**Messages not appearing**
|
||||
- Refresh the Chat Sessions view
|
||||
- Check server status in the HumanAgent Chat panel
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
## Features
|
||||
|
||||
- ** AI-to-Human Communication**: AI agents can send messages and questions directly to developers
|
||||
- ** VS Code Chat Interface**: Dockable chat panel integrated into VS Code
|
||||
- ** Session Management**: Each workspace gets its own communication session
|
||||
- ** Workspace Tool Overrides**: Customize MCP tool behavior per workspace
|
||||
- ** Audio Notifications**: Optional sound alerts for new AI messages
|
||||
- ** Status Monitoring**: Track server status and pending requests
|
||||
- ** HTTP + Stdio Support**: Compatible with various MCP clients
|
||||
|
||||
## Installation
|
||||
|
||||
### VS Code Marketplace (Recommended)
|
||||
|
||||
1. Open VS Code
|
||||
2. Go to Extensions (`Ctrl+Shift+X` or `Cmd+Shift+X`)
|
||||
3. Search for "HumanAgent MCP"
|
||||
4. Click **Install**
|
||||
5. The extension will auto-configure and start working
|
||||
|
||||
### Manual Installation
|
||||
|
||||
Download the `.vsix` file from releases and install:
|
||||
```bash
|
||||
code --install-extension humanagent-mcp-*.vsix
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. **Install the extension** in VS Code
|
||||
2. **Open any workspace** - the extension auto-starts
|
||||
3. **Open the HumanAgent Chat** panel (View → HumanAgent MCP Chat)
|
||||
4. **AI agents can immediately send messages** that appear in your chat interface
|
||||
|
||||
The extension automatically:
|
||||
- ✅ Configures MCP server settings
|
||||
- ✅ Starts HTTP server on port 3737
|
||||
- ✅ Registers with VS Code's MCP system
|
||||
- ✅ Creates workspace-specific session
|
||||
|
||||
## How It Works
|
||||
|
||||
The extension automatically:
|
||||
- ✅ Starts an MCP server on `http://127.0.0.1:3737/mcp`
|
||||
- ✅ Configures itself within VS Code's extension system
|
||||
- ✅ Provides the `HumanAgent_Chat` tool for AI agents
|
||||
- ✅ Creates a chat interface for receiving AI messages
|
||||
|
||||
**For AI agents:** Use the MCP tool `HumanAgent_Chat` to send messages to the human developer. Messages appear instantly in the VS Code chat panel.
|
||||
|
||||
## Tool Customization
|
||||
|
||||
Create a `.vscode/HumanAgentOverride.json` file in your workspace to customize tool behavior:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"description": "Custom HumanAgent tools for this workspace",
|
||||
"tools": {
|
||||
"HumanAgent_Chat": {
|
||||
"name": "HumanAgent_Chat",
|
||||
"description": "Custom description for this workspace's chat tool",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "The message to send"
|
||||
},
|
||||
"context": {
|
||||
"type": "string",
|
||||
"description": "Optional context"
|
||||
},
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"enum": ["low", "normal", "high", "urgent"],
|
||||
"default": "normal"
|
||||
}
|
||||
},
|
||||
"required": ["message"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use the **🔄 Reload Override File** option in the chat panel's cog menu to apply changes.
|
||||
|
||||
## Available Commands
|
||||
|
||||
- **Create Session**: Initialize a new chat session
|
||||
- **Show Status**: Display server status and statistics
|
||||
- **Configure MCP**: Set up MCP server registration
|
||||
- **Override Prompt**: Create workspace-specific tool configurations
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
||||
│ MCP Client │ │ HumanAgent MCP │ │ VS Code UI │
|
||||
│ (Claude/Cursor) │◄──►│ Server │◄──►│ Chat Interface │
|
||||
│ │ │ (Port 3737) │ │ │
|
||||
└─────────────────┘ └──────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Development Installation
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd humanagent-mcp
|
||||
npm install
|
||||
npm run compile
|
||||
```
|
||||
|
||||
Press `F5` in VS Code to launch the Extension Development Host.
|
||||
|
||||
### Project Structure
|
||||
```
|
||||
src/
|
||||
├── extension.ts # VS Code extension entry point
|
||||
├── mcp/
|
||||
│ ├── server.ts # MCP HTTP server implementation
|
||||
│ ├── mcpStandalone.js # Standalone server runner
|
||||
│ └── types.ts # TypeScript definitions
|
||||
├── webview/
|
||||
│ └── chatWebviewProvider.ts # Chat UI implementation
|
||||
└── providers/
|
||||
└── chatTreeProvider.ts # Session tree view
|
||||
```
|
||||
|
||||
### Build Commands
|
||||
```bash
|
||||
npm run compile # TypeScript compilation
|
||||
npm run watch # Watch mode for development
|
||||
npm run package # Production build
|
||||
```
|
||||
|
||||
### Testing
|
||||
```bash
|
||||
# Test MCP server directly
|
||||
curl -X POST http://localhost:3737/mcp \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"id":"test","type":"request","method":"tools/list"}'
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
- **Development**: Logs appear in VS Code Developer Console
|
||||
- **Production**: Logs saved to `.vscode/HumanAgent.log` in each workspace
|
||||
- **Standalone**: Logs saved to system temp directory
|
||||
|
||||
## Technical Details
|
||||
|
||||
### MCP Protocol Support
|
||||
- **Protocol Version**: 2024-11-05
|
||||
- **Transport**: HTTP (primary), Stdio (compatibility)
|
||||
- **Tools**: `HumanAgent_Chat` with workspace customization
|
||||
- **Session Management**: Isolated per workspace
|
||||
|
||||
### Security Considerations
|
||||
- HTTP server binds to localhost only (127.0.0.1)
|
||||
- No external network access required
|
||||
- Workspace-specific tool isolation
|
||||
|
||||
## Limitations
|
||||
|
||||
- Requires VS Code to be running for AI communication
|
||||
- HTTP server uses fixed port 3737 (configurable in code)
|
||||
- Tool overrides require manual reload after changes
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Server not starting?**
|
||||
- Check port 3737 is available: `lsof -i :3737`
|
||||
- Verify workspace has write permissions for `.vscode/` directory
|
||||
|
||||
**AI messages not appearing?**
|
||||
- Confirm MCP client is connected to `http://127.0.0.1:3737/mcp`
|
||||
- Check HumanAgent Chat panel is open in VS Code
|
||||
- Review logs in `.vscode/HumanAgent.log`
|
||||
|
||||
**Override file not working?**
|
||||
- Validate JSON syntax in HumanAgentOverride.json
|
||||
- Use "🔄 Reload Override File" to apply changes
|
||||
- Check Developer Console for error messages
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](LICENSE) file for details.
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Make your changes with tests
|
||||
4. Submit a pull request
|
||||
|
||||
---
|
||||
|
||||
**Built for seamless AI-human collaboration in VS Code** 🚀
|
||||
-330
@@ -1,330 +0,0 @@
|
||||
# HumanAgent MCP - Developer Documentation
|
||||
|
||||
Technical documentation for developers working on or extending the HumanAgent MCP extension.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Components
|
||||
|
||||
**Extension Entry Point** (`src/extension.ts`)
|
||||
- VS Code extension activation and lifecycle
|
||||
- MCP server definition provider for VS Code native integration
|
||||
- Session management and workspace detection
|
||||
- Command registration and event handling
|
||||
|
||||
**MCP Server** (`src/mcp/server.ts`)
|
||||
- HTTP server on port 3737 serving MCP protocol
|
||||
- Tool definitions and execution (HumanAgent_Chat)
|
||||
- Session-specific tool overrides
|
||||
- SSE connections for real-time updates
|
||||
- Web interface generation
|
||||
|
||||
**Chat Manager** (`src/mcp/chatManager.ts`)
|
||||
- Centralized message and session storage
|
||||
- Request/response correlation
|
||||
- Session cleanup and memory management
|
||||
|
||||
**Webview Provider** (`src/webview/chatWebviewProvider.ts`)
|
||||
- VS Code webview integration
|
||||
- Chat interface UI and messaging
|
||||
- Server configuration and status monitoring
|
||||
|
||||
**Configuration Manager** (`src/mcp/mcpConfigManager.ts`)
|
||||
- MCP server registration (workspace/global)
|
||||
- Configuration file management (.vscode/mcp.json)
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
AI Client -> MCP Server (port 3737) -> ChatManager -> Webview Provider -> VS Code UI
|
||||
-> SSE Client -> Web Interface
|
||||
```
|
||||
|
||||
## Key Features Implementation
|
||||
|
||||
### Session Management
|
||||
|
||||
Each workspace gets a unique session ID based on workspace path hash. Session data includes:
|
||||
- Chat message history (managed by ChatManager)
|
||||
- Pending requests awaiting human response
|
||||
- Tool overrides loaded from `.vscode/override-prompt.md`
|
||||
- Workspace-specific configuration
|
||||
|
||||
### Tool Override System
|
||||
|
||||
1. Default `HumanAgent_Chat` tool defined in `server.ts`
|
||||
2. Per-workspace overrides loaded from `.vscode/override-prompt.md`
|
||||
3. Markdown parsed to extract tool description and schema modifications
|
||||
4. Session-specific tool maps maintain overrides per workspace
|
||||
|
||||
### Real-time Communication
|
||||
|
||||
- **MCP Protocol**: Standard JSON-RPC over HTTP for AI client communication
|
||||
- **SSE (Server-Sent Events)**: Real-time updates to webview and web interface
|
||||
- **VS Code Events**: Native VS Code messaging for webview updates
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js 18+
|
||||
- VS Code 1.105.0+
|
||||
- TypeScript knowledge
|
||||
|
||||
### Build Process
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Development build with watch
|
||||
npm run watch
|
||||
|
||||
# Production build
|
||||
npm run package
|
||||
|
||||
# Compile extension only
|
||||
npm run compile
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── extension.ts # Extension entry point
|
||||
├── mcp/
|
||||
│ ├── server.ts # MCP server implementation
|
||||
│ ├── chatManager.ts # Session and message management
|
||||
│ ├── mcpConfigManager.ts # Configuration handling
|
||||
│ ├── types.ts # TypeScript interfaces
|
||||
│ └── mcpStandalone.ts # Standalone server entry
|
||||
├── webview/
|
||||
│ └── chatWebviewProvider.ts # VS Code webview integration
|
||||
├── providers/
|
||||
│ └── chatTreeProvider.ts # Explorer tree view
|
||||
├── audio/
|
||||
│ └── audioNotification.ts # Sound notifications
|
||||
└── serverManager.ts # Server lifecycle management
|
||||
```
|
||||
|
||||
### Key Classes
|
||||
|
||||
**McpServer**
|
||||
- Main server class implementing MCP protocol
|
||||
- Tool registration and execution
|
||||
- HTTP request handling and routing
|
||||
- SSE connection management
|
||||
|
||||
**ChatManager**
|
||||
- Message storage and retrieval
|
||||
- Pending request tracking
|
||||
- Session lifecycle management
|
||||
- Memory cleanup and limits
|
||||
|
||||
**ChatWebviewProvider**
|
||||
- VS Code webview implementation
|
||||
- Chat UI rendering and interaction
|
||||
- Server status monitoring
|
||||
- Configuration management
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### Extension Manifest (`package.json`)
|
||||
|
||||
Key sections:
|
||||
- `contributes.commands` - VS Code commands
|
||||
- `contributes.views` - Panel and tree view definitions
|
||||
- `contributes.configuration` - User settings schema
|
||||
- `contributes.mcpServerDefinitionProviders` - VS Code MCP integration
|
||||
|
||||
### Workspace Configuration (`.vscode/mcp.json`)
|
||||
|
||||
Generated automatically when registering workspace MCP server:
|
||||
|
||||
```json
|
||||
{
|
||||
"servers": {
|
||||
"humanagent-mcp": {
|
||||
"type": "http",
|
||||
"url": "http://127.0.0.1:3737/mcp?sessionId=session-xxx",
|
||||
"notifications": {
|
||||
"enableSound": true,
|
||||
"enableFlashing": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Tool Override (`.vscode/override-prompt.md`)
|
||||
|
||||
Markdown file for customizing tool behavior per workspace. Parsed sections:
|
||||
- Description becomes tool description
|
||||
- Properties section modifies input schema
|
||||
- Additional context included in tool execution
|
||||
|
||||
## API Endpoints
|
||||
|
||||
The MCP server exposes both MCP protocol and web endpoints:
|
||||
|
||||
### MCP Protocol (`/mcp`)
|
||||
|
||||
Standard MCP JSON-RPC methods:
|
||||
- `initialize` - Client initialization
|
||||
- `tools/list` - Available tools query
|
||||
- `tools/call` - Tool execution (HumanAgent_Chat)
|
||||
|
||||
### Web Endpoints
|
||||
|
||||
- `GET /` - Web chat interface
|
||||
- `GET /sessions` - Session list API
|
||||
- `POST /send-message` - Web message sending
|
||||
- `GET /sse/{sessionId}` - Server-sent events connection
|
||||
|
||||
## Testing
|
||||
|
||||
### Extension Testing
|
||||
|
||||
```bash
|
||||
# Run in extension development host
|
||||
# Press F5 in VS Code to launch debug instance
|
||||
```
|
||||
|
||||
### MCP Server Testing
|
||||
|
||||
```bash
|
||||
# Test server independently
|
||||
node dist/mcpStandalone.js
|
||||
curl http://127.0.0.1:3737/sessions
|
||||
```
|
||||
|
||||
### Integration Testing
|
||||
|
||||
Test AI client integration by configuring Claude/Cursor with:
|
||||
```
|
||||
http://127.0.0.1:3737/mcp?sessionId=test-session
|
||||
```
|
||||
|
||||
## Logging and Debugging
|
||||
|
||||
### Extension Logs
|
||||
|
||||
Enable debug logging via settings:
|
||||
- `humanagent-mcp.logging.enabled` = true
|
||||
- `humanagent-mcp.logging.level` = "DEBUG"
|
||||
|
||||
Logs written to `.vscode/HumanAgent-server.log` in workspace.
|
||||
|
||||
### VS Code Debug Console
|
||||
|
||||
View extension debug output:
|
||||
1. Help > Toggle Developer Tools
|
||||
2. Console tab shows extension logs
|
||||
|
||||
### Server Debug Mode
|
||||
|
||||
Environment variables for standalone server:
|
||||
```bash
|
||||
HUMANAGENT_LOGGING_ENABLED=true
|
||||
HUMANAGENT_LOGGING_LEVEL=DEBUG
|
||||
node dist/mcpStandalone.js
|
||||
```
|
||||
|
||||
## Extension Points
|
||||
|
||||
### Adding New Tools
|
||||
|
||||
1. Define tool in `initializeDefaultTools()` method
|
||||
2. Add handler in `handleToolCall()` method
|
||||
3. Update tool override parsing if needed
|
||||
|
||||
### Custom Notification Types
|
||||
|
||||
1. Add new SSE message types in `sendMcpNotification()`
|
||||
2. Handle in webview JavaScript
|
||||
3. Update UI accordingly
|
||||
|
||||
### Additional Configuration
|
||||
|
||||
1. Add to `package.json` contributes.configuration
|
||||
2. Read settings in extension code
|
||||
3. Pass to server during initialization
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Async Request Handling
|
||||
|
||||
```typescript
|
||||
// Store request resolver
|
||||
this.requestResolvers.set(requestId, {
|
||||
resolve: (response: string) => {
|
||||
// Handle response
|
||||
},
|
||||
reject: (error: Error) => {
|
||||
// Handle error
|
||||
}
|
||||
});
|
||||
|
||||
// Set timeout if needed
|
||||
if (timeoutMs) {
|
||||
setTimeout(() => {
|
||||
// Timeout logic
|
||||
}, timeoutMs);
|
||||
}
|
||||
```
|
||||
|
||||
### Session-Specific Operations
|
||||
|
||||
```typescript
|
||||
// Get session tools
|
||||
const sessionTools = this.sessionTools.get(sessionId) || this.tools;
|
||||
|
||||
// Store session data
|
||||
this.sessionData.set(sessionId, data);
|
||||
|
||||
// Clean up session
|
||||
this.activeSessions.delete(sessionId);
|
||||
```
|
||||
|
||||
### Webview Communication
|
||||
|
||||
```typescript
|
||||
// Send to webview
|
||||
this._view.webview.postMessage({
|
||||
type: 'messageType',
|
||||
data: payload
|
||||
});
|
||||
|
||||
// Handle webview messages
|
||||
webview.onDidReceiveMessage(message => {
|
||||
switch (message.type) {
|
||||
case 'actionType':
|
||||
// Handle action
|
||||
break;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Build and Packaging
|
||||
|
||||
### Development Build
|
||||
|
||||
```bash
|
||||
npm run compile
|
||||
```
|
||||
|
||||
### Production Package
|
||||
|
||||
```bash
|
||||
npm run package
|
||||
```
|
||||
|
||||
This creates `dist/extension.js` and `dist/mcpStandalone.js` for distribution.
|
||||
|
||||
### Extension Packaging
|
||||
|
||||
```bash
|
||||
vsce package
|
||||
```
|
||||
|
||||
Creates `.vsix` file for manual installation or marketplace publishing.
|
||||
@@ -127,6 +127,16 @@
|
||||
"enum": ["ERROR", "WARN", "INFO", "DEBUG"],
|
||||
"default": "INFO",
|
||||
"description": "Set the logging level for HumanAgent MCP server"
|
||||
},
|
||||
"humanagent-mcp.notifications.enableSound": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable audio notifications when AI agents send messages"
|
||||
},
|
||||
"humanagent-mcp.notifications.enableFlashing": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable visual flashing notifications when AI agents send messages"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,3 +7,42 @@
|
||||
2025-10-24T09:36:01.128Z - RESPONSE ENDPOINT CALLED - RequestID: 10-1761298555386
|
||||
2025-10-24T09:36:37.205Z - RESPONSE ENDPOINT CALLED - RequestID: 11-1761298573778
|
||||
2025-10-25T00:51:00.473Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761353445662
|
||||
2025-10-25T04:01:02.918Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761364822234
|
||||
2025-10-25T04:15:25.912Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1761365673152
|
||||
2025-10-25T05:11:52.195Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761369085275
|
||||
2025-10-25T05:13:08.587Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1761369125738
|
||||
2025-10-25T05:13:46.757Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1761369196447
|
||||
2025-10-25T05:14:13.224Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1761369242206
|
||||
2025-10-25T05:14:37.881Z - RESPONSE ENDPOINT CALLED - RequestID: 7-1761369262103
|
||||
2025-10-25T05:15:07.921Z - RESPONSE ENDPOINT CALLED - RequestID: 8-1761369292715
|
||||
2025-10-25T05:16:21.162Z - RESPONSE ENDPOINT CALLED - RequestID: 9-1761369320152
|
||||
2025-10-25T05:16:54.687Z - RESPONSE ENDPOINT CALLED - RequestID: 10-1761369392733
|
||||
2025-10-25T05:18:12.537Z - RESPONSE ENDPOINT CALLED - RequestID: 11-1761369434229
|
||||
2025-10-25T05:31:53.635Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761370255763
|
||||
2025-10-25T22:25:03.252Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761430956625
|
||||
2025-10-25T23:25:06.434Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761433618081
|
||||
2025-10-25T23:51:51.036Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761436271152
|
||||
2025-10-26T00:10:24.529Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761437390231
|
||||
2025-10-26T00:50:40.987Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761439764111
|
||||
2025-10-26T02:36:30.812Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761446137388
|
||||
2025-10-26T02:36:46.213Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1761446194329
|
||||
2025-10-26T02:37:06.823Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1761446210035
|
||||
2025-10-26T02:39:35.845Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761446268480
|
||||
2025-10-26T02:52:49.230Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761447129937
|
||||
2025-10-26T02:58:10.739Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1761447173815
|
||||
2025-10-26T02:58:23.071Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1761446231600
|
||||
2025-10-26T03:12:51.723Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761448352577
|
||||
2025-10-26T03:13:06.068Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1761448377257
|
||||
2025-10-26T03:14:30.027Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1761448389577
|
||||
2025-10-26T03:27:07.019Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761449187260
|
||||
2025-10-26T03:28:01.453Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1761449230412
|
||||
2025-10-26T04:12:40.297Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761451913551
|
||||
2025-10-26T04:32:38.258Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761453136803
|
||||
2025-10-26T04:33:24.748Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1761453160409
|
||||
2025-10-26T04:34:19.385Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1761453244838
|
||||
2025-10-26T04:34:47.275Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1761453207008
|
||||
2025-10-26T04:35:07.379Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1761453290240
|
||||
2025-10-26T04:35:22.313Z - RESPONSE ENDPOINT CALLED - RequestID: 7-1761453309691
|
||||
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
|
||||
|
||||
+133
-120
@@ -21,10 +21,11 @@ class HumanAgentMcpProvider implements vscode.McpServerDefinitionProvider {
|
||||
constructor(private sessionId: string) {}
|
||||
|
||||
provideMcpServerDefinitions(token: vscode.CancellationToken): vscode.ProviderResult<vscode.McpHttpServerDefinition[]> {
|
||||
// Return our HumanAgent MCP server definition with current sessionId
|
||||
const serverUrl = `http://127.0.0.1:3737/mcp?sessionId=${this.sessionId}`;
|
||||
// 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');
|
||||
return [server];
|
||||
}
|
||||
|
||||
@@ -144,8 +145,8 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
serverManager = ServerManager.getInstance(serverOptions);
|
||||
|
||||
// Auto-detect and start standalone MCP server if already configured
|
||||
await autoStartMcpServer(mcpConfigManager, workspaceSessionId);
|
||||
// Auto-start server and register session (no mcp.json dependency)
|
||||
await ensureServerAndRegisterSession(workspaceSessionId);
|
||||
|
||||
// Restore the persisted session name after server is running (with retry)
|
||||
setTimeout(async () => {
|
||||
@@ -191,9 +192,6 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// Create dedicated status command
|
||||
const showStatusCommand = vscode.commands.registerCommand('humanagent-mcp.showStatus', async () => {
|
||||
const isWorkspaceRegistered = mcpConfigManager?.isMcpServerRegistered(false) ?? false;
|
||||
const isGlobalRegistered = mcpConfigManager?.isMcpServerRegistered(true) ?? false;
|
||||
|
||||
// Get detailed server status
|
||||
const serverStatus = await serverManager.getServerStatus();
|
||||
|
||||
@@ -204,8 +202,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
`- Port: ${serverStatus.port}\n` +
|
||||
`- Host: ${serverStatus.host}\n` +
|
||||
`- Session: ${workspaceSessionId}\n` +
|
||||
`- Workspace registration: ${isWorkspaceRegistered ? '✅' : '❌'}\n` +
|
||||
`- Global registration: ${isGlobalRegistered ? '✅' : '❌'}`
|
||||
`- Registration: Native Provider ✅`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -252,16 +249,9 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
});
|
||||
|
||||
const configureMcpCommand = vscode.commands.registerCommand('humanagent-mcp.configureMcp', async () => {
|
||||
// Refresh state checks each time the command is executed
|
||||
const hasWorkspace = mcpConfigManager?.hasWorkspace() ?? false;
|
||||
const isWorkspaceRegistered = mcpConfigManager?.isMcpServerRegistered(false) ?? false;
|
||||
const isGlobalRegistered = mcpConfigManager?.isMcpServerRegistered(true) ?? false;
|
||||
|
||||
console.log(`HumanAgent MCP: Configure command - hasWorkspace: ${hasWorkspace}, workspaceRegistered: ${isWorkspaceRegistered}, globalRegistered: ${isGlobalRegistered}`);
|
||||
|
||||
const options = [];
|
||||
|
||||
// Server management options
|
||||
// Server management options only (registration handled automatically by native provider)
|
||||
const serverStatus = await serverManager.getServerStatus();
|
||||
if (serverStatus.isRunning) {
|
||||
options.push('🔴 Stop Server');
|
||||
@@ -270,33 +260,10 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
options.push('▶️ Start Server');
|
||||
}
|
||||
|
||||
if (hasWorkspace) {
|
||||
if (isWorkspaceRegistered) {
|
||||
options.push('🗑️ Unregister from This Workspace');
|
||||
console.log('HumanAgent MCP: Added workspace UNREGISTER option');
|
||||
} else {
|
||||
options.push('📝 Register for This Workspace');
|
||||
console.log('HumanAgent MCP: Added workspace REGISTER option');
|
||||
}
|
||||
}
|
||||
|
||||
if (isGlobalRegistered) {
|
||||
options.push('🗑️ Unregister Globally');
|
||||
console.log('HumanAgent MCP: Added global UNREGISTER option');
|
||||
} else {
|
||||
options.push('🌐 Register Globally');
|
||||
console.log('HumanAgent MCP: Added global REGISTER option');
|
||||
}
|
||||
|
||||
if (hasWorkspace) {
|
||||
options.push('📄 Open Workspace Configuration');
|
||||
}
|
||||
options.push('📊 Show Status');
|
||||
|
||||
console.log(`HumanAgent MCP: Final options: ${options.join(', ')}`);
|
||||
|
||||
const action = await vscode.window.showQuickPick(options, {
|
||||
placeHolder: 'Choose MCP Server configuration action:'
|
||||
placeHolder: 'Choose MCP Server action:'
|
||||
});
|
||||
|
||||
if (!action) {
|
||||
@@ -314,36 +281,12 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
case '🔄 Restart Server':
|
||||
await vscode.commands.executeCommand('humanagent-mcp.restartServer');
|
||||
break;
|
||||
case '📝 Register for This Workspace':
|
||||
await mcpConfigManager!.ensureMcpServerRegistered(false, workspaceSessionId);
|
||||
vscode.window.showInformationMessage('MCP server registered for this workspace! Restart VS Code to enable Copilot integration.');
|
||||
break;
|
||||
case '🌐 Register Globally':
|
||||
await mcpConfigManager!.ensureMcpServerRegistered(true, workspaceSessionId);
|
||||
vscode.window.showInformationMessage('MCP server registered globally! Restart VS Code to enable Copilot integration.');
|
||||
break;
|
||||
case '🗑️ Unregister from This Workspace':
|
||||
await mcpConfigManager!.removeMcpServerRegistration(false);
|
||||
vscode.window.showInformationMessage('MCP server unregistered from this workspace. Restart VS Code to apply changes.');
|
||||
break;
|
||||
case '🗑️ Unregister Globally':
|
||||
await mcpConfigManager!.removeMcpServerRegistration(true);
|
||||
vscode.window.showInformationMessage('MCP server unregistered globally. Restart VS Code to apply changes.');
|
||||
break;
|
||||
case '📄 Open Workspace Configuration':
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
||||
if (workspaceRoot) {
|
||||
const configPath = vscode.Uri.file(workspaceRoot + '/.vscode/mcp.json');
|
||||
vscode.commands.executeCommand('vscode.open', configPath);
|
||||
}
|
||||
break;
|
||||
case '📊 Show Status':
|
||||
// Call the dedicated status command
|
||||
vscode.commands.executeCommand('humanagent-mcp.showStatus');
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(`MCP configuration failed: ${error instanceof Error ? error.message : String(error)}`);
|
||||
vscode.window.showErrorMessage(`Server action failed: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -364,37 +307,38 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
//vscode.window.showInformationMessage('HumanAgent MCP extension activated successfully!');
|
||||
}
|
||||
|
||||
// Auto-detect MCP server configuration and guide user if needed
|
||||
async function autoStartMcpServer(configManager: McpConfigManager, sessionId: string): Promise<void> {
|
||||
// Simplified server startup and session registration (no mcp.json dependency)
|
||||
async function ensureServerAndRegisterSession(sessionId: string): Promise<void> {
|
||||
try {
|
||||
// Check for workspace configuration first (higher priority)
|
||||
if (configManager.isMcpServerRegistered(false)) {
|
||||
console.log(`HumanAgent MCP: Found workspace configuration for session ${sessionId}, checking server status...`);
|
||||
await ensureServerAccessibleAndRegister(sessionId, 'workspace');
|
||||
return;
|
||||
}
|
||||
console.log(`HumanAgent MCP: Starting server and registering session ${sessionId}...`);
|
||||
|
||||
// Check for global configuration
|
||||
if (configManager.isMcpServerRegistered(true)) {
|
||||
console.log(`HumanAgent MCP: Found global configuration for session ${sessionId}, checking server status...`);
|
||||
await ensureServerAccessibleAndRegister(sessionId, 'global');
|
||||
return;
|
||||
}
|
||||
|
||||
// No configuration found - guide user to setup
|
||||
console.log(`HumanAgent MCP: No MCP configuration found for session ${sessionId}`);
|
||||
vscode.window.showInformationMessage(
|
||||
'HumanAgent MCP Server not configured. Use the Configure MCP command to set up the server.',
|
||||
'Configure Now'
|
||||
).then(selection => {
|
||||
if (selection === 'Configure Now') {
|
||||
vscode.commands.executeCommand('humanagent-mcp.configureMcp');
|
||||
// Check if server is accessible, if not start it
|
||||
const serverAccessible = await isServerAccessible();
|
||||
if (!serverAccessible) {
|
||||
console.log('HumanAgent MCP: Server not accessible, starting server...');
|
||||
const serverStarted = await serverManager.ensureServerRunning();
|
||||
if (!serverStarted) {
|
||||
console.error('HumanAgent MCP: Failed to start server');
|
||||
vscode.window.showWarningMessage('HumanAgent MCP Server could not be started. Some features may not work.');
|
||||
return;
|
||||
}
|
||||
});
|
||||
console.log('HumanAgent MCP: Server started successfully');
|
||||
}
|
||||
|
||||
// Register session with the server
|
||||
const sessionExists = await validateSessionWithServer(sessionId);
|
||||
if (!sessionExists) {
|
||||
console.log(`HumanAgent MCP: Session ${sessionId} not found on server, registering new session...`);
|
||||
await registerSessionWithStandaloneServer(sessionId, false);
|
||||
} else {
|
||||
console.log(`HumanAgent MCP: Session ${sessionId} exists on server, re-registering with override data...`);
|
||||
await registerSessionWithStandaloneServer(sessionId, true);
|
||||
}
|
||||
console.log(`HumanAgent MCP: Session registration complete for ${sessionId}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('HumanAgent MCP: Failed to check server configuration:', error);
|
||||
vscode.window.showErrorMessage('Failed to check HumanAgent MCP Server configuration');
|
||||
console.error('HumanAgent MCP: Failed to start server or register session:', error);
|
||||
vscode.window.showWarningMessage('HumanAgent MCP Server could not be initialized. Please check the server status and try reloading the workspace.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +358,7 @@ async function isPortInUse(port: number): Promise<boolean> {
|
||||
});
|
||||
}
|
||||
|
||||
// Check if MCP server is accessible and responding
|
||||
// Check if MCP server is accessible and responding with retry
|
||||
async function isServerAccessible(): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch('http://127.0.0.1:3737/sessions', {
|
||||
@@ -423,12 +367,30 @@ async function isServerAccessible(): Promise<boolean> {
|
||||
});
|
||||
return response.ok;
|
||||
} catch (error) {
|
||||
console.log('HumanAgent MCP: Server accessibility check failed:', error);
|
||||
console.log('HumanAgent MCP: Server accessibility check failed, retrying in 3 seconds...', error);
|
||||
|
||||
// Wait 3 seconds and try once more
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
||||
try {
|
||||
const retryResponse = await fetch('http://127.0.0.1:3737/sessions', {
|
||||
method: 'GET',
|
||||
signal: AbortSignal.timeout(5000)
|
||||
});
|
||||
|
||||
if (retryResponse.ok) {
|
||||
console.log('HumanAgent MCP: Server accessible on retry');
|
||||
return true;
|
||||
}
|
||||
} catch (retryError) {
|
||||
console.log('HumanAgent MCP: Server accessibility retry failed:', retryError);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if session exists on server by testing a simple MCP call
|
||||
// Check if session exists on server by testing a simple MCP call with retry
|
||||
async function validateSessionWithServer(sessionId: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch('http://127.0.0.1:3737/mcp', {
|
||||
@@ -449,49 +411,100 @@ async function validateSessionWithServer(sessionId: string): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`HumanAgent MCP: Session ${sessionId} validation failed:`, error);
|
||||
return false;
|
||||
console.log(`HumanAgent MCP: Session ${sessionId} validation failed, retrying in 3 seconds...`, error);
|
||||
|
||||
// Wait 3 seconds and try once more
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
||||
try {
|
||||
const retryResponse = await fetch('http://127.0.0.1:3737/mcp', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
sessionId,
|
||||
method: 'tools/list'
|
||||
})
|
||||
});
|
||||
|
||||
if (retryResponse.ok) {
|
||||
const result = await retryResponse.json() as any;
|
||||
console.log(`HumanAgent MCP: Session ${sessionId} validated on server (retry)`);
|
||||
return true;
|
||||
} else {
|
||||
console.log(`HumanAgent MCP: Session ${sessionId} not found on server (${retryResponse.status}) (retry)`);
|
||||
return false;
|
||||
}
|
||||
} catch (retryError) {
|
||||
console.log(`HumanAgent MCP: Session ${sessionId} validation retry failed:`, retryError);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register session with standalone server via HTTP (always sends override data)
|
||||
// Register session with standalone server via HTTP (always sends override data) with retry
|
||||
async function registerSessionWithStandaloneServer(sessionId: string, forceReregister: boolean = false): Promise<void> {
|
||||
try {
|
||||
// Read workspace override file if it exists
|
||||
let overrideData = null;
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
||||
if (workspaceRoot) {
|
||||
const overrideFilePath = path.join(workspaceRoot, '.vscode', 'HumanAgentOverride.json');
|
||||
try {
|
||||
const fs = require('fs');
|
||||
if (fs.existsSync(overrideFilePath)) {
|
||||
const overrideContent = fs.readFileSync(overrideFilePath, 'utf8');
|
||||
overrideData = JSON.parse(overrideContent);
|
||||
console.log(`HumanAgent MCP: Loaded override data for session ${sessionId}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`HumanAgent MCP: Error reading override file:`, error);
|
||||
// Read workspace override file if it exists
|
||||
let overrideData = null;
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
||||
if (workspaceRoot) {
|
||||
const overrideFilePath = path.join(workspaceRoot, '.vscode', 'HumanAgentOverride.json');
|
||||
try {
|
||||
const fs = require('fs');
|
||||
if (fs.existsSync(overrideFilePath)) {
|
||||
const overrideContent = fs.readFileSync(overrideFilePath, 'utf8');
|
||||
overrideData = JSON.parse(overrideContent);
|
||||
console.log(`HumanAgent MCP: Loaded override data for session ${sessionId}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`HumanAgent MCP: Error reading override file:`, error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const requestBody = {
|
||||
sessionId,
|
||||
overrideData: overrideData,
|
||||
forceReregister: forceReregister
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('http://127.0.0.1:3737/sessions/register', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
sessionId,
|
||||
overrideData: overrideData,
|
||||
forceReregister: forceReregister
|
||||
})
|
||||
body: JSON.stringify(requestBody)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json() as any;
|
||||
console.log(`HumanAgent MCP: Session ${sessionId} registered successfully. Total sessions: ${result.totalSessions}`);
|
||||
return;
|
||||
} else {
|
||||
console.error(`HumanAgent MCP: Failed to register session ${sessionId}: ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`HumanAgent MCP: Error registering session ${sessionId}:`, error);
|
||||
console.error(`HumanAgent MCP: Error registering session ${sessionId}, retrying in 3 seconds...`, error);
|
||||
|
||||
// Wait 3 seconds and try once more
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
||||
try {
|
||||
const retryResponse = await fetch('http://127.0.0.1:3737/sessions/register', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(requestBody)
|
||||
});
|
||||
|
||||
if (retryResponse.ok) {
|
||||
const result = await retryResponse.json() as any;
|
||||
console.log(`HumanAgent MCP: Session ${sessionId} registered successfully on retry. Total sessions: ${result.totalSessions}`);
|
||||
return;
|
||||
} else {
|
||||
console.error(`HumanAgent MCP: Failed to register session ${sessionId} on retry: ${retryResponse.status}`);
|
||||
throw new Error(`Registration failed: ${retryResponse.status}`);
|
||||
}
|
||||
} catch (retryError) {
|
||||
console.error(`HumanAgent MCP: Session registration retry failed:`, retryError);
|
||||
throw new Error(`Registration failed after retry: ${retryError}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,15 +68,10 @@ export class McpConfigManager {
|
||||
|
||||
// Use the extension path passed during construction
|
||||
|
||||
// Configure our MCP server (HTTP transport)
|
||||
const mcpUrl = sessionId ? `http://127.0.0.1:3737/mcp?sessionId=${sessionId}` : 'http://127.0.0.1:3737/mcp';
|
||||
// Configure our MCP server (HTTP transport) - no sessionId in URL
|
||||
const serverConfig: any = {
|
||||
type: 'http',
|
||||
url: mcpUrl,
|
||||
notifications: {
|
||||
enableSound: true,
|
||||
enableFlashing: true
|
||||
}
|
||||
url: 'http://127.0.0.1:3737/mcp'
|
||||
};
|
||||
|
||||
// Add our server to the config
|
||||
@@ -100,15 +95,10 @@ export class McpConfigManager {
|
||||
try {
|
||||
// Use the extension path passed during construction
|
||||
|
||||
// Configure our MCP server (HTTP transport)
|
||||
const mcpUrl = sessionId ? `http://127.0.0.1:3737/mcp?sessionId=${sessionId}` : 'http://127.0.0.1:3737/mcp';
|
||||
// Configure our MCP server (HTTP transport) - no sessionId in URL
|
||||
const serverConfig: any = {
|
||||
type: 'http',
|
||||
url: mcpUrl,
|
||||
notifications: {
|
||||
enableSound: true,
|
||||
enableFlashing: true
|
||||
}
|
||||
url: 'http://127.0.0.1:3737/mcp'
|
||||
};
|
||||
|
||||
// Get current global MCP servers configuration
|
||||
|
||||
+293
-100
@@ -17,8 +17,8 @@ class DebugLogger {
|
||||
|
||||
constructor(workspaceRoot?: string) {
|
||||
// Check environment variables for logging configuration
|
||||
this.loggingEnabled = process.env.HUMANAGENT_LOGGING_ENABLED === 'true';
|
||||
this.loggingLevel = process.env.HUMANAGENT_LOGGING_LEVEL || 'INFO';
|
||||
this.loggingEnabled = process.env.HUMANAGENT_LOGGING_ENABLED === 'true' || true; // Enable by default for debugging
|
||||
this.loggingLevel = process.env.HUMANAGENT_LOGGING_LEVEL || 'DEBUG'; // Debug level by default
|
||||
|
||||
// If logging is disabled, just log to console for important messages
|
||||
if (!this.loggingEnabled) {
|
||||
@@ -27,20 +27,9 @@ class DebugLogger {
|
||||
}
|
||||
|
||||
try {
|
||||
// Determine log path based on workspace or fallback to temp directory
|
||||
if (workspaceRoot) {
|
||||
const vscodeDir = path.join(workspaceRoot, '.vscode');
|
||||
this.logPath = path.join(vscodeDir, 'HumanAgent-server.log');
|
||||
|
||||
// Ensure .vscode directory exists
|
||||
if (!fs.existsSync(vscodeDir)) {
|
||||
fs.mkdirSync(vscodeDir, { recursive: true });
|
||||
}
|
||||
} else {
|
||||
// Fallback for standalone server or when no workspace available
|
||||
const tempDir = os.tmpdir();
|
||||
this.logPath = path.join(tempDir, 'HumanAgent-server.log');
|
||||
}
|
||||
// Always log to system temp directory - server is workspace-independent
|
||||
const tempDir = os.tmpdir();
|
||||
this.logPath = path.join(tempDir, 'HumanAgent-server.log');
|
||||
|
||||
console.log(`[LOGGER] Attempting to create log file at: ${this.logPath}`);
|
||||
|
||||
@@ -134,9 +123,9 @@ export class McpServer extends EventEmitter {
|
||||
private requestResolvers: Map<string, { resolve: (response: string) => void; reject: (error: Error) => void }> = new Map();
|
||||
private activeSessions: Set<string> = new Set();
|
||||
private sseConnections: Set<http.ServerResponse> = new Set();
|
||||
private conversationToSession: Map<string, string> = new Map(); // Map VS Code conversation IDs to registered session IDs
|
||||
private chatManager: ChatManager; // Centralized chat and session management
|
||||
private sseClients: Map<string, http.ServerResponse> = new Map(); // Per-session SSE connections
|
||||
private sseClients: Map<string, http.ServerResponse> = new Map(); // Per-session SSE connections (VS Code webviews)
|
||||
private webInterfaceConnections: Set<http.ServerResponse> = new Set(); // Web interface connections (all browsers)
|
||||
|
||||
constructor(private sessionId?: string, private workspacePath?: string) {
|
||||
super();
|
||||
@@ -169,32 +158,62 @@ export class McpServer extends EventEmitter {
|
||||
|
||||
private setupEventForwarding(): void {
|
||||
this.on('request-state-change', (data) => {
|
||||
this.debugLogger.log('SSE', 'Forwarding request-state-change to SSE connections');
|
||||
this.broadcastToSSE('request-state-change', data);
|
||||
this.debugLogger.log('SSE', 'Forwarding request-state-change to target session and web interface');
|
||||
this.sendToSessionAndWeb(data.sessionId, 'request-state-change', data);
|
||||
});
|
||||
}
|
||||
|
||||
private broadcastToSSE(eventType: string, data: any): void {
|
||||
// Send event to web interface connections only
|
||||
private sendToWebInterface(eventType: string, data: any): void {
|
||||
const message = JSON.stringify({ type: eventType, data });
|
||||
const eventData = `data: ${message}\n\n`;
|
||||
|
||||
this.debugLogger.log('SSE', `Broadcasting to ${this.sseConnections.size} SSE connections:`, message);
|
||||
this.debugLogger.log('SSE', `Sending to ${this.webInterfaceConnections.size} web interface connections:`, message);
|
||||
|
||||
// Send to all active SSE connections
|
||||
for (const connection of this.sseConnections) {
|
||||
for (const connection of this.webInterfaceConnections) {
|
||||
if (!connection.destroyed) {
|
||||
try {
|
||||
connection.write(eventData);
|
||||
} catch (error) {
|
||||
this.debugLogger.log('SSE', 'Failed to write to SSE connection:', error);
|
||||
this.debugLogger.log('SSE', 'Failed to write to web interface connection:', error);
|
||||
this.webInterfaceConnections.delete(connection);
|
||||
this.sseConnections.delete(connection);
|
||||
}
|
||||
} else {
|
||||
this.webInterfaceConnections.delete(connection);
|
||||
this.sseConnections.delete(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send event to specific session only
|
||||
private sendToSession(sessionId: string, eventType: string, data: any): void {
|
||||
const message = { type: eventType, data };
|
||||
|
||||
const sessionConnection = this.sseClients.get(sessionId);
|
||||
if (!sessionConnection) {
|
||||
this.debugLogger.log('WARN', `❌ No SSE connection found for session ${sessionId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug: Compare connection objects to see if they match the heartbeat connection
|
||||
this.debugLogger.log('SSE', `🔍 Sending to session ${sessionId} - Connection destroyed: ${sessionConnection.destroyed}, writable: ${sessionConnection.writable}`);
|
||||
|
||||
// Use the enhanced sendSSEMessage method with health checking
|
||||
this.sendSSEMessage(sessionConnection, message);
|
||||
this.debugLogger.log('SSE', `Sent to session ${sessionId}:`, JSON.stringify(message));
|
||||
}
|
||||
|
||||
// Send event to specific session AND web interface
|
||||
private sendToSessionAndWeb(sessionId: string, eventType: string, data: any): void {
|
||||
// Send to specific session
|
||||
this.sendToSession(sessionId, eventType, data);
|
||||
// Also send to web interface
|
||||
this.sendToWebInterface(eventType, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private sendMcpNotification(method: string, params?: any, sessionId?: string): void {
|
||||
this.debugLogger.log('MCP', `Sending SSE notification: ${method}`, params);
|
||||
|
||||
@@ -229,11 +248,27 @@ export class McpServer extends EventEmitter {
|
||||
|
||||
private sendSSEMessage(response: http.ServerResponse, message: any): void {
|
||||
try {
|
||||
// Check connection health before sending
|
||||
if (response.destroyed) {
|
||||
this.debugLogger.log('ERROR', `Cannot send SSE message: connection is destroyed`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.writable) {
|
||||
this.debugLogger.log('ERROR', `Cannot send SSE message: connection is not writable`);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = JSON.stringify(message);
|
||||
response.write(`data: ${data}\n\n`);
|
||||
this.debugLogger.log('SSE', `Sent SSE message: ${message.method || 'response'}`);
|
||||
const success = response.write(`data: ${data}\n\n`);
|
||||
|
||||
if (success) {
|
||||
this.debugLogger.log('SSE', `✅ Successfully sent SSE message: ${message.type || message.method || 'response'}`);
|
||||
} else {
|
||||
this.debugLogger.log('ERROR', `❌ Failed to write SSE message (buffer full): ${message.type || message.method || 'response'}`);
|
||||
}
|
||||
} catch (error) {
|
||||
this.debugLogger.log('ERROR', `Failed to send SSE message:`, error);
|
||||
this.debugLogger.log('ERROR', `❌ Exception sending SSE message:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,10 +292,7 @@ export class McpServer extends EventEmitter {
|
||||
type: 'string',
|
||||
description: 'Optional context or background information for the human agent'
|
||||
},
|
||||
sessionId: {
|
||||
type: 'string',
|
||||
description: 'Optional specific session ID to use. If not provided, a new session will be created.'
|
||||
},
|
||||
|
||||
priority: {
|
||||
type: 'string',
|
||||
enum: ['low', 'normal', 'high', 'urgent'],
|
||||
@@ -512,7 +544,11 @@ export class McpServer extends EventEmitter {
|
||||
const reqUrl = new URL(req.url!, `http://${req.headers.host}`);
|
||||
|
||||
if (reqUrl.pathname === '/mcp') {
|
||||
// Main MCP protocol endpoint
|
||||
// Main MCP protocol endpoint (webview SSE)
|
||||
} else if (reqUrl.pathname === '/mcp-tools') {
|
||||
// MCP tools endpoint (extension only, no SSE conflicts)
|
||||
await this.handleMcpToolsEndpoint(req, res, reqUrl);
|
||||
return;
|
||||
} else if (req.url === '/HumanAgent') {
|
||||
// Web interface for multi-session chat
|
||||
await this.handleWebInterface(req, res);
|
||||
@@ -626,22 +662,31 @@ export class McpServer extends EventEmitter {
|
||||
this.debugLogger.log('SSE', 'Headers:', req.headers);
|
||||
this.debugLogger.log('SSE', 'URL:', req.url);
|
||||
|
||||
// Extract sessionId from query params in URL or Mcp-Session-Id header
|
||||
// Extract sessionId and clientType from query params in URL or headers
|
||||
const url = new URL(req.url!, `http://${req.headers.host}`);
|
||||
let sessionId = url.searchParams.get('sessionId');
|
||||
const clientType = url.searchParams.get('clientType');
|
||||
|
||||
// If not in URL, try the Mcp-Session-Id header (per MCP spec)
|
||||
if (!sessionId) {
|
||||
sessionId = req.headers['mcp-session-id'] as string;
|
||||
}
|
||||
|
||||
if (!sessionId) {
|
||||
this.debugLogger.log('SSE', 'No sessionId in SSE request (tried URL param and Mcp-Session-Id header)');
|
||||
// Validate connection parameters
|
||||
if (!sessionId && clientType !== 'web') {
|
||||
this.debugLogger.log('ERROR', 'SSE connection rejected: sessionId required for VS Code connections, or use clientType=web for web interface');
|
||||
this.debugLogger.log('SSE', `Request headers: ${JSON.stringify(req.headers)}`);
|
||||
this.debugLogger.log('SSE', `Request URL: ${req.url}`);
|
||||
// For now, let's allow connection without sessionId and use a default
|
||||
sessionId = 'default-sse-session';
|
||||
this.debugLogger.log('SSE', `Using default sessionId: ${sessionId}`);
|
||||
res.statusCode = 400;
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(JSON.stringify({ error: 'sessionId required for VS Code connections, or use clientType=web for web interface' }));
|
||||
return;
|
||||
}
|
||||
|
||||
// For web interface connections, use a placeholder sessionId for logging
|
||||
if (clientType === 'web') {
|
||||
sessionId = 'web-interface';
|
||||
this.debugLogger.log('SSE', 'Web interface SSE connection detected via clientType=web');
|
||||
}
|
||||
|
||||
// Set up Server-Sent Events (SSE) stream
|
||||
@@ -657,11 +702,21 @@ export class McpServer extends EventEmitter {
|
||||
|
||||
this.debugLogger.log('SSE', `SSE headers set for session ${sessionId}, adding to connections...`);
|
||||
|
||||
// Add this connection to our session-based SSE connections
|
||||
this.sseClients.set(sessionId, res);
|
||||
this.sseConnections.add(res); // Keep old connections for cleanup
|
||||
this.debugLogger.log('HTTP', `Added SSE connection for session ${sessionId}. Total connections: ${this.sseConnections.size}`);
|
||||
this.debugLogger.log('SSE', `SSE connection added for session ${sessionId}. Total: ${this.sseConnections.size}`);
|
||||
// Detect connection type: web interface via clientType=web, VS Code via sessionId
|
||||
const isWebInterface = clientType === 'web';
|
||||
const isVSCodeWebview = !isWebInterface && sessionId !== 'web-interface';
|
||||
|
||||
if (isWebInterface) {
|
||||
// Web interface connection - add to web interface connections
|
||||
this.webInterfaceConnections.add(res);
|
||||
this.sseConnections.add(res); // Keep old connections for cleanup
|
||||
this.debugLogger.log('SSE', `Added web interface SSE connection. Total web connections: ${this.webInterfaceConnections.size}`);
|
||||
} else {
|
||||
// VS Code webview connection - add to session-specific connections
|
||||
this.sseClients.set(sessionId!, res);
|
||||
this.sseConnections.add(res); // Keep old connections for cleanup
|
||||
this.debugLogger.log('SSE', `Added VS Code SSE connection for session ${sessionId}. Total session connections: ${this.sseClients.size}`);
|
||||
}
|
||||
|
||||
// Send initial connection acknowledgment
|
||||
const initialMessage = 'data: {"type":"connection","status":"established","sessionId":"' + sessionId + '"}\n\n';
|
||||
@@ -676,15 +731,22 @@ export class McpServer extends EventEmitter {
|
||||
clearInterval(heartbeat);
|
||||
this.sseConnections.delete(res);
|
||||
}
|
||||
}, 30000); // Send heartbeat every 30 seconds
|
||||
}, 10000); // Send heartbeat every 10 seconds
|
||||
|
||||
// Handle client disconnect
|
||||
const cleanup = () => {
|
||||
this.debugLogger.log('HTTP', `SSE connection closed for session ${sessionId}`);
|
||||
clearInterval(heartbeat);
|
||||
this.sseConnections.delete(res);
|
||||
this.sseClients.delete(sessionId);
|
||||
this.debugLogger.log('HTTP', `Removed SSE connection for session ${sessionId}. Total connections: ${this.sseConnections.size}`);
|
||||
|
||||
// Remove from appropriate connection type
|
||||
if (isWebInterface) {
|
||||
this.webInterfaceConnections.delete(res);
|
||||
this.debugLogger.log('HTTP', `Removed web interface SSE connection. Total web connections: ${this.webInterfaceConnections.size}`);
|
||||
} else {
|
||||
this.sseClients.delete(sessionId);
|
||||
this.debugLogger.log('HTTP', `Removed VS Code SSE connection for session ${sessionId}. Total session connections: ${this.sseClients.size}`);
|
||||
}
|
||||
};
|
||||
|
||||
req.on('close', cleanup);
|
||||
@@ -698,6 +760,33 @@ export class McpServer extends EventEmitter {
|
||||
res.end('Method Not Allowed');
|
||||
}
|
||||
|
||||
private async handleMcpToolsEndpoint(req: http.IncomingMessage, res: http.ServerResponse, reqUrl: URL): Promise<void> {
|
||||
// MCP tools endpoint - handles MCP protocol for VS Code extension without SSE conflicts
|
||||
this.debugLogger.log('HTTP', `MCP Tools: ${req.method} ${req.url}`);
|
||||
|
||||
// Extract sessionId from query params
|
||||
const sessionId = reqUrl.searchParams.get('sessionId');
|
||||
if (!sessionId) {
|
||||
this.debugLogger.log('ERROR', 'MCP Tools: sessionId required');
|
||||
res.statusCode = 400;
|
||||
res.end(JSON.stringify({ error: 'sessionId required' }));
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method === 'POST') {
|
||||
// Handle MCP protocol messages (initialize, tools/list, tools/call)
|
||||
await this.handleHttpPost(req, res);
|
||||
} else if (req.method === 'GET') {
|
||||
// Reject GET requests to prevent SSE conflicts - tools only via POST
|
||||
this.debugLogger.log('WARN', 'MCP Tools: GET requests not allowed (use /mcp for SSE)');
|
||||
res.statusCode = 405;
|
||||
res.end(JSON.stringify({ error: 'GET not allowed on /mcp-tools - use /mcp for SSE' }));
|
||||
} else {
|
||||
res.statusCode = 405;
|
||||
res.end('Method Not Allowed');
|
||||
}
|
||||
}
|
||||
|
||||
private async handleSessionEndpoint(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
|
||||
const url = new URL(req.url || '', `http://localhost:${this.port}`);
|
||||
|
||||
@@ -769,9 +858,9 @@ export class McpServer extends EventEmitter {
|
||||
this.sessionNames.set(sessionId, name);
|
||||
this.debugLogger.log('INFO', `Session ${sessionId} named: "${name}"`);
|
||||
|
||||
// Broadcast name change via SSE to all connected clients
|
||||
this.broadcastToSSE('session-name-changed', { sessionId, name });
|
||||
this.debugLogger.log('SSE', 'Broadcasting session name change to all clients');
|
||||
// Send name change to target session and web interface
|
||||
this.sendToSessionAndWeb(sessionId, 'session-name-changed', { sessionId, name });
|
||||
this.debugLogger.log('SSE', 'Sent session name change to target session and web interface');
|
||||
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
@@ -1417,6 +1506,95 @@ export class McpServer extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
function addSessionTab(sessionId) {
|
||||
// Check if tab already exists
|
||||
const existingTab = document.querySelector(\`[data-session="\${sessionId}"].tab\`);
|
||||
if (existingTab) {
|
||||
console.log(\`Tab for session \${sessionId} already exists\`);
|
||||
return;
|
||||
}
|
||||
|
||||
const tabsContainer = document.getElementById('tabs');
|
||||
const contentDiv = document.querySelector('.content');
|
||||
|
||||
if (!tabsContainer || !contentDiv) {
|
||||
console.error('Could not find tabs container or content div');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new tab
|
||||
const tabElement = document.createElement('div');
|
||||
tabElement.className = 'tab';
|
||||
tabElement.setAttribute('data-session', sessionId);
|
||||
tabElement.textContent = \`Session: \${sessionId.substring(0, 8)}\`;
|
||||
tabElement.onclick = () => switchToSession(sessionId);
|
||||
|
||||
// Add tab to container
|
||||
tabsContainer.appendChild(tabElement);
|
||||
|
||||
// Create new chat container
|
||||
const chatContainer = document.createElement('div');
|
||||
chatContainer.className = 'chat-container';
|
||||
chatContainer.setAttribute('data-session', sessionId);
|
||||
chatContainer.innerHTML = \`
|
||||
<div class="messages" id="messages-\${sessionId}">
|
||||
<!-- Messages will be loaded dynamically -->
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<textarea class="input-box" placeholder="Type your message..." data-session="\${sessionId}"></textarea>
|
||||
<button class="send-button" data-session="\${sessionId}">Send</button>
|
||||
</div>
|
||||
\`;
|
||||
|
||||
// Add chat container to content
|
||||
contentDiv.appendChild(chatContainer);
|
||||
|
||||
// Set up event listeners for new input elements
|
||||
const textarea = chatContainer.querySelector('textarea');
|
||||
const button = chatContainer.querySelector('button');
|
||||
|
||||
if (textarea) {
|
||||
textarea.addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
sendResponse(sessionId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (button) {
|
||||
button.addEventListener('click', () => sendResponse(sessionId));
|
||||
}
|
||||
|
||||
console.log(\`Added new session tab: \${sessionId}\`);
|
||||
}
|
||||
|
||||
function removeSessionTab(sessionId) {
|
||||
// Remove tab
|
||||
const tabElement = document.querySelector(\`[data-session="\${sessionId}"].tab\`);
|
||||
if (tabElement) {
|
||||
tabElement.remove();
|
||||
}
|
||||
|
||||
// Remove chat container
|
||||
const chatContainer = document.querySelector(\`[data-session="\${sessionId}"].chat-container\`);
|
||||
if (chatContainer) {
|
||||
chatContainer.remove();
|
||||
}
|
||||
|
||||
// If this was the active session, switch to first available
|
||||
const remainingTabs = document.querySelectorAll('.tab');
|
||||
if (remainingTabs.length > 0) {
|
||||
const firstTab = remainingTabs[0];
|
||||
const firstSessionId = firstTab.getAttribute('data-session');
|
||||
if (firstSessionId) {
|
||||
switchToSession(firstSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(\`Removed session tab: \${sessionId}\`);
|
||||
}
|
||||
|
||||
// Load existing messages for all sessions
|
||||
async function loadExistingMessages() {
|
||||
const sessions = ['${sessions.map(s => s.id).join("', '")}'];
|
||||
@@ -1478,7 +1656,7 @@ export class McpServer extends EventEmitter {
|
||||
// WebSocket connection for real-time updates
|
||||
function setupRealtimeUpdates() {
|
||||
console.log('Setting up SSE connection to /mcp...');
|
||||
const eventSource = new EventSource('/mcp');
|
||||
const eventSource = new EventSource('/mcp?clientType=web');
|
||||
|
||||
eventSource.onopen = function(event) {
|
||||
console.log('SSE connection opened successfully:', event);
|
||||
@@ -1548,6 +1726,14 @@ export class McpServer extends EventEmitter {
|
||||
} else if (data.type === 'session_update') {
|
||||
// Refresh the page to show new sessions
|
||||
window.location.reload();
|
||||
} else if (data.type === 'session-registered' && data.data) {
|
||||
// Add new session tab dynamically
|
||||
console.log('New session registered:', data.data);
|
||||
addSessionTab(data.data.sessionId);
|
||||
} else if (data.type === 'session-unregistered' && data.data) {
|
||||
// Remove session tab dynamically
|
||||
console.log('Session unregistered:', data.data);
|
||||
removeSessionTab(data.data.sessionId);
|
||||
} else if (data.type === 'session-name-changed' && data.data) {
|
||||
// Handle session name changes
|
||||
console.log('Session name changed:', data.data);
|
||||
@@ -1646,11 +1832,10 @@ export class McpServer extends EventEmitter {
|
||||
|
||||
private async handleToolCall(message: McpMessage): Promise<McpMessage> {
|
||||
const { name, arguments: args } = message.params;
|
||||
// Extract session ID from _meta.vscode.conversationId (VS Code) or fallback to args.sessionId (web)
|
||||
const rawSessionId = message.params._meta?.['vscode.conversationId'] || args?.sessionId;
|
||||
const sessionId = this.mapToRegisteredSession(rawSessionId);
|
||||
// Use actual session ID from MCP message context, not tool argument
|
||||
const sessionId = message.params.sessionId;
|
||||
|
||||
this.debugLogger.log('MCP', `Tool call - name: "${name}", raw session: ${rawSessionId}, mapped session: ${sessionId}`, { name, args });
|
||||
this.debugLogger.log('MCP', `Tool call - name: "${name}", sessionId: ${sessionId}`, { name, args });
|
||||
|
||||
// Check session-specific tools first, then default tools
|
||||
const sessionTools = sessionId ? this.sessionTools.get(sessionId) : null;
|
||||
@@ -1676,6 +1861,21 @@ export class McpServer extends EventEmitter {
|
||||
|
||||
private async handleHumanAgentChatTool(messageId: string, params: HumanAgentChatToolParams, sessionId?: string, toolName?: string): Promise<McpMessage> {
|
||||
this.debugLogger.log('TOOL', 'HumanAgent_Chat called with params:', params);
|
||||
|
||||
// Require valid session ID - no default fallback allowed
|
||||
const actualSessionId = sessionId || params.sessionId;
|
||||
if (!actualSessionId) {
|
||||
this.debugLogger.log('ERROR', 'HumanAgent_Chat tool called without session ID - rejecting');
|
||||
return {
|
||||
id: messageId,
|
||||
type: 'response',
|
||||
error: {
|
||||
code: -32602,
|
||||
message: 'Invalid parameters: sessionId is required for HumanAgent_Chat tool'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const startTime = Date.now();
|
||||
const timeoutMs = params.timeout ? params.timeout * 1000 : null; // Convert to milliseconds or null for no timeout
|
||||
this.debugLogger.log('TOOL', `Using timeout: ${timeoutMs ? `${timeoutMs}ms (${timeoutMs/1000}s)` : 'no timeout (wait indefinitely)'}`);
|
||||
@@ -1711,9 +1911,8 @@ export class McpServer extends EventEmitter {
|
||||
}, timeoutMs);
|
||||
}
|
||||
|
||||
// Store the pending request using the extracted session ID
|
||||
const sessionToUse = sessionId || params.sessionId || 'default';
|
||||
this.debugLogger.log('TOOL', `Adding pending request ${requestId} to session: ${sessionToUse}`);
|
||||
// Use the validated session ID
|
||||
this.debugLogger.log('TOOL', `Adding pending request ${requestId} to session: ${actualSessionId}`);
|
||||
|
||||
// Store the AI's message (this IS the AI communication - it talks by calling the tool)
|
||||
const aiMessage: ChatMessage = {
|
||||
@@ -1723,21 +1922,21 @@ export class McpServer extends EventEmitter {
|
||||
timestamp: new Date(),
|
||||
type: 'text'
|
||||
};
|
||||
this.chatManager.addMessage(sessionToUse, aiMessage);
|
||||
this.debugLogger.log('CHAT', `Stored AI message in ChatManager for session ${sessionToUse}: ${aiMessage.content.substring(0, 50)}...`);
|
||||
this.broadcastMessageToClients(sessionToUse, aiMessage);
|
||||
this.chatManager.addMessage(actualSessionId, aiMessage);
|
||||
this.debugLogger.log('CHAT', `Stored AI message in ChatManager for session ${actualSessionId}: ${aiMessage.content.substring(0, 50)}...`);
|
||||
this.broadcastMessageToClients(actualSessionId, aiMessage);
|
||||
|
||||
// Emit request state to enable input controls and show waiting indicator
|
||||
this.emit('request-state-change', {
|
||||
requestId,
|
||||
sessionId: sessionToUse,
|
||||
sessionId: actualSessionId,
|
||||
state: 'waiting_for_response',
|
||||
message: params.message,
|
||||
context: params.context,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
this.chatManager.addPendingRequest(sessionToUse, requestId, { ...params, toolName: toolName || 'HumanAgent_Chat' });
|
||||
this.chatManager.addPendingRequest(actualSessionId, requestId, { ...params, toolName: toolName || 'HumanAgent_Chat' });
|
||||
this.requestResolvers.set(requestId, {
|
||||
resolve: (response: string) => {
|
||||
if (timeoutHandle) { clearTimeout(timeoutHandle); }
|
||||
@@ -1747,7 +1946,7 @@ export class McpServer extends EventEmitter {
|
||||
// Emit request completed state to disable input controls and hide waiting indicator
|
||||
this.emit('request-state-change', {
|
||||
requestId,
|
||||
sessionId: sessionToUse,
|
||||
sessionId: actualSessionId,
|
||||
state: 'completed',
|
||||
response: response,
|
||||
timestamp: new Date().toISOString()
|
||||
@@ -1872,38 +2071,12 @@ export class McpServer extends EventEmitter {
|
||||
}
|
||||
|
||||
this.debugLogger.log('INFO', `Session registered: ${sessionId} (${this.activeSessions.size} total sessions)`);
|
||||
|
||||
// Send session registration to web interface only (for web UI tab creation)
|
||||
this.sendToWebInterface('session-registered', { sessionId, totalSessions: this.activeSessions.size });
|
||||
}
|
||||
|
||||
private mapToRegisteredSession(conversationId?: string): string | undefined {
|
||||
if (!conversationId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Check if it's already a registered session ID
|
||||
if (this.activeSessions.has(conversationId)) {
|
||||
return conversationId;
|
||||
}
|
||||
|
||||
// Check if it's a conversation ID we've seen before
|
||||
const mappedSession = this.conversationToSession.get(conversationId);
|
||||
if (mappedSession && this.activeSessions.has(mappedSession)) {
|
||||
this.debugLogger.log('MCP', `Mapped conversation ${conversationId} to session ${mappedSession}`);
|
||||
return mappedSession;
|
||||
}
|
||||
|
||||
// If not found, try to map to the first available registered session
|
||||
// This handles the case where VS Code conversation ID needs to be linked to a web-registered session
|
||||
const activeSessions = Array.from(this.activeSessions);
|
||||
if (activeSessions.length > 0) {
|
||||
const targetSession = activeSessions[0]; // Use first available session
|
||||
this.conversationToSession.set(conversationId, targetSession);
|
||||
this.debugLogger.log('MCP', `Auto-mapped conversation ${conversationId} to session ${targetSession}`);
|
||||
return targetSession;
|
||||
}
|
||||
|
||||
this.debugLogger.log('MCP', `No registered session found for conversation ${conversationId}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
unregisterSession(sessionId: string): void {
|
||||
this.activeSessions.delete(sessionId);
|
||||
@@ -1912,6 +2085,9 @@ export class McpServer extends EventEmitter {
|
||||
this.sessionWorkspacePaths.delete(sessionId);
|
||||
this.sessionMessageSettings.delete(sessionId);
|
||||
this.debugLogger.log('INFO', `Session unregistered and cleaned up: ${sessionId} (${this.activeSessions.size} total sessions)`);
|
||||
|
||||
// Send session unregistration to web interface only (for web UI tab removal)
|
||||
this.sendToWebInterface('session-unregistered', { sessionId, totalSessions: this.activeSessions.size });
|
||||
}
|
||||
|
||||
getActiveSessions(): string[] {
|
||||
@@ -1975,7 +2151,7 @@ export class McpServer extends EventEmitter {
|
||||
// Removed: storeMessage and getSessionMessages wrapper methods - call ChatManager directly
|
||||
|
||||
private broadcastMessageToClients(sessionId: string, message: ChatMessage): void {
|
||||
// Broadcast message to all connected SSE clients
|
||||
// Send message to specific session AND all web interface connections
|
||||
const messageEvent = {
|
||||
type: 'chat_message',
|
||||
sessionId: sessionId,
|
||||
@@ -1990,15 +2166,32 @@ export class McpServer extends EventEmitter {
|
||||
|
||||
const sseData = `data: ${JSON.stringify(messageEvent)}\n\n`;
|
||||
|
||||
// Send to all connected SSE clients (VS Code webviews and web interfaces)
|
||||
for (const connection of this.sseConnections) {
|
||||
// Send to the specific session's SSE connection (VS Code webview)
|
||||
const sessionConnection = this.sseClients.get(sessionId);
|
||||
if (sessionConnection) {
|
||||
try {
|
||||
connection.write(sseData);
|
||||
this.debugLogger.log('CHAT', `Broadcasted message to SSE client for session ${sessionId}`);
|
||||
sessionConnection.write(sseData);
|
||||
this.debugLogger.log('CHAT', `Sent message to VS Code session ${sessionId}`);
|
||||
} catch (error) {
|
||||
this.debugLogger.log('ERROR', 'Failed to broadcast message to SSE client:', error);
|
||||
this.debugLogger.log('ERROR', `Failed to send message to VS Code session ${sessionId}:`, error);
|
||||
// Remove failed connection
|
||||
this.sseConnections.delete(connection);
|
||||
this.sseClients.delete(sessionId);
|
||||
this.sseConnections.delete(sessionConnection);
|
||||
}
|
||||
} else {
|
||||
this.debugLogger.log('WARN', `No VS Code SSE connection found for session ${sessionId}`);
|
||||
}
|
||||
|
||||
// Also send to all web interface connections
|
||||
for (const webConnection of this.webInterfaceConnections) {
|
||||
try {
|
||||
webConnection.write(sseData);
|
||||
this.debugLogger.log('CHAT', `Sent message to web interface for session ${sessionId}`);
|
||||
} catch (error) {
|
||||
this.debugLogger.log('ERROR', `Failed to send message to web interface:`, error);
|
||||
// Remove failed connection
|
||||
this.webInterfaceConnections.delete(webConnection);
|
||||
this.sseConnections.delete(webConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,23 +51,12 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
|
||||
|
||||
private loadNotificationSettings() {
|
||||
try {
|
||||
// Try to load settings from mcp.json
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
||||
if (workspaceRoot) {
|
||||
const mcpConfigPath = `${workspaceRoot}/.vscode/mcp.json`;
|
||||
const fs = require('fs');
|
||||
if (fs.existsSync(mcpConfigPath)) {
|
||||
const mcpConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'));
|
||||
// Check if humanagent-mcp server has notifications settings
|
||||
if (mcpConfig.servers && mcpConfig.servers['humanagent-mcp'] && mcpConfig.servers['humanagent-mcp'].notifications) {
|
||||
const notifications = mcpConfig.servers['humanagent-mcp'].notifications;
|
||||
this.notificationSettings = {
|
||||
enableSound: notifications.enableSound ?? true,
|
||||
enableFlashing: notifications.enableFlashing ?? true
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
// Load settings from VS Code configuration
|
||||
const config = vscode.workspace.getConfiguration('humanagent-mcp');
|
||||
this.notificationSettings = {
|
||||
enableSound: config.get<boolean>('notifications.enableSound', true),
|
||||
enableFlashing: config.get<boolean>('notifications.enableFlashing', true)
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('ChatWebviewProvider: Error loading notification settings:', error);
|
||||
// Use defaults on error
|
||||
@@ -248,18 +237,14 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
const isRegisteredWorkspace = this.mcpConfigManager?.isMcpServerRegistered(false) ?? false;
|
||||
const isRegisteredGlobal = this.mcpConfigManager?.isMcpServerRegistered(true) ?? false;
|
||||
const configType = isRegisteredWorkspace ? 'workspace' : (isRegisteredGlobal ? 'global' : 'none');
|
||||
|
||||
this._view.webview.postMessage({
|
||||
type: 'serverStatus',
|
||||
data: {
|
||||
running: true, // Assume standalone server is running if configured
|
||||
tools: 1, // Default tool count
|
||||
pendingRequests: 0, // Can't get from standalone server easily
|
||||
registered: isRegisteredWorkspace || isRegisteredGlobal,
|
||||
configType: configType
|
||||
registered: true, // Always true with native provider
|
||||
configType: 'native' // Native provider registration
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -488,11 +473,9 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
|
||||
vscode.window.showInformationMessage('MCP Server management not available - using standalone server');
|
||||
break;
|
||||
case 'register':
|
||||
// Use the MCP configuration from the parent command
|
||||
vscode.commands.executeCommand('humanagent-mcp.configureMcp');
|
||||
break;
|
||||
case 'unregister':
|
||||
vscode.commands.executeCommand('humanagent-mcp.configureMcp');
|
||||
// Registration handled automatically by native provider
|
||||
vscode.window.showInformationMessage('HumanAgent MCP registration is handled automatically by the native provider.');
|
||||
break;
|
||||
case 'configure':
|
||||
vscode.commands.executeCommand('humanagent-mcp.configureMcp');
|
||||
@@ -501,6 +484,10 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
|
||||
// Test notification sound by triggering a fake notification
|
||||
await this.displayHumanAgentMessage('🔊 Audio test - this is a test notification sound!', 'Testing audio notifications', 'test-audio');
|
||||
break;
|
||||
case 'requestServerStatus':
|
||||
// Show the same notification popup as the main status command
|
||||
vscode.commands.executeCommand('humanagent-mcp.showStatus');
|
||||
break;
|
||||
case 'overridePrompt':
|
||||
await this.createPromptOverrideFile();
|
||||
break;
|
||||
@@ -850,7 +837,8 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
|
||||
<script>
|
||||
const vscode = acquireVsCodeApi();
|
||||
|
||||
// Set global flag for override file existence
|
||||
// Set session ID and override file flag
|
||||
const sessionId = '${this.workspaceSessionId}';
|
||||
window.overrideFileExists = ${overrideFileExists};
|
||||
|
||||
// Play notification beep sound
|
||||
@@ -955,47 +943,15 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
|
||||
let currentServerStatus = null;
|
||||
|
||||
function getDynamicMenuOptions() {
|
||||
const options = [];
|
||||
// Simplified menu options (no registration needed with native provider)
|
||||
const options = [
|
||||
{ text: '📊 Show Status', action: 'requestServerStatus' },
|
||||
{ text: window.overrideFileExists ? '📁 Recreate Override File' : '📁 Create Override File', action: 'overridePrompt' },
|
||||
{ text: '📝 Name This Chat', action: 'nameSession' },
|
||||
{ text: '🌐 Open Web View', action: 'openWebView' }
|
||||
];
|
||||
|
||||
if (!currentServerStatus) {
|
||||
// Default options when status unknown
|
||||
const defaultOptions = [
|
||||
{ text: '📦 Install Globally', action: 'register' },
|
||||
{ text: '📁 Install in Workspace', action: 'register' },
|
||||
{ text: '📊 Show Status', action: 'requestServerStatus' },
|
||||
{ text: window.overrideFileExists ? '📁 Recreate Override File' : '📁 Create Override File', action: 'overridePrompt' },
|
||||
{ text: '📝 Name This Chat', action: 'nameSession' },
|
||||
{ text: '🌐 Open Web View', action: 'openWebView' }
|
||||
];
|
||||
|
||||
// Check for override file existence even when status unknown
|
||||
if (window.overrideFileExists) {
|
||||
defaultOptions.push({ text: '🔄 Reload Override File', action: 'reloadOverride' });
|
||||
}
|
||||
|
||||
defaultOptions.push({ text: '⚙️ Configure MCP', action: 'configure' });
|
||||
return defaultOptions;
|
||||
}
|
||||
|
||||
// Dynamic options based on current registration status
|
||||
if (currentServerStatus.configType === 'workspace') {
|
||||
options.push({ text: '🗑️ Uninstall from Workspace', action: 'unregister' });
|
||||
options.push({ text: '📦 Install Globally', action: 'register' });
|
||||
} else if (currentServerStatus.configType === 'global') {
|
||||
options.push({ text: '📁 Install in Workspace', action: 'register' });
|
||||
options.push({ text: '🗑️ Uninstall Globally', action: 'unregister' });
|
||||
} else {
|
||||
// Not installed anywhere
|
||||
options.push({ text: '📦 Install Globally', action: 'register' });
|
||||
options.push({ text: '📁 Install in Workspace', action: 'register' });
|
||||
}
|
||||
|
||||
options.push({ text: '📊 Show Status', action: 'requestServerStatus' });
|
||||
options.push({ text: window.overrideFileExists ? '📁 Recreate Override File' : '📁 Create Override File', action: 'overridePrompt' });
|
||||
options.push({ text: '📝 Name This Chat', action: 'nameSession' });
|
||||
options.push({ text: '🌐 Open Web View', action: 'openWebView' });
|
||||
|
||||
// Check for HumanAgentOverride.json file existence (passed from extension)
|
||||
// Check for override file existence
|
||||
if (window.overrideFileExists) {
|
||||
options.push({ text: '🔄 Reload Override File', action: 'reloadOverride' });
|
||||
}
|
||||
@@ -1059,19 +1015,78 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
|
||||
});
|
||||
|
||||
// Set up SSE connection for real-time server events
|
||||
let currentEventSource = null;
|
||||
let connectionInProgress = false;
|
||||
|
||||
function setupSSEConnection() {
|
||||
if (connectionInProgress) {
|
||||
console.log('⚠️ SSE connection already in progress, skipping duplicate attempt');
|
||||
return;
|
||||
}
|
||||
|
||||
connectionInProgress = true;
|
||||
|
||||
try {
|
||||
console.log('Setting up SSE connection to MCP server...');
|
||||
const eventSource = new EventSource('http://localhost:3737/mcp');
|
||||
// Close existing connection if present
|
||||
if (currentEventSource && currentEventSource.readyState !== 2) { // 2 = CLOSED
|
||||
console.log('🔄 Closing existing EventSource before creating new one');
|
||||
currentEventSource.close();
|
||||
}
|
||||
|
||||
console.log('Setting up SSE connection to MCP server for session:', sessionId);
|
||||
const eventSource = new EventSource(\`http://localhost:3737/mcp?sessionId=\${sessionId}\`);
|
||||
currentEventSource = eventSource;
|
||||
|
||||
// Enhanced connection health monitoring
|
||||
let lastHeartbeat = Date.now();
|
||||
let heartbeatTimeout = null;
|
||||
let messageCount = 0;
|
||||
let connectionStartTime = Date.now();
|
||||
|
||||
// Monitor heartbeat to detect stale connections
|
||||
function resetHeartbeatTimeout() {
|
||||
if (heartbeatTimeout) {
|
||||
clearTimeout(heartbeatTimeout);
|
||||
}
|
||||
heartbeatTimeout = setTimeout(() => {
|
||||
console.error('❌ SSE Connection Analysis:');
|
||||
console.error(' - No heartbeat for 25 seconds, EventSource appears stale');
|
||||
console.error(' - Last heartbeat:', new Date(lastHeartbeat).toISOString());
|
||||
console.error(' - Connection duration:', Math.round((Date.now() - connectionStartTime) / 1000), 'seconds');
|
||||
console.error(' - Messages received:', messageCount);
|
||||
console.error(' - EventSource readyState:', eventSource.readyState);
|
||||
console.error(' - Reconnecting...');
|
||||
eventSource.close();
|
||||
connectionInProgress = false;
|
||||
setTimeout(setupSSEConnection, 1000);
|
||||
}, 25000); // Timeout after 25 seconds (2.5x heartbeat interval)
|
||||
}
|
||||
|
||||
eventSource.onopen = function(event) {
|
||||
console.log('SSE connection opened:', event);
|
||||
console.log('✅ SSE connection opened for session:', sessionId);
|
||||
console.log(' EventSource readyState:', eventSource.readyState);
|
||||
console.log(' Connection time:', new Date().toISOString());
|
||||
lastHeartbeat = Date.now();
|
||||
connectionStartTime = Date.now();
|
||||
messageCount = 0;
|
||||
connectionInProgress = false; // Connection successful, allow future connections
|
||||
resetHeartbeatTimeout();
|
||||
};
|
||||
|
||||
eventSource.onmessage = function(event) {
|
||||
try {
|
||||
messageCount++;
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('SSE event received:', data);
|
||||
|
||||
// Handle heartbeat for connection monitoring
|
||||
if (data.type === 'heartbeat') {
|
||||
lastHeartbeat = Date.now();
|
||||
resetHeartbeatTimeout();
|
||||
console.log('💓 Heartbeat received at', new Date().toISOString(), '(msg #' + messageCount + ')');
|
||||
return; // Don't log heartbeats further
|
||||
}
|
||||
|
||||
console.log('📨 SSE event received (msg #' + messageCount + '):', data);
|
||||
|
||||
if (data.type === 'request-state-change') {
|
||||
handleRequestStateChange(data.data);
|
||||
@@ -1087,13 +1102,30 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
|
||||
};
|
||||
|
||||
eventSource.onerror = function(error) {
|
||||
console.error('SSE connection error:', error);
|
||||
// Try to reconnect after 5 seconds
|
||||
console.error('❌ SSE connection error detected:');
|
||||
console.error(' Error object:', error);
|
||||
console.error(' EventSource readyState:', eventSource.readyState);
|
||||
console.error(' Connection duration:', Math.round((Date.now() - connectionStartTime) / 1000), 'seconds');
|
||||
console.error(' Messages received before error:', messageCount);
|
||||
console.error(' Last heartbeat:', new Date(lastHeartbeat).toISOString());
|
||||
|
||||
if (heartbeatTimeout) {
|
||||
clearTimeout(heartbeatTimeout);
|
||||
}
|
||||
|
||||
// Log readyState meaning
|
||||
const stateNames = ['CONNECTING', 'OPEN', 'CLOSED'];
|
||||
console.error(' EventSource state:', stateNames[eventSource.readyState] || 'UNKNOWN');
|
||||
|
||||
// Reset connection state and try to reconnect after 5 seconds
|
||||
connectionInProgress = false;
|
||||
console.log('🔄 Reconnecting SSE in 5 seconds...');
|
||||
setTimeout(setupSSEConnection, 5000);
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to setup SSE connection:', error);
|
||||
connectionInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user