Skip to content

Commit 3292de9

Browse files
committed
fix(v1.2.4): Fix critical session ID mismatch and SSE transport issues
CRITICAL FIXES: - Session ID mismatch: Use transport.sessionId consistently (was creating custom sessionId but storing with transport's ID) - Store transport BEFORE connecting to prevent race condition - Remove manual keep-alive interference (SSEServerTransport handles internally) - Remove duplicate express.json() middleware Root Cause: v1.2.1-1.2.3 "bugfixes" exposed pre-existing session ID mismatch bug. SSEServerTransport generates its own UUID internally, our custom sessionId was orphaned. Impact: Should resolve connection regression from v1.2.3 (0% → expected 100% test success) Files changed: - src/index.js: Session ID consistency, cleanup race condition fix, keep-alive removal - package.json: Version bump to 1.2.4
1 parent e32454d commit 3292de9

File tree

2 files changed

+28
-41
lines changed

2 files changed

+28
-41
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tsdav-mcp-server",
3-
"version": "1.2.3",
3+
"version": "1.2.4",
44
"description": "Model Context Protocol (MCP) server for CalDAV/CardDAV/VTODO integration via tsdav - enables AI systems to manage calendars, contacts, and tasks",
55
"type": "module",
66
"main": "src/index.js",

src/index.js

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -237,80 +237,67 @@ app.get('/health', (req, res) => {
237237
* SSE endpoint - GET /sse
238238
*/
239239
app.get('/sse', authenticateBearer, async (req, res) => {
240-
const sessionId = `session-${Date.now()}-${Math.random().toString(36).substring(7)}`;
241-
const sessionLogger = createSessionLogger(sessionId);
242-
243-
sessionLogger.info({
244-
ip: req.ip,
245-
userAgent: req.get('user-agent') || 'unknown',
246-
}, 'New SSE connection established');
247-
248240
try {
249-
// Set SSE headers
241+
// Set SSE headers FIRST
250242
res.setHeader('Content-Type', 'text/event-stream');
251243
res.setHeader('Cache-Control', 'no-cache');
252244
res.setHeader('Connection', 'keep-alive');
253245
res.setHeader('X-Accel-Buffering', 'no');
246+
247+
// Create SSE transport (this generates the sessionId internally)
248+
const transport = new SSEServerTransport('/messages', res);
249+
250+
// Use transport's sessionId consistently everywhere
251+
const sessionId = transport.sessionId;
252+
const sessionLogger = createSessionLogger(sessionId);
253+
254+
sessionLogger.info({
255+
ip: req.ip,
256+
userAgent: req.get('user-agent') || 'unknown',
257+
sessionId: sessionId,
258+
}, 'New SSE connection established');
259+
254260
sessionLogger.debug('SSE headers set');
255261

262+
// Store transport BEFORE connecting (prevents race condition)
263+
transports[sessionId] = transport;
264+
updateSessionActivity(sessionId);
265+
sessionLogger.debug('Transport stored');
266+
256267
// Create MCP server for this session
257268
sessionLogger.debug('Creating MCP server');
258269
const mcpServer = createMCPServer(sessionId);
259270

260-
// Create SSE transport
261-
sessionLogger.debug('Creating SSE transport');
262-
const transport = new SSEServerTransport('/messages', res);
263-
264-
// Store transport with its sessionId (from the transport itself)
265-
sessionLogger.debug({ transportSessionId: transport.sessionId }, 'Transport created');
266-
transports[transport.sessionId] = transport;
267-
updateSessionActivity(transport.sessionId);
268-
269271
// Connect MCP server to transport
270272
sessionLogger.debug('Connecting MCP server to transport');
271273
await mcpServer.connect(transport);
272274
sessionLogger.info('MCP server connected successfully, session active');
273275

274-
// Keep connection alive
275-
const keepAliveInterval = setInterval(() => {
276-
if (!res.writableEnded) {
277-
res.write(': keepalive\n\n');
278-
sessionLogger.debug('Keepalive sent');
279-
} else {
280-
clearInterval(keepAliveInterval);
281-
}
282-
}, 30000); // Every 30 seconds
283-
284276
// Cleanup on disconnect
285277
req.on('close', () => {
286-
sessionLogger.info({ transportSessionId: transport.sessionId }, 'SSE connection closed by client');
287-
clearInterval(keepAliveInterval);
288-
delete transports[transport.sessionId];
289-
sessionActivity.delete(transport.sessionId);
278+
sessionLogger.info('SSE connection closed by client');
279+
delete transports[sessionId];
280+
sessionActivity.delete(sessionId);
290281
});
291282

292283
req.on('error', (error) => {
293284
sessionLogger.error({
294285
error: error.message,
295286
code: error.code,
296-
transportSessionId: transport.sessionId,
297287
}, 'SSE connection error');
298-
clearInterval(keepAliveInterval);
299-
delete transports[transport.sessionId];
300-
sessionActivity.delete(transport.sessionId);
288+
delete transports[sessionId];
289+
sessionActivity.delete(sessionId);
301290
});
302291

303292
res.on('finish', () => {
304293
sessionLogger.debug('Response finished');
305-
clearInterval(keepAliveInterval);
306294
});
307295

308296
res.on('close', () => {
309297
sessionLogger.debug('Response closed');
310-
clearInterval(keepAliveInterval);
311298
});
312299
} catch (error) {
313-
sessionLogger.error({ error: error.message, stack: error.stack }, 'Error setting up SSE connection');
300+
logger.error({ error: error.message, stack: error.stack }, 'Error setting up SSE connection');
314301
if (!res.headersSent) {
315302
const errorResponse = createHTTPErrorResponse(error);
316303
res.status(errorResponse.statusCode).json(errorResponse.body);
@@ -322,7 +309,7 @@ app.get('/sse', authenticateBearer, async (req, res) => {
322309
* Message endpoint - POST /messages
323310
* Used by SSE clients to send messages back to the server
324311
*/
325-
app.post('/messages', authenticateBearer, express.json(), async (req, res) => {
312+
app.post('/messages', authenticateBearer, async (req, res) => {
326313
const sessionId = req.query.sessionId;
327314
const requestLogger = createSessionLogger(sessionId || 'unknown');
328315

0 commit comments

Comments
 (0)