From 1ab822e58dd3d77ccc322c3794614716c0a19813 Mon Sep 17 00:00:00 2001 From: Morax Date: Tue, 29 Jul 2025 14:31:57 +0800 Subject: [PATCH] Fix SSE endpoint and improve server deployment - Enhanced SSE endpoint with better error handling and logging - Added comprehensive API info endpoint - Improved server startup logging with all endpoints - Updated Dockerfile to use SSE transport by default - Added debug script for SSE connection troubleshooting - Server now binds to 0.0.0.0 for better container compatibility --- Dockerfile | 4 +-- README.md | 2 +- debug-sse.sh | 56 +++++++++++++++++++++++++++++++++++++++++ src/http-server.ts | 63 ++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 115 insertions(+), 10 deletions(-) create mode 100755 debug-sse.sh diff --git a/Dockerfile b/Dockerfile index dfbe9c0..d98ec03 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,5 +31,5 @@ EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD node -e "require('http').get('http://localhost:3000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })" -# Default command - run HTTP server -CMD ["node", "dist/index.js", "--transport", "http", "--port", "3000"] +# Default command - run HTTP server with SSE support +CMD ["node", "dist/index.js", "--transport", "sse", "--port", "3000"] diff --git a/README.md b/README.md index 3185e25..e60ca8b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A professional-grade Model Context Protocol (MCP) server for Rider-Waite tarot c ```json { "command": "npx", - "args": ["tarot-mcp-server"], + "args": ["tarot-mcp-server@latest"], "env": { "NODE_ENV": "production" } diff --git a/debug-sse.sh b/debug-sse.sh new file mode 100755 index 0000000..5272fb8 --- /dev/null +++ b/debug-sse.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Debug script for SSE connection issues + +SERVER_URL=${1:-"http://localhost:3000"} + +echo "🔍 Debugging SSE connection to: $SERVER_URL" +echo "================================================" + +# Test basic connectivity +echo "1. Testing basic connectivity..." +if curl -f "$SERVER_URL/health" > /dev/null 2>&1; then + echo "✅ Server is reachable" + curl -s "$SERVER_URL/health" | jq '.' 2>/dev/null || curl -s "$SERVER_URL/health" +else + echo "❌ Server is not reachable at $SERVER_URL" + exit 1 +fi + +echo "" + +# Test API info endpoint +echo "2. Testing API info endpoint..." +if curl -f "$SERVER_URL/api/info" > /dev/null 2>&1; then + echo "✅ API info endpoint is working" + curl -s "$SERVER_URL/api/info" | jq '.' 2>/dev/null || curl -s "$SERVER_URL/api/info" +else + echo "❌ API info endpoint is not working" +fi + +echo "" + +# Test SSE endpoint +echo "3. Testing SSE endpoint..." +echo "Attempting to connect to SSE endpoint (will timeout after 5 seconds)..." + +timeout 5s curl -N -H "Accept: text/event-stream" -H "Cache-Control: no-cache" "$SERVER_URL/sse" 2>&1 | head -10 + +echo "" +echo "4. Testing SSE endpoint with verbose output..." +curl -v -N -H "Accept: text/event-stream" -H "Cache-Control: no-cache" "$SERVER_URL/sse" 2>&1 | head -20 + +echo "" +echo "================================================" +echo "🔍 Debug complete!" +echo "" +echo "If you see 404 errors, check:" +echo "1. Server is running in HTTP/SSE mode (not stdio)" +echo "2. Server is listening on the correct port" +echo "3. No reverse proxy is interfering" +echo "4. Firewall allows the connection" +echo "" +echo "Expected SSE response should include:" +echo "- HTTP 200 status" +echo "- Content-Type: text/event-stream" +echo "- Connection: keep-alive" diff --git a/src/http-server.ts b/src/http-server.ts index 06df3c7..ca7d627 100644 --- a/src/http-server.ts +++ b/src/http-server.ts @@ -89,14 +89,60 @@ export class TarotHttpServer { * Setup HTTP routes */ private setupRoutes(): void { + // Health check endpoint this.app.get('/health', (req, res) => { - res.json({ status: 'ok' }); + res.json({ + status: 'ok', + timestamp: new Date().toISOString(), + endpoints: { + sse: '/sse', + mcp: '/mcp', + health: '/health', + api: { + reading: '/api/reading', + customSpread: '/api/custom-spread', + info: '/api/info' + } + } + }); }); - // SSE endpoint + // API info endpoint + this.app.get('/api/info', (req, res) => { + res.json({ + name: 'Tarot MCP Server', + version: '1.0.0', + capabilities: ['tools'], + tools: this.tarotServer.getAvailableTools(), + endpoints: { + sse: '/sse', + mcp: '/mcp', + health: '/health' + } + }); + }); + + // SSE endpoint for MCP this.app.get('/sse', async (req, res) => { - const transport = new SSEServerTransport('/sse', res); - await this.server.connect(transport); + try { + console.log('SSE connection request received'); + const transport = new SSEServerTransport('/sse', res); + await this.server.connect(transport); + console.log('SSE connection established'); + } catch (error) { + console.error('SSE connection error:', error); + res.status(500).json({ error: 'Failed to establish SSE connection' }); + } + }); + + // MCP HTTP endpoint (alternative to SSE) + this.app.post('/mcp', async (req, res) => { + try { + // This would need proper MCP HTTP transport implementation + res.json({ message: 'MCP HTTP endpoint - not yet implemented' }); + } catch (error) { + res.status(500).json({ error: error instanceof Error ? error.message : String(error) }); + } }); // Example of a direct API endpoint @@ -133,9 +179,12 @@ export class TarotHttpServer { */ public async start(): Promise { return new Promise((resolve) => { - this.app.listen(this.port, () => { - console.log(`Tarot MCP Server running on http://localhost:${this.port}`); - console.log(`SSE endpoint available at http://localhost:${this.port}/sse`); + this.app.listen(this.port, '0.0.0.0', () => { + console.log(`🔮 Tarot MCP Server running on http://0.0.0.0:${this.port}`); + console.log(`📡 SSE endpoint: http://0.0.0.0:${this.port}/sse`); + console.log(`🔧 MCP endpoint: http://0.0.0.0:${this.port}/mcp`); + console.log(`❤️ Health check: http://0.0.0.0:${this.port}/health`); + console.log(`📋 API info: http://0.0.0.0:${this.port}/api/info`); resolve(); }); });