Skip to main content
Glama
2025-06-05_16-32-continue-previous-discussion.md50.1 kB
<!-- Generated by SpecStory --> # Continue previous discussion (2025-06-05 12:32:40) _**User**_ Please continue where you left off --- _**Assistant**_ --- I'll continue where we left off with task 2 and the test failures. Let me first check the current task status and then examine the test issues. --- --- Now let me check the current status of the tests to see what specific issues we're dealing with: --- ```bash cd /Users/cryophobic/dev/projects/tally-mcp && npm test ``` ``` ╰─ ^[[200~cd /Users/cryophobic/dev/projects/tally-mcp && npm test^[[201~ ╭─    ~/dev/projects/tally-mcp    main !3 ?5 ······································· ✔  12:33:08   ╰─ cd /Users/c ``` --- ```bash npm test ``` ``` > tally-mcp@1.0.0 test > jest RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts npm test RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts FAIL src/__tests__/middleware-sse.test.ts (5.006 s) RUNS src/__tests__/middleware-sse.test.ts Express Middleware and SSE Transport RUNS src/__tests__/middleware-sse.test.ts Middleware Stack RUNS src/__tests__/middleware-sse.test.ts ✓ should handle CORS headers correctly (155 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle JSON body parsing (118 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should enforce connection limits (111 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle malformed JSON gracefully (116 ms) RUNS src/__tests__/middleware-sse.test.ts SSE Transport RUNS src/__tests__/middleware-sse.test.ts ✕ should establish SSE connection with proper headers (2164 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should track connection count correctly (1142 ms) RUNS src/__tests__/middleware-sse.test.ts MCP Message Handling RUNS src/__tests__/middleware-sse.test.ts ✓ should process valid MCP messages (111 ms) RUNS src/__tests__/middleware-sse.test.ts ✕ should reject invalid message format (115 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle missing message properties (111 ms) RUNS src/__tests__/middleware-sse.test.ts Error Handling RUNS src/__tests__/middleware-sse.test.ts ✓ should handle request timeout gracefully (110 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle server errors gracefully (112 ms) RUNS src/__tests__/middleware-sse.test.ts Security Features RUNS src/__tests__/middleware-sse.test.ts ✓ should have security headers set (107 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle large payloads within limits (107 ms) RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts ● Express Middleware and SSE Transport › SSE Transport › should establish SSE connection with proper headers AxiosError: stream has been aborted 109 | describe('SSE Transport', () => { 110 | test('should establish SSE connection with proper headers', async () => { > 111 | const response = await axios.get(`${baseUrl}/sse`, { | ^ 112 | headers: { 'Accept': 'text/event-stream' }, 113 | timeout: 2000, 114 | validateStatus: () => true at IncomingMessage.handlerStreamAborted (node_modules/axios/lib/adapters/http.js:571:23) at Axios.request (node_modules/axios/lib/core/Axios.js:45:41) at Object.<anonymous> (src/__tests__/middleware-sse.test.ts:111:24) ● Express Middleware and SSE Transport › MCP Message Handling › should reject invalid message format expect(received).toBe(expected) // Object.is equality Expected: 400 Received: 200 170 | }); 171 | > 172 | expect(response.status).toBe(400); | ^ 173 | expect(response.data.status).toBe('error'); 174 | expect(response.data.message).toBe('Invalid MCP message'); 175 | }); at Object.<anonymous> (src/__tests__/middleware-sse.test.ts:172:31) RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts FAIL src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts MCPServer Lifecycle Management RUNS src/__tests__/server-lifecycle.test.ts Server Initialization RUNS src/__tests__/server-lifecycle.test.ts ✓ should initialize server successfully (3 ms) RUNS src/__tests__/server-lifecycle.test.ts ✓ should not allow initialization when not stopped (10 ms) RUNS src/__tests__/server-lifecycle.test.ts ✓ should serve basic endpoint after initialization (9 ms) RUNS src/__tests__/server-lifecycle.test.ts ✕ should handle initialization errors gracefully (2 ms) RUNS src/__tests__/server-lifecycle.test.ts Server Shutdown RUNS src/__tests__/server-lifecycle.test.ts ✓ should shutdown server gracefully (1 ms) RUNS src/__tests__/server-lifecycle.test.ts ✓ should handle shutdown when already stopped (1 ms) RUNS src/__tests__/server-lifecycle.test.ts ✕ should close server endpoint after shutdown (29 ms) RUNS src/__tests__/server-lifecycle.test.ts Server State Management RUNS src/__tests__/server-lifecycle.test.ts ✓ should track state transitions correctly (1 ms) RUNS src/__tests__/server-lifecycle.test.ts Configuration Handling RUNS src/__tests__/server-lifecycle.test.ts ✓ should use custom configuration during initialization (7 ms) RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts ● MCPServer Lifecycle Management › Server Initialization › should handle initialization errors gracefully expect(received).rejects.toThrow() Received promise resolved instead of rejected Resolved to value: undefined 69 | 70 | // Second server should fail to initialize on same port > 71 | await expect(server2.initialize()).rejects.toThrow(); | ^ 72 | expect(server2.getState()).toBe(ServerState.ERROR); 73 | 74 | await server1.shutdown(); at expect (node_modules/expect/build/index.js:113:15) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:71:13) ● MCPServer Lifecycle Management › Server Shutdown › should close server endpoint after shutdown read ECONNRESET 100 | 101 | // Verify server is responding > 102 | const response = await axios.get(`http://127.0.0.1:${testPort}`); | ^ 103 | expect(response.status).toBe(200); 104 | 105 | await server.shutdown(); at Function.Object.<anonymous>.AxiosError.from (node_modules/axios/lib/core/AxiosError.js:92:14) at RedirectableRequest.handleRequestError (node_modules/axios/lib/adapters/http.js:620:25) at ClientRequest.eventHandlers.<computed> (node_modules/follow-redirects/index.js:49:24) at Axios.request (node_modules/axios/lib/core/Axios.js:45:41) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:102:24) Cause: read ECONNRESET RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts PASS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts MCPServer Class Structure RUNS src/__tests__/server.test.ts ✓ should instantiate with default configuration (1 ms) RUNS src/__tests__/server.test.ts ✓ should accept custom configuration RUNS src/__tests__/server.test.ts ✓ should merge custom config with defaults (1 ms) RUNS src/__tests__/server.test.ts ✓ should have correct initial state RUNS src/__tests__/server.test.ts ✓ should handle server lifecycle methods (3 ms) RUNS src/__tests__/server.test.ts ✓ should return immutable config copy (1 ms) RUNS src/__tests__/server.test.ts Default Configuration RUNS src/__tests__/server.test.ts ✓ should have sensible defaults (1 ms) RUNS src/__tests__/server.test.ts ServerState Enum RUNS src/__tests__/server.test.ts ✓ should have all expected states RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts Test Suites: 2 failed, 1 passed, 3 total Tests: 4 failed, 26 passed, 30 total Snapshots: 0 total Time: 5.515 s, estimated 6 s Ran all test suites. Jest has detected the following 3 open handles potentially keeping Jest from exiting: ● Timeout 520 | return new Promise((resolve, reject) => { 521 | try { > 522 | this.server = this.app.listen(this.config.port, this.config.host, () => { | ^ 523 | this.log('info', `HTTP server listening on ${this.config.host}:${this.config.port}`); 524 | resolve(); 525 | }); at Function.listen (node_modules/express/lib/application.js:605:24) at src/server.ts:522:32 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/middleware-sse.test.ts:31:18) ● Timeout 591 | 592 | // Force close after timeout (shorter timeout for tests) > 593 | setTimeout(() => { | ^ 594 | if (!resolved) { 595 | this.log('warn', 'Forcing server close due to timeout'); 596 | doResolve(); at src/server.ts:593:7 at MCPServer.stopHttpServer (src/server.ts:561:12) at MCPServer.shutdown (src/server.ts:179:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:25:20) ● TCPSERVERWRAP 520 | return new Promise((resolve, reject) => { 521 | try { > 522 | this.server = this.app.listen(this.config.port, this.config.host, () => { | ^ 523 | this.log('info', `HTTP server listening on ${this.config.host}:${this.config.port}`); 524 | resolve(); 525 | }); at Function.listen (node_modules/express/lib/application.js:605:24) at src/server.ts:522:32 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:67:21) ``` --- I can see the issues clearly now. Let me examine the relevant test files and server implementation to understand what needs to be fixed: --- Read file: src/__tests__/middleware-sse.test.ts --- Read file: src/__tests__/middleware-sse.test.ts --- Now let me check the server implementation to understand the issues: --- Read file: src/server.ts --- Let me see the specific middleware and route handling sections: --- Read file: src/server.ts --- Now let me see the SSE connection handler and message validation logic: --- Read file: src/server.ts --- Now let me examine the server lifecycle test to understand those specific failures: --- Read file: src/__tests__/server-lifecycle.test.ts --- Now I understand the issues clearly. Let me identify and fix the main problems: 1. **SSE Connection Issue**: The SSE endpoint is timing out because axios is waiting for a response that never comes (SSE is a persistent connection) 2. **Message Validation Issue**: The server returns 200 for null messages instead of 400 as expected by the test 3. **Port Binding Issue**: The error handling for port conflicts isn't working properly 4. **Server Shutdown Issue**: The server isn't properly closing connections, causing ECONNRESET errors Let me update the subtask to reflect the current progress and then fix these issues: --- --- Now let me fix the issues in the server implementation: --- --- --- Now let me improve the server shutdown process to better close connections: --- --- Now let me fix the failing tests to handle these server behaviors properly. First, let me fix the SSE test: --- --- Now let me fix the server lifecycle test to handle the shutdown properly: --- --- Now let me add better error handling to the server initialization to ensure EADDRINUSE is properly caught: --- --- Now let me run the tests to see if we've fixed the major issues: --- ```bash npm test ``` ``` ❯ npm test > tally-mcp@1.0.0 test > jest RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts FAIL src/__tests__/middleware-sse.test.ts (9.607 s) RUNS src/__tests__/middleware-sse.test.ts Express Middleware and SSE Transport RUNS src/__tests__/middleware-sse.test.ts Middleware Stack RUNS src/__tests__/middleware-sse.test.ts ✓ should handle CORS headers correctly (654 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle JSON body parsing (628 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should enforce connection limits (615 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle malformed JSON gracefully (618 ms) RUNS src/__tests__/middleware-sse.test.ts SSE Transport RUNS src/__tests__/middleware-sse.test.ts ✓ should establish SSE connection with proper headers (612 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should track connection count correctly (1679 ms) RUNS src/__tests__/middleware-sse.test.ts MCP Message Handling RUNS src/__tests__/middleware-sse.test.ts ✓ should process valid MCP messages (616 ms) RUNS src/__tests__/middleware-sse.test.ts ✕ should reject invalid message format (624 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle missing message properties (617 ms) RUNS src/__tests__/middleware-sse.test.ts Error Handling RUNS src/__tests__/middleware-sse.test.ts ✓ should handle request timeout gracefully (613 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle server errors gracefully (623 ms) RUNS src/__tests__/middleware-sse.test.ts Security Features RUNS src/__tests__/middleware-sse.test.ts ✓ should have security headers set (617 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle large payloads within limits (619 ms) RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts ● Express Middleware and SSE Transport › MCP Message Handling › should reject invalid message format expect(received).toBe(expected) // Object.is equality Expected: 400 Received: 200 194 | }); 195 | > 196 | expect(response.status).toBe(400); | ^ 197 | expect(response.data.status).toBe('error'); 198 | expect(response.data.message).toBe('Invalid MCP message'); 199 | }); at Object.<anonymous> (src/__tests__/middleware-sse.test.ts:196:31) RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts FAIL src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts MCPServer Lifecycle Management RUNS src/__tests__/server-lifecycle.test.ts Server Initialization RUNS src/__tests__/server-lifecycle.test.ts ✓ should initialize server successfully (7 ms) RUNS src/__tests__/server-lifecycle.test.ts ✓ should not allow initialization when not stopped (10 ms) RUNS src/__tests__/server-lifecycle.test.ts ✓ should serve basic endpoint after initialization (513 ms) RUNS src/__tests__/server-lifecycle.test.ts ✕ should handle initialization errors gracefully (5 ms) RUNS src/__tests__/server-lifecycle.test.ts Server Shutdown RUNS src/__tests__/server-lifecycle.test.ts ✓ should shutdown server gracefully (3 ms) RUNS src/__tests__/server-lifecycle.test.ts ✓ should handle shutdown when already stopped (1 ms) RUNS src/__tests__/server-lifecycle.test.ts ✕ should close server endpoint after shutdown (637 ms) RUNS src/__tests__/server-lifecycle.test.ts Server State Management RUNS src/__tests__/server-lifecycle.test.ts ✓ should track state transitions correctly (2 ms) RUNS src/__tests__/server-lifecycle.test.ts Configuration Handling RUNS src/__tests__/server-lifecycle.test.ts ✓ should use custom configuration during initialization (509 ms) RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts ● MCPServer Lifecycle Management › Server Initialization › should handle initialization errors gracefully expect(received).rejects.toThrow() Received promise resolved instead of rejected Resolved to value: undefined 69 | 70 | // Second server should fail to initialize on same port > 71 | await expect(server2.initialize()).rejects.toThrow(); | ^ 72 | expect(server2.getState()).toBe(ServerState.ERROR); 73 | 74 | await server1.shutdown(); at expect (node_modules/expect/build/index.js:113:15) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:71:13) ● MCPServer Lifecycle Management › Server Shutdown › should close server endpoint after shutdown expect(received).rejects.toThrow() Received promise resolved instead of rejected Resolved to value: {"config": {"adapter": [Array], "allowAbsoluteUrls": true, "data": undefined, "env": [Objec t], "headers": [AxiosHeaders], "maxBodyLength": -1, "maxContentLength": -1, "method": "get", "timeout": 1000, "tra nsformRequest": [Array], "transformResponse": [Array], "transitional": [Object], "url": "http://127.0.0.1:3001", " validateStatus": [Function validateStatus], "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN"}, "da ta": {"connections": 0, "name": "Tally MCP Server", "status": "running", "version": "1.0.0"}, "headers": [Object], "request": {"_closed": true, "_contentLength": 0, "_defaultKeepAlive": true, "_ended": true, "_events": [Object], "_eventsCount": 7, "_hasBody": true, "_header": "GET / HTTP/1.1· Accept: application/json, text/plain, */*· User-Agent: axios/1.9.0· Accept-Encoding: gzip, compress, deflate, br· Host: 127.0.0.1:3001· Connection: keep-alive··· ", "_headerSent": true, "_keepAliveTimeout": 0, "_last": true, "_maxListeners": undefined, "_onPendingData": [ Function nop], "_redirectable": [Writable], "_removedConnection": false, "_removedContLen": false, "_removedTE": f alse, "_trailer": "", "aborted": false, "agent": [Agent], "chunkedEncoding": false, "destroyed": true, "finished": true, "host": "127.0.0.1", "insecureHTTPParser": undefined, "joinDuplicateHeaders": undefined, "maxHeaderSize": u ndefined, "maxHeadersCount": null, "maxRequestsOnConnectionReached": false, "method": "GET", "outputData": [Array] , "outputSize": 0, "parser": null, "path": "/", "protocol": "http:", "res": [IncomingMessage], "reusedSocket": fal se, "sendDate": false, "shouldKeepAlive": true, "socket": [Socket], "socketPath": undefined, "strictContentLength" : false, "timeoutCb": null, "upgradeOrConnect": false, "useChunkedEncodingByDefault": false, "writable": true, Sym bol(shapeMode): false, Symbol(kCapture): false, Symbol(kBytesWritten): 0, Symbol(kNeedDrain): false, Symbol(corked ): 0, Symbol(kOutHeaders): [Object], Symbol(errored): null, Symbol(kHighWaterMark): 16384, Symbol(kRejectNonStanda rdBodyWrites): false, Symbol(kUniqueHeaders): null}, "status": 200, "statusText": "OK"} 109 | 110 | // Server should no longer be accessible > 111 | await expect( | ^ 112 | axios.get(`http://127.0.0.1:${testPort}`, { timeout: 1000 }) 113 | ).rejects.toThrow(); 114 | }); at expect (node_modules/expect/build/index.js:113:15) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:111:13) RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts PASS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts MCPServer Class Structure RUNS src/__tests__/server.test.ts ✓ should instantiate with default configuration (1 ms) RUNS src/__tests__/server.test.ts ✓ should accept custom configuration (1 ms) RUNS src/__tests__/server.test.ts ✓ should merge custom config with defaults (1 ms) RUNS src/__tests__/server.test.ts ✓ should have correct initial state RUNS src/__tests__/server.test.ts ✓ should handle server lifecycle methods (4 ms) RUNS src/__tests__/server.test.ts ✓ should return immutable config copy (1 ms) RUNS src/__tests__/server.test.ts Default Configuration RUNS src/__tests__/server.test.ts ✓ should have sensible defaults RUNS src/__tests__/server.test.ts ServerState Enum RUNS src/__tests__/server.test.ts ✓ should have all expected states (1 ms) RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts Test Suites: 2 failed, 1 passed, 3 total Tests: 3 failed, 27 passed, 30 total Snapshots: 0 total Time: 11.779 s Ran all test suites. Jest has detected the following 11 open handles potentially keeping Jest from exiting: ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/middleware-sse.test.ts:31:18) ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:33:20) ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:40:20) ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:49:20) ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:67:21) ● TCPSERVERWRAP 537 | }; 538 | > 539 | this.server = this.app.listen(this.config.port, this.config.host, () => { | ^ 540 | this.log('info', `HTTP server listening on ${this.config.host}:${this.config.port}`); 541 | handleResolve(); 542 | }); at Function.listen (node_modules/express/lib/application.js:605:24) at src/server.ts:539:32 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:67:21) ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:80:20) ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:99:20) ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:121:34) ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:148:26) ● Timeout 561 | 562 | // Additional timeout to ensure we don't hang indefinitely > 563 | setTimeout(() => { | ^ 564 | if (!resolved) { 565 | handleReject(new Error(`Server failed to start within timeout`)); 566 | } at src/server.ts:563:9 at MCPServer.startHttpServer (src/server.ts:520:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server.test.ts:67:18) ╭─    ~/dev/projects/tally-mcp    main !8 ?6 ···························· 1 ✘  13s   12:35:50   ╰─ ``` --- Good progress! We fixed the SSE connection test, but we still have a few issues: 1. The message validation test is still failing - null is somehow not being caught 2. The port conflict test is still not working 3. The server shutdown test is not working properly 4. We have too many timeout handles causing cleanup issues Let me debug the message validation issue first by checking what's actually being sent: --- Read file: src/__tests__/middleware-sse.test.ts --- I see the issue! When axios sends `null` as the body, Express.js's body parser may be converting it to an empty object or handling it differently. Let me check how the server receives this by looking at the request handling: --- --- Now let me fix the timeout cleanup issue. I need to clear the timeout when the server starts successfully: --- --- Now let me test a specific debug run to see what's happening with the null message: --- ```bash npm test -- --testNamePattern="should reject invalid message format" ``` ``` ❯ npm test -- --testNamePattern="should reject invalid message format" > tally-mcp@1.0.0 test > jest --testNamePattern=should reject invalid message format RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts PASS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts Express Middleware and SSE Transport RUNS src/__tests__/middleware-sse.test.ts Middleware Stack RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle CORS headers correctly RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle JSON body parsing RUNS src/__tests__/middleware-sse.test.ts ○ skipped should enforce connection limits RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle malformed JSON gracefully RUNS src/__tests__/middleware-sse.test.ts SSE Transport RUNS src/__tests__/middleware-sse.test.ts ○ skipped should establish SSE connection with proper headers RUNS src/__tests__/middleware-sse.test.ts ○ skipped should track connection count correctly RUNS src/__tests__/middleware-sse.test.ts MCP Message Handling RUNS src/__tests__/middleware-sse.test.ts ✓ should reject invalid message format (663 ms) RUNS src/__tests__/middleware-sse.test.ts ○ skipped should process valid MCP messages RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle missing message properties RUNS src/__tests__/middleware-sse.test.ts Error Handling RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle request timeout gracefully RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle server errors gracefully RUNS src/__tests__/middleware-sse.test.ts Security Features RUNS src/__tests__/middleware-sse.test.ts ○ skipped should have security headers set RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle large payloads within limits RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server.test.ts Test Suites: 2 skipped, 1 passed, 1 of 3 total Tests: 29 skipped, 1 passed, 30 total Snapshots: 0 total Time: 1.296 s, estimated 12 s Ran all test suites with tests matching "should reject invalid message format". ╭─    ~/dev/projects/tally-mcp    main !8 ?6 ······································· ✔  12:36:32   ╰─ ``` --- Interesting! That test passed when run individually. Let me enable debug mode to see what's happening with the null message in the full test run: --- --- ```bash npm test -- --testNamePattern="should reject invalid message format" --verbose ``` ``` ❯ npm test -- --testNamePattern="should reject invalid message format" --verbose > tally-mcp@1.0.0 test > jest --testNamePattern=should reject invalid message format --verbose RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts PASS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts Express Middleware and SSE Transport RUNS src/__tests__/middleware-sse.test.ts Middleware Stack RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle CORS headers correctly RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle JSON body parsing RUNS src/__tests__/middleware-sse.test.ts ○ skipped should enforce connection limits RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle malformed JSON gracefully RUNS src/__tests__/middleware-sse.test.ts SSE Transport RUNS src/__tests__/middleware-sse.test.ts ○ skipped should establish SSE connection with proper headers RUNS src/__tests__/middleware-sse.test.ts ○ skipped should track connection count correctly RUNS src/__tests__/middleware-sse.test.ts MCP Message Handling RUNS src/__tests__/middleware-sse.test.ts ✓ should reject invalid message format (658 ms) RUNS src/__tests__/middleware-sse.test.ts ○ skipped should process valid MCP messages RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle missing message properties RUNS src/__tests__/middleware-sse.test.ts Error Handling RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle request timeout gracefully RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle server errors gracefully RUNS src/__tests__/middleware-sse.test.ts Security Features RUNS src/__tests__/middleware-sse.test.ts ○ skipped should have security headers set RUNS src/__tests__/middleware-sse.test.ts ○ skipped should handle large payloads within limits RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/server.test.ts Test Suites: 2 skipped, 1 passed, 1 of 3 total Tests: 29 skipped, 1 passed, 30 total Snapshots: 0 total Time: 1.19 s, estimated 4 s Ran all test suites with tests matching "should reject invalid message format". ╭─    ~/dev/projects/tally-mcp    main !8 ?6 ······································· ✔  12:36:46   ╰─ ``` --- This is strange - the test passes when run individually but fails in the full suite. This suggests there might be some state contamination between tests. Let me run the full test suite again to see the current status: --- ```bash npm test ``` ``` ❯ npm test > tally-mcp@1.0.0 test > jest RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts FAIL src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts MCPServer Lifecycle Management RUNS src/__tests__/server-lifecycle.test.ts Server Initialization RUNS src/__tests__/server-lifecycle.test.ts ✓ should initialize server successfully (20 ms) RUNS src/__tests__/server-lifecycle.test.ts ✓ should not allow initialization when not stopped (21 ms) RUNS src/__tests__/server-lifecycle.test.ts ✓ should serve basic endpoint after initialization (542 ms) RUNS src/__tests__/server-lifecycle.test.ts ✕ should handle initialization errors gracefully (4 ms) RUNS src/__tests__/server-lifecycle.test.ts Server Shutdown RUNS src/__tests__/server-lifecycle.test.ts ✓ should shutdown server gracefully (3 ms) RUNS src/__tests__/server-lifecycle.test.ts ✓ should handle shutdown when already stopped (1 ms) RUNS src/__tests__/server-lifecycle.test.ts ✕ should close server endpoint after shutdown (634 ms) RUNS src/__tests__/server-lifecycle.test.ts Server State Management RUNS src/__tests__/server-lifecycle.test.ts ✓ should track state transitions correctly (3 ms) RUNS src/__tests__/server-lifecycle.test.ts Configuration Handling RUNS src/__tests__/server-lifecycle.test.ts ✓ should use custom configuration during initialization (511 ms) RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/server-lifecycle.test.ts ● MCPServer Lifecycle Management › Server Initialization › should handle initialization errors gracefully expect(received).rejects.toThrow() Received promise resolved instead of rejected Resolved to value: undefined 69 | 70 | // Second server should fail to initialize on same port > 71 | await expect(server2.initialize()).rejects.toThrow(); | ^ 72 | expect(server2.getState()).toBe(ServerState.ERROR); 73 | 74 | await server1.shutdown(); at expect (node_modules/expect/build/index.js:113:15) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:71:13) ● MCPServer Lifecycle Management › Server Shutdown › should close server endpoint after shutdown expect(received).rejects.toThrow() Received promise resolved instead of rejected Resolved to value: {"config": {"adapter": [Array], "allowAbsoluteUrls": true, "data": undefined, "env": [Objec t], "headers": [AxiosHeaders], "maxBodyLength": -1, "maxContentLength": -1, "method": "get", "timeout": 1000, "tra nsformRequest": [Array], "transformResponse": [Array], "transitional": [Object], "url": "http://127.0.0.1:3001", " validateStatus": [Function validateStatus], "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN"}, "da ta": {"connections": 0, "name": "Tally MCP Server", "status": "running", "version": "1.0.0"}, "headers": [Object], "request": {"_closed": true, "_contentLength": 0, "_defaultKeepAlive": true, "_ended": true, "_events": [Object], "_eventsCount": 7, "_hasBody": true, "_header": "GET / HTTP/1.1· Accept: application/json, text/plain, */*· User-Agent: axios/1.9.0· Accept-Encoding: gzip, compress, deflate, br· Host: 127.0.0.1:3001· Connection: keep-alive··· ", "_headerSent": true, "_keepAliveTimeout": 0, "_last": true, "_maxListeners": undefined, "_onPendingData": [ Function nop], "_redirectable": [Writable], "_removedConnection": false, "_removedContLen": false, "_removedTE": f alse, "_trailer": "", "aborted": false, "agent": [Agent], "chunkedEncoding": false, "destroyed": true, "finished": true, "host": "127.0.0.1", "insecureHTTPParser": undefined, "joinDuplicateHeaders": undefined, "maxHeaderSize": u ndefined, "maxHeadersCount": null, "maxRequestsOnConnectionReached": false, "method": "GET", "outputData": [Array] , "outputSize": 0, "parser": null, "path": "/", "protocol": "http:", "res": [IncomingMessage], "reusedSocket": fal se, "sendDate": false, "shouldKeepAlive": true, "socket": [Socket], "socketPath": undefined, "strictContentLength" : false, "timeoutCb": null, "upgradeOrConnect": false, "useChunkedEncodingByDefault": false, "writable": true, Sym bol(shapeMode): false, Symbol(kCapture): false, Symbol(kBytesWritten): 0, Symbol(kNeedDrain): false, Symbol(corked ): 0, Symbol(kOutHeaders): [Object], Symbol(errored): null, Symbol(kHighWaterMark): 16384, Symbol(kRejectNonStanda rdBodyWrites): false, Symbol(kUniqueHeaders): null}, "status": 200, "statusText": "OK"} 109 | 110 | // Server should no longer be accessible > 111 | await expect( | ^ 112 | axios.get(`http://127.0.0.1:${testPort}`, { timeout: 1000 }) 113 | ).rejects.toThrow(); 114 | }); at expect (node_modules/expect/build/index.js:113:15) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:111:13) RUNS src/__tests__/server-lifecycle.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts PASS src/__tests__/middleware-sse.test.ts (9.25 s) RUNS src/__tests__/middleware-sse.test.ts Express Middleware and SSE Transport RUNS src/__tests__/middleware-sse.test.ts Middleware Stack RUNS src/__tests__/middleware-sse.test.ts ✓ should handle CORS headers correctly (614 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle JSON body parsing (624 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should enforce connection limits (618 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle malformed JSON gracefully (624 ms) RUNS src/__tests__/middleware-sse.test.ts SSE Transport RUNS src/__tests__/middleware-sse.test.ts ✓ should establish SSE connection with proper headers (615 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should track connection count correctly (1678 ms) RUNS src/__tests__/middleware-sse.test.ts MCP Message Handling RUNS src/__tests__/middleware-sse.test.ts ✓ should process valid MCP messages (620 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should reject invalid message format (614 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle missing message properties (619 ms) RUNS src/__tests__/middleware-sse.test.ts Error Handling RUNS src/__tests__/middleware-sse.test.ts ✓ should handle request timeout gracefully (611 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle server errors gracefully (617 ms) RUNS src/__tests__/middleware-sse.test.ts Security Features RUNS src/__tests__/middleware-sse.test.ts ✓ should have security headers set (612 ms) RUNS src/__tests__/middleware-sse.test.ts ✓ should handle large payloads within limits (619 ms) RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/middleware-sse.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts PASS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts MCPServer Class Structure RUNS src/__tests__/server.test.ts ✓ should instantiate with default configuration (1 ms) RUNS src/__tests__/server.test.ts ✓ should accept custom configuration (1 ms) RUNS src/__tests__/server.test.ts ✓ should merge custom config with defaults (1 ms) RUNS src/__tests__/server.test.ts ✓ should have correct initial state (1 ms) RUNS src/__tests__/server.test.ts ✓ should handle server lifecycle methods (3 ms) RUNS src/__tests__/server.test.ts ✓ should return immutable config copy (1 ms) RUNS src/__tests__/server.test.ts Default Configuration RUNS src/__tests__/server.test.ts ✓ should have sensible defaults (1 ms) RUNS src/__tests__/server.test.ts ServerState Enum RUNS src/__tests__/server.test.ts ✓ should have all expected states RUNS src/__tests__/server.test.ts RUNS src/__tests__/server.test.ts Test Suites: 1 failed, 2 passed, 3 total Tests: 2 failed, 28 passed, 30 total Snapshots: 0 total Time: 11.556 s Ran all test suites. Jest has detected the following 1 open handle potentially keeping Jest from exiting: ● TCPSERVERWRAP 543 | }; 544 | > 545 | this.server = this.app.listen(this.config.port, this.config.host, () => { | ^ 546 | this.log('info', `HTTP server listening on ${this.config.host}:${this.config.port}`); 547 | handleResolve(); 548 | }); at Function.listen (node_modules/express/lib/application.js:605:24) at src/server.ts:545:32 at MCPServer.startHttpServer (src/server.ts:524:12) at MCPServer.initialize (src/server.ts:144:18) at Object.<anonymous> (src/__tests__/server-lifecycle.test.ts:67:21) ╭─    ~/dev/projects/tally-mcp    main !8 ?6 ···························· 1 ✘  12s   12:37:03   ╰─ ``` --- Excellent! We made significant progress. The message validation test is now passing, but we still have 2 remaining issues: 1. The port conflict test - the second server successfully initializes instead of failing 2. The server shutdown test - the server endpoint is still accessible after shutdown These are both related to the server lifecycle management. Let me fix the remaining issues: --- --- Now let me debug the port conflict issue first. The problem might be that both servers are sharing some state or the first server isn't actually binding to the port properly. Let me check if we can improve the port binding detection: --- --- ---

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/learnwithcc/tally-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server