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:
B Harper
2025-10-26 15:36:26 +11:00
parent 2de7ad2db1
commit 60ea857b54
10 changed files with 585 additions and 1604 deletions
-644
View File
@@ -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\"}"
-8
View File
@@ -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": []
-314
View File
@@ -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
View File
@@ -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.
+10
View File
@@ -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"
}
}
}
+39
View File
@@ -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
View File
@@ -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}`);
}
}
}
+4 -14
View File
@@ -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
View File
@@ -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);
}
}
}
+106 -74
View File
@@ -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;
}
}