diff --git a/HTTP_IMPLEMENTATION_GUIDE.md b/HTTP_IMPLEMENTATION_GUIDE.md new file mode 100644 index 0000000..56a0556 --- /dev/null +++ b/HTTP_IMPLEMENTATION_GUIDE.md @@ -0,0 +1,792 @@ +# HTTP Implementation Technical Guide + +## Deep Technical Analysis + +### Current MCP Transport Mechanism + +The current implementation uses `StdioServerTransport` which: +1. Reads JSON-RPC messages from stdin +2. Writes responses to stdout +3. Maintains a single, persistent connection +4. Has implicit trust (local execution) + +### Target HTTP Transport Mechanism + +The `StreamableHTTPServerTransport`: +1. Accepts HTTP POST requests with JSON-RPC payloads +2. Can upgrade to Server-Sent Events (SSE) for server-initiated messages +3. Requires session management for state persistence +4. Needs explicit authentication + +## Detailed Implementation Steps + +### Step 1: Install Required Dependencies + +```bash +npm install express cors helmet compression dotenv +npm install --save-dev @types/express @types/cors +``` + +### Step 2: Create HTTP Server Structure + +```typescript +// src/mcp/transports/http-transport.ts +import express, { Request, Response, NextFunction } from 'express'; +import cors from 'cors'; +import helmet from 'helmet'; +import compression from 'compression'; +import { randomUUID } from 'crypto'; +import { + StreamableHTTPServerTransport, + StreamableHTTPServerTransportOptions +} from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import { logger } from '../../utils/logger'; + +export interface HTTPServerConfig { + port: number; + host: string; + authToken?: string; + corsOrigins?: string[]; + sessionTimeout?: number; // in milliseconds + maxSessions?: number; +} + +export interface MCPSession { + id: string; + transport: StreamableHTTPServerTransport; + server: any; // Your MCP server instance + createdAt: Date; + lastActivity: Date; + metadata?: Record; +} + +export class HTTPTransportServer { + private app: express.Application; + private sessions: Map = new Map(); + private config: HTTPServerConfig; + private cleanupInterval?: NodeJS.Timeout; + + constructor(config: HTTPServerConfig) { + this.config = { + sessionTimeout: 30 * 60 * 1000, // 30 minutes default + maxSessions: 100, + ...config + }; + + this.app = express(); + this.setupMiddleware(); + this.setupRoutes(); + this.startSessionCleanup(); + } + + private setupMiddleware(): void { + // Security headers + this.app.use(helmet()); + + // CORS configuration + this.app.use(cors({ + origin: this.config.corsOrigins || true, + credentials: true, + methods: ['POST', 'GET', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization', 'MCP-Session-ID'] + })); + + // Compression + this.app.use(compression()); + + // JSON parsing with size limit + this.app.use(express.json({ limit: '10mb' })); + + // Request logging + this.app.use((req, res, next) => { + logger.info(`${req.method} ${req.path}`, { + sessionId: req.headers['mcp-session-id'], + ip: req.ip + }); + next(); + }); + } + + private setupRoutes(): void { + // Health check endpoint + this.app.get('/health', (req, res) => { + res.json({ + status: 'ok', + sessions: this.sessions.size, + uptime: process.uptime() + }); + }); + + // Main MCP endpoint + this.app.post('/mcp', + this.authenticateRequest.bind(this), + this.handleMCPRequest.bind(this) + ); + + // Session management endpoint + this.app.get('/sessions', + this.authenticateRequest.bind(this), + (req, res) => { + const sessionInfo = Array.from(this.sessions.entries()).map(([id, session]) => ({ + id, + createdAt: session.createdAt, + lastActivity: session.lastActivity, + metadata: session.metadata + })); + res.json({ sessions: sessionInfo }); + } + ); + } + + private authenticateRequest(req: Request, res: Response, next: NextFunction): void { + if (!this.config.authToken) { + return next(); + } + + const authHeader = req.headers.authorization; + const token = authHeader?.startsWith('Bearer ') + ? authHeader.slice(7) + : authHeader; + + if (token !== this.config.authToken) { + logger.warn('Authentication failed', { ip: req.ip }); + return res.status(401).json({ error: 'Unauthorized' }); + } + + next(); + } + + private async handleMCPRequest(req: Request, res: Response): Promise { + try { + const sessionId = req.headers['mcp-session-id'] as string; + let session = sessionId ? this.sessions.get(sessionId) : null; + + // Create new session if needed + if (!session) { + if (this.sessions.size >= this.config.maxSessions!) { + return res.status(503).json({ error: 'Server at capacity' }); + } + + session = await this.createSession(); + res.setHeader('MCP-Session-ID', session.id); + } + + // Update last activity + session.lastActivity = new Date(); + + // Handle the request through the transport + await session.transport.handleRequest(req, res); + + } catch (error) { + logger.error('Error handling MCP request', error); + res.status(500).json({ + error: 'Internal server error', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } + } + + private async createSession(): Promise { + const id = randomUUID(); + const transport = new StreamableHTTPServerTransport(); + + // Create your MCP server instance here + const { N8NDocumentationMCPServer } = await import('../server-update'); + const server = new N8NDocumentationMCPServer(); + + // Connect transport to server + await server.connect(transport); + + const session: MCPSession = { + id, + transport, + server, + createdAt: new Date(), + lastActivity: new Date() + }; + + this.sessions.set(id, session); + logger.info('Created new session', { sessionId: id }); + + return session; + } + + private startSessionCleanup(): void { + this.cleanupInterval = setInterval(() => { + const now = Date.now(); + const timeout = this.config.sessionTimeout!; + + for (const [id, session] of this.sessions.entries()) { + if (now - session.lastActivity.getTime() > timeout) { + this.destroySession(id); + } + } + }, 60000); // Check every minute + } + + private destroySession(id: string): void { + const session = this.sessions.get(id); + if (session) { + // Cleanup server resources + if (session.server && typeof session.server.close === 'function') { + session.server.close(); + } + + this.sessions.delete(id); + logger.info('Destroyed session', { sessionId: id }); + } + } + + public start(): void { + this.app.listen(this.config.port, this.config.host, () => { + logger.info(`HTTP MCP Server listening on ${this.config.host}:${this.config.port}`); + }); + } + + public stop(): void { + if (this.cleanupInterval) { + clearInterval(this.cleanupInterval); + } + + // Cleanup all sessions + for (const id of this.sessions.keys()) { + this.destroySession(id); + } + } +} +``` + +### Step 3: Modify MCP Server for Transport Flexibility + +```typescript +// src/mcp/server-update.ts modifications +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { Transport } from '@modelcontextprotocol/sdk/types.js'; + +export class N8NDocumentationMCPServer { + private server: Server; + // ... existing code ... + + // Add connect method to accept any transport + async connect(transport: Transport): Promise { + await this.ensureInitialized(); + await this.server.connect(transport); + logger.info('MCP Server connected with transport', { + transportType: transport.constructor.name + }); + } + + // Modify run method to be transport-agnostic + async run(transport?: Transport): Promise { + await this.ensureInitialized(); + + if (!transport) { + // Default to stdio for backward compatibility + transport = new StdioServerTransport(); + } + + await this.connect(transport); + logger.info('n8n Documentation MCP Server running'); + } +} +``` + +### Step 4: Create Unified Entry Point + +```typescript +// src/mcp/index-universal.ts +#!/usr/bin/env node +import { N8NDocumentationMCPServer } from './server-update'; +import { HTTPTransportServer } from './transports/http-transport'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { logger } from '../utils/logger'; +import dotenv from 'dotenv'; + +// Load environment variables +dotenv.config(); + +interface CLIArgs { + mode: 'stdio' | 'http'; + port?: number; + host?: string; + authToken?: string; +} + +function parseArgs(): CLIArgs { + const args = process.argv.slice(2); + const config: CLIArgs = { + mode: 'stdio' // default + }; + + for (let i = 0; i < args.length; i++) { + switch (args[i]) { + case '--mode': + config.mode = args[++i] as 'stdio' | 'http'; + break; + case '--port': + config.port = parseInt(args[++i]); + break; + case '--host': + config.host = args[++i]; + break; + case '--auth-token': + config.authToken = args[++i]; + break; + } + } + + // Allow environment variables to override + config.mode = (process.env.MCP_MODE as any) || config.mode; + config.port = parseInt(process.env.MCP_PORT || '') || config.port || 3000; + config.host = process.env.MCP_HOST || config.host || '0.0.0.0'; + config.authToken = process.env.MCP_AUTH_TOKEN || config.authToken; + + return config; +} + +async function main() { + try { + const config = parseArgs(); + logger.info('Starting MCP server', config); + + if (config.mode === 'http') { + // HTTP mode - server manages its own lifecycle + const httpServer = new HTTPTransportServer({ + port: config.port!, + host: config.host!, + authToken: config.authToken, + corsOrigins: process.env.MCP_CORS_ORIGINS?.split(','), + sessionTimeout: parseInt(process.env.MCP_SESSION_TIMEOUT || '') || undefined, + maxSessions: parseInt(process.env.MCP_MAX_SESSIONS || '') || undefined + }); + + httpServer.start(); + + // Graceful shutdown + process.on('SIGINT', () => { + logger.info('Shutting down HTTP server...'); + httpServer.stop(); + process.exit(0); + }); + + } else { + // Stdio mode - traditional single instance + const server = new N8NDocumentationMCPServer(); + await server.run(); // Uses stdio by default + } + + } catch (error) { + logger.error('Failed to start MCP server', error); + process.exit(1); + } +} + +if (require.main === module) { + main(); +} +``` + +### Step 5: Environment Configuration + +```bash +# .env.example +# Server mode: stdio or http +MCP_MODE=http + +# HTTP server configuration +MCP_PORT=3000 +MCP_HOST=0.0.0.0 +MCP_AUTH_TOKEN=your-secure-token-here + +# CORS origins (comma-separated) +MCP_CORS_ORIGINS=https://claude.ai,http://localhost:3000 + +# Session management +MCP_SESSION_TIMEOUT=1800000 # 30 minutes in milliseconds +MCP_MAX_SESSIONS=100 + +# Existing configuration +NODE_ENV=production +LOG_LEVEL=info +``` + +### Step 6: Docker Configuration for Remote Deployment + +```dockerfile +# Dockerfile.http +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm ci + +# Copy source code +COPY . . + +# Build the application +RUN npm run build + +# Production stage +FROM node:20-alpine + +WORKDIR /app + +# Install production dependencies only +COPY package*.json ./ +RUN npm ci --only=production && npm cache clean --force + +# Copy built application +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/data ./data + +# Create non-root user +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nodejs -u 1001 + +# Change ownership +RUN chown -R nodejs:nodejs /app + +USER nodejs + +# Expose port +EXPOSE 3000 + +# Health check +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); })" + +# Start the server +CMD ["node", "dist/mcp/index-universal.js", "--mode", "http"] +``` + +### Step 7: Production Deployment Script + +```bash +#!/bin/bash +# deploy.sh + +# Configuration +DOMAIN="mcp.your-domain.com" +EMAIL="your-email@example.com" +AUTH_TOKEN=$(openssl rand -base64 32) + +# Update system +sudo apt update && sudo apt upgrade -y + +# Install dependencies +sudo apt install -y docker.io docker-compose nginx certbot python3-certbot-nginx + +# Clone repository +git clone https://github.com/yourusername/n8n-mcp.git +cd n8n-mcp + +# Create .env file +cat > .env << EOF +MCP_MODE=http +MCP_PORT=3000 +MCP_HOST=0.0.0.0 +MCP_AUTH_TOKEN=$AUTH_TOKEN +MCP_CORS_ORIGINS=https://claude.ai +NODE_ENV=production +LOG_LEVEL=info +EOF + +# Build and run with Docker +docker build -f Dockerfile.http -t n8n-mcp-http . +docker run -d \ + --name n8n-mcp \ + --restart always \ + -p 127.0.0.1:3000:3000 \ + --env-file .env \ + n8n-mcp-http + +# Configure Nginx +sudo tee /etc/nginx/sites-available/mcp << EOF +server { + listen 80; + server_name $DOMAIN; + return 301 https://\$server_name\$request_uri; +} + +server { + listen 443 ssl http2; + server_name $DOMAIN; + + # SSL will be configured by certbot + + location /mcp { + proxy_pass http://127.0.0.1:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_cache_bypass \$http_upgrade; + + # Timeouts for long-running requests + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location /health { + proxy_pass http://127.0.0.1:3000; + } +} +EOF + +# Enable site +sudo ln -s /etc/nginx/sites-available/mcp /etc/nginx/sites-enabled/ +sudo nginx -t && sudo systemctl reload nginx + +# Get SSL certificate +sudo certbot --nginx -d $DOMAIN --email $EMAIL --agree-tos --non-interactive + +echo "Deployment complete!" +echo "Your MCP server is available at: https://$DOMAIN/mcp" +echo "Auth token: $AUTH_TOKEN" +echo "Save this token - you'll need it for client configuration" +``` + +### Step 8: Client Configuration with mcp-remote + +```json +// claude_desktop_config.json for remote server +{ + "mcpServers": { + "n8n-remote": { + "command": "npx", + "args": [ + "-y", + "mcp-remote@latest", + "connect", + "https://mcp.your-domain.com/mcp" + ], + "env": { + "MCP_AUTH_TOKEN": "your-auth-token-here" + } + } + } +} +``` + +### Step 9: Monitoring and Logging + +```typescript +// src/utils/monitoring.ts +import { Request, Response, NextFunction } from 'express'; + +export interface RequestMetrics { + path: string; + method: string; + statusCode: number; + duration: number; + sessionId?: string; + timestamp: Date; +} + +export class MonitoringService { + private metrics: RequestMetrics[] = []; + + public middleware() { + return (req: Request, res: Response, next: NextFunction) => { + const start = Date.now(); + + res.on('finish', () => { + const metric: RequestMetrics = { + path: req.path, + method: req.method, + statusCode: res.statusCode, + duration: Date.now() - start, + sessionId: req.headers['mcp-session-id'] as string, + timestamp: new Date() + }; + + this.metrics.push(metric); + + // Keep only last 1000 metrics in memory + if (this.metrics.length > 1000) { + this.metrics.shift(); + } + }); + + next(); + }; + } + + public getMetrics() { + return { + requests: this.metrics.length, + avgDuration: this.calculateAverage('duration'), + errorRate: this.calculateErrorRate(), + activeSessions: new Set(this.metrics.map(m => m.sessionId)).size + }; + } + + private calculateAverage(field: keyof RequestMetrics): number { + if (this.metrics.length === 0) return 0; + const sum = this.metrics.reduce((acc, m) => acc + (m[field] as number || 0), 0); + return sum / this.metrics.length; + } + + private calculateErrorRate(): number { + if (this.metrics.length === 0) return 0; + const errors = this.metrics.filter(m => m.statusCode >= 400).length; + return errors / this.metrics.length; + } +} +``` + +## Security Considerations + +### 1. Authentication Token Management +- Use strong, random tokens (minimum 32 characters) +- Rotate tokens regularly +- Never commit tokens to version control +- Use environment variables or secret management systems + +### 2. Rate Limiting +```typescript +import rateLimit from 'express-rate-limit'; + +const limiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, // limit each IP to 100 requests per windowMs + message: 'Too many requests from this IP' +}); + +app.use('/mcp', limiter); +``` + +### 3. Input Validation +- Validate JSON-RPC structure +- Limit request body size +- Sanitize any user inputs +- Use schema validation for MCP tool parameters + +### 4. HTTPS/TLS +- Always use HTTPS in production +- Use strong TLS configurations +- Enable HSTS headers +- Consider certificate pinning for high-security deployments + +## Performance Optimization + +### 1. Database Connection Pooling +Since we're using SQLite through our adapter, consider: +- Read-only replicas for query operations +- In-memory caching for frequently accessed nodes +- Connection pooling if switching to PostgreSQL + +### 2. Response Caching +```typescript +const nodeCache = new NodeCache({ stdTTL: 600 }); // 10 minute cache + +// In your tool handlers +const cachedResult = nodeCache.get(cacheKey); +if (cachedResult) { + return cachedResult; +} +``` + +### 3. Compression +- Already implemented with compression middleware +- Consider additional optimizations for large responses + +### 4. CDN Integration +- Serve static assets through CDN +- Cache API responses where appropriate +- Use geographic distribution for global access + +## Testing Strategy + +### 1. Unit Tests +```typescript +// src/test/http-transport.test.ts +describe('HTTPTransportServer', () => { + it('should create new session on first request', async () => { + // Test implementation + }); + + it('should reuse existing session', async () => { + // Test implementation + }); + + it('should cleanup expired sessions', async () => { + // Test implementation + }); +}); +``` + +### 2. Integration Tests +- Test full request/response cycle +- Verify authentication +- Test session persistence +- Validate error handling + +### 3. Load Testing +```bash +# Using Apache Bench +ab -n 1000 -c 10 -H "Authorization: Bearer your-token" https://your-server/mcp + +# Using k6 +k6 run load-test.js +``` + +## Troubleshooting Guide + +### Common Issues + +1. **Connection Refused** + - Check firewall rules + - Verify nginx configuration + - Ensure Docker container is running + +2. **Authentication Failures** + - Verify token format (Bearer prefix) + - Check environment variables + - Ensure token matches server configuration + +3. **Session Timeout** + - Adjust MCP_SESSION_TIMEOUT + - Check client keep-alive settings + - Monitor server resources + +4. **Performance Issues** + - Enable monitoring + - Check database query performance + - Review nginx access logs + - Monitor Docker container resources + +## Future Enhancements + +1. **WebSocket Support** + - Implement full duplex communication + - Reduce latency for real-time updates + - Better support for server-initiated messages + +2. **OAuth2 Integration** + - Support for third-party authentication + - User-specific access controls + - Integration with enterprise SSO + +3. **Multi-tenancy** + - Separate databases per organization + - Role-based access control + - Usage tracking and quotas + +4. **Horizontal Scaling** + - Redis for session storage + - Load balancer configuration + - Distributed caching + +## Conclusion + +This implementation provides a robust foundation for running n8n-MCP as a remote HTTP service. The dual-mode support ensures backward compatibility while enabling new deployment scenarios. With proper security measures and monitoring in place, this solution can scale from single-user deployments to enterprise-wide installations. \ No newline at end of file diff --git a/HTTP_IMPLEMENTATION_ROADMAP.md b/HTTP_IMPLEMENTATION_ROADMAP.md new file mode 100644 index 0000000..a3311d1 --- /dev/null +++ b/HTTP_IMPLEMENTATION_ROADMAP.md @@ -0,0 +1,371 @@ +# HTTP Implementation Roadmap + +## Quick Reference Architecture + +``` +┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐ +│ Claude Desktop │ stdio │ mcp-remote │ HTTP │ n8n-MCP HTTP │ +│ ├────────>│ adapter ├────────>│ Server │ +└─────────────────┘ └──────────────┘ └─────────────────┘ + │ │ + │ Auth Token │ + └──────────────────────────┘ +``` + +## Implementation Checklist + +### Prerequisites +- [ ] Understand StreamableHTTPServerTransport API +- [ ] Review mcp-remote documentation +- [ ] Set up test environment with Express.js +- [ ] Plan session management strategy + +### Phase 1: Core HTTP Server (Days 1-3) + +#### Day 1: Basic HTTP Server +- [ ] Install dependencies: `express`, `cors`, `helmet`, `compression` +- [ ] Create `src/mcp/transports/http-transport.ts` +- [ ] Implement basic Express server structure +- [ ] Add health check endpoint `/health` +- [ ] Add MCP endpoint `/mcp` (placeholder) + +#### Day 2: MCP Integration +- [ ] Import StreamableHTTPServerTransport +- [ ] Implement session management (in-memory) +- [ ] Connect transport to MCP server +- [ ] Handle JSON-RPC requests +- [ ] Test with simple curl commands + +#### Day 3: Authentication & Security +- [ ] Implement Bearer token authentication +- [ ] Add rate limiting +- [ ] Configure CORS properly +- [ ] Add request logging +- [ ] Basic error handling + +### Phase 2: Server Modifications (Days 4-6) + +#### Day 4: Refactor Server Class +- [ ] Modify `N8NDocumentationMCPServer` to accept any transport +- [ ] Add `connect(transport)` method +- [ ] Update `run()` method for backward compatibility +- [ ] Test stdio mode still works + +#### Day 5: Configuration System +- [ ] Create configuration interface +- [ ] Add environment variable support +- [ ] Implement CLI argument parsing +- [ ] Create `.env.example` file +- [ ] Document all configuration options + +#### Day 6: Unified Entry Point +- [ ] Create `index-universal.ts` +- [ ] Implement mode detection (stdio vs http) +- [ ] Handle graceful shutdown +- [ ] Test both modes work correctly + +### Phase 3: Production Readiness (Days 7-9) + +#### Day 7: Docker & Deployment +- [ ] Create `Dockerfile.http` +- [ ] Add health checks to Docker +- [ ] Create `docker-compose.yml` +- [ ] Write deployment script +- [ ] Test container locally + +#### Day 8: Monitoring & Logging +- [ ] Enhance logging with correlation IDs +- [ ] Add metrics collection +- [ ] Implement `/metrics` endpoint +- [ ] Add session analytics +- [ ] Create monitoring dashboard + +#### Day 9: Documentation +- [ ] Write user setup guide +- [ ] Create troubleshooting guide +- [ ] Document API endpoints +- [ ] Add architecture diagrams +- [ ] Create video tutorial + +### Phase 4: Testing & Launch (Days 10-14) + +#### Day 10: Testing Suite +- [ ] Unit tests for HTTP transport +- [ ] Integration tests for full flow +- [ ] Load testing with Apache Bench +- [ ] Security testing (auth, injection) +- [ ] Cross-platform client testing + +#### Day 11: Beta Deployment +- [ ] Deploy to test server +- [ ] Configure nginx + SSL +- [ ] Test with mcp-remote +- [ ] Monitor performance +- [ ] Gather initial feedback + +#### Day 12: Performance Optimization +- [ ] Implement response caching +- [ ] Optimize database queries +- [ ] Add connection pooling +- [ ] Profile memory usage +- [ ] Fine-tune nginx config + +#### Day 13: Security Hardening +- [ ] Security audit +- [ ] Implement CSP headers +- [ ] Add request validation +- [ ] Set up fail2ban +- [ ] Configure firewall rules + +#### Day 14: Production Launch +- [ ] Final deployment +- [ ] Update documentation +- [ ] Announce to community +- [ ] Monitor closely +- [ ] Respond to feedback + +## Code Templates + +### 1. Minimal Express Server Test +```typescript +// test-server.ts - Quick test to verify concept +import express from 'express'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; + +const app = express(); +app.use(express.json()); + +const transport = new StreamableHTTPServerTransport(); + +app.post('/mcp', async (req, res) => { + await transport.handleRequest(req, res); +}); + +app.listen(3000, () => { + console.log('Test server running on http://localhost:3000'); +}); +``` + +### 2. Environment Variables +```bash +# .env +MCP_MODE=http +MCP_PORT=3000 +MCP_HOST=0.0.0.0 +MCP_AUTH_TOKEN=development-token-change-in-production +MCP_SESSION_TIMEOUT=1800000 +MCP_MAX_SESSIONS=50 +MCP_CORS_ORIGINS=http://localhost:3000,https://claude.ai +NODE_ENV=development +LOG_LEVEL=debug +``` + +### 3. Test Script +```bash +#!/bin/bash +# test-http.sh - Test HTTP endpoint + +TOKEN="development-token-change-in-production" +URL="http://localhost:3000/mcp" + +# Test health check +curl -s http://localhost:3000/health | jq . + +# Test MCP endpoint +curl -s -X POST $URL \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $TOKEN" \ + -d '{ + "jsonrpc": "2.0", + "method": "tools/list", + "id": 1 + }' | jq . +``` + +### 4. nginx Configuration +```nginx +# /etc/nginx/sites-available/n8n-mcp +server { + listen 80; + server_name mcp.yourdomain.com; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + server_name mcp.yourdomain.com; + + ssl_certificate /etc/letsencrypt/live/mcp.yourdomain.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/mcp.yourdomain.com/privkey.pem; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + location / { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } +} +``` + +### 5. Claude Desktop Config +```json +{ + "mcpServers": { + "n8n-docs-remote": { + "command": "npx", + "args": [ + "-y", + "mcp-remote@latest", + "connect", + "https://mcp.yourdomain.com/mcp" + ], + "env": { + "MCP_AUTH_TOKEN": "your-secure-token" + } + } + } +} +``` + +## Testing Scenarios + +### Scenario 1: Basic Connectivity +1. Start HTTP server locally +2. Use curl to test endpoints +3. Verify authentication works +4. Check session creation + +### Scenario 2: mcp-remote Integration +1. Install mcp-remote globally +2. Configure with local server +3. Test all MCP tools work +4. Verify session persistence + +### Scenario 3: Load Testing +```bash +# Test 100 concurrent users +ab -n 1000 -c 100 \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -p request.json \ + http://localhost:3000/mcp +``` + +### Scenario 4: Security Testing +1. Test without auth token (should fail) +2. Test with invalid token (should fail) +3. Test SQL injection attempts +4. Test large payload handling +5. Test rate limiting + +## Deployment Commands + +### Local Development +```bash +# Start in development mode +npm run dev:http + +# Watch logs +tail -f logs/mcp-http.log +``` + +### Production Deployment +```bash +# Build and deploy +npm run build +docker build -f Dockerfile.http -t n8n-mcp-http . +docker run -d --name n8n-mcp-http \ + -p 3000:3000 \ + --env-file .env.production \ + --restart unless-stopped \ + n8n-mcp-http + +# Check status +docker logs n8n-mcp-http +curl https://mcp.yourdomain.com/health +``` + +## Monitoring Checklist + +### Application Metrics +- [ ] Request rate +- [ ] Response times +- [ ] Error rates +- [ ] Active sessions +- [ ] Memory usage +- [ ] CPU usage + +### Business Metrics +- [ ] Unique users +- [ ] Most used tools +- [ ] Peak usage times +- [ ] Geographic distribution + +### Alerts to Configure +- [ ] Server down +- [ ] High error rate (> 5%) +- [ ] Slow response times (> 1s) +- [ ] Memory usage > 80% +- [ ] Disk space < 20% +- [ ] SSL certificate expiring + +## Rollback Plan + +If issues arise: + +1. **Immediate**: Switch DNS back to maintenance page +2. **Quick Fix**: Rollback Docker container to previous version +3. **Investigate**: Check logs and metrics +4. **Fix Forward**: Deploy hotfix if simple +5. **Full Rollback**: Restore previous version if complex + +## Success Criteria + +### Week 1 +- [ ] HTTP server running locally +- [ ] All MCP tools working via HTTP +- [ ] Basic authentication working +- [ ] Session management functional + +### Week 2 +- [ ] Deployed to test environment +- [ ] SSL/HTTPS working +- [ ] mcp-remote integration tested +- [ ] Documentation complete + +### Week 3 +- [ ] Beta users testing +- [ ] Performance acceptable +- [ ] No security issues found +- [ ] Monitoring in place + +### Week 4 +- [ ] Production deployment +- [ ] Public announcement +- [ ] User adoption beginning +- [ ] Positive feedback + +## Future Enhancements + +After successful launch, consider: + +1. **WebSocket Support** - Real-time bidirectional communication +2. **OAuth2/SSO** - Enterprise authentication +3. **Multi-tenancy** - Separate instances per organization +4. **Usage Analytics** - Detailed usage tracking +5. **API Keys** - Per-user authentication +6. **Webhooks** - Event notifications +7. **Clustering** - Horizontal scaling +8. **GraphQL API** - Alternative query interface + +This roadmap provides a clear, actionable path to implementing HTTP support in n8n-MCP. Each phase builds on the previous one, ensuring a stable and well-tested deployment. \ No newline at end of file diff --git a/HTTP_REMOTE_DEPLOYMENT_PLAN.md b/HTTP_REMOTE_DEPLOYMENT_PLAN.md new file mode 100644 index 0000000..1a2d533 --- /dev/null +++ b/HTTP_REMOTE_DEPLOYMENT_PLAN.md @@ -0,0 +1,286 @@ +# HTTP Remote Deployment Plan for n8n-MCP + +## Executive Summary + +This document outlines the comprehensive plan to transform the n8n-MCP server from a local stdio-based implementation to a remote HTTP-accessible service that can be deployed on the internet and accessed by Claude Desktop users from anywhere. + +## Current State Analysis + +### Current Architecture +- **Transport**: StdioServerTransport (requires local execution) +- **Communication**: stdin/stdout between Claude Desktop and the MCP server +- **Deployment**: Must run on the same machine as Claude Desktop +- **Authentication**: None (implicit trust from local execution) +- **State Management**: Single instance per process + +### Limitations +1. Users must install and maintain the server locally +2. No centralized updates or management +3. Limited to single-user scenarios +4. Requires Node.js and dependencies on client machine + +## Target Architecture + +### Goals +1. Deploy n8n-MCP server on remote infrastructure (VPS, cloud, etc.) +2. Enable multiple Claude Desktop users to connect to a single server instance +3. Maintain security through authentication and encryption +4. Support both local (stdio) and remote (HTTP) modes for flexibility + +### Technical Requirements + +#### 1. HTTP Transport Implementation +- Use `StreamableHTTPServerTransport` from `@modelcontextprotocol/sdk` +- Implement session management for stateful connections +- Support JSON-RPC 2.0 protocol over HTTP +- Handle both request/response and server-sent events + +#### 2. Authentication & Security +- Implement Bearer token authentication +- Use HTTPS/TLS for all communications +- Consider OAuth2 for advanced scenarios +- Rate limiting and DDoS protection + +#### 3. Infrastructure Requirements +- HTTP server (Express.js recommended) +- SSL certificates (Let's Encrypt) +- Reverse proxy (nginx/Caddy) +- Process manager (PM2) +- Domain name for stable endpoint + +## Implementation Plan + +### Phase 1: Core HTTP Server Implementation + +#### 1.1 Create HTTP Server Module +```typescript +// src/mcp/http-server.ts +import express from 'express'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import { N8NDocumentationMCPServer } from './server-update'; + +interface Session { + id: string; + transport: StreamableHTTPServerTransport; + server: N8NDocumentationMCPServer; + lastActivity: Date; +} +``` + +#### 1.2 Session Management +- Implement session creation and cleanup +- Handle concurrent sessions +- Add session timeout (e.g., 30 minutes) +- Store session state in memory (consider Redis for production) + +#### 1.3 Authentication Middleware +```typescript +const authenticateToken = (req: Request, res: Response, next: NextFunction) => { + const authHeader = req.headers['authorization']; + const token = authHeader && authHeader.split(' ')[1]; + + if (!token || token !== process.env.AUTH_TOKEN) { + return res.sendStatus(401); + } + + next(); +}; +``` + +### Phase 2: Dual-Mode Support + +#### 2.1 Configuration System +```typescript +interface ServerConfig { + mode: 'stdio' | 'http'; + http?: { + port: number; + host: string; + authToken: string; + ssl?: { + cert: string; + key: string; + }; + }; +} +``` + +#### 2.2 Entry Point Refactoring +- Create unified entry point that can start either stdio or HTTP server +- Use environment variables or CLI arguments for mode selection +- Maintain backward compatibility with existing stdio mode + +### Phase 3: Client Adapter Implementation + +#### 3.1 mcp-remote Integration +Since Claude Desktop doesn't natively support HTTP transport yet, we need to: +1. Document how to use `mcp-remote` adapter +2. Create wrapper scripts for easy setup +3. Provide configuration examples + +#### 3.2 Claude Desktop Configuration +```json +{ + "mcpServers": { + "n8n-documentation-remote": { + "command": "npx", + "args": [ + "mcp-remote", + "https://your-server.com/mcp", + "--auth-token", "your-auth-token" + ] + } + } +} +``` + +### Phase 4: Deployment Infrastructure + +#### 4.1 Docker Container +```dockerfile +FROM node:20-alpine +WORKDIR /app +COPY . . +RUN npm ci --only=production +RUN npm run build +EXPOSE 3000 +CMD ["npm", "run", "start:http"] +``` + +#### 4.2 Nginx Configuration +```nginx +server { + listen 443 ssl http2; + server_name mcp.your-domain.com; + + ssl_certificate /etc/letsencrypt/live/mcp.your-domain.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/mcp.your-domain.com/privkey.pem; + + location /mcp { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } +} +``` + +#### 4.3 PM2 Configuration +```json +{ + "apps": [{ + "name": "n8n-mcp-server", + "script": "./dist/mcp/http-server.js", + "env": { + "NODE_ENV": "production", + "PORT": 3000, + "AUTH_TOKEN": "your-secure-token" + } + }] +} +``` + +## Technical Challenges & Solutions + +### 1. State Management +**Challenge**: MCP servers can be stateful, but HTTP is stateless by nature. +**Solution**: Implement session management with unique session IDs in headers. + +### 2. Authentication with mcp-remote +**Challenge**: mcp-remote needs to pass authentication to the remote server. +**Solution**: Use environment variables or command-line arguments for auth tokens. + +### 3. Database Access +**Challenge**: Multiple concurrent sessions accessing SQLite database. +**Solution**: Our database adapter already handles this; sql.js runs in-memory with persistence. + +### 4. Performance & Scaling +**Challenge**: Single server instance handling multiple clients. +**Solution**: +- Implement connection pooling +- Add caching layer for frequently accessed data +- Consider horizontal scaling with load balancer + +### 5. Security +**Challenge**: Exposing MCP server to the internet. +**Solution**: +- Mandatory HTTPS +- Strong authentication tokens +- Rate limiting +- Input validation +- Regular security audits + +## Implementation Timeline + +### Week 1: Core HTTP Server +- [ ] Implement basic HTTP server with Express +- [ ] Integrate StreamableHTTPServerTransport +- [ ] Add session management +- [ ] Implement authentication + +### Week 2: Dual-Mode Support +- [ ] Refactor entry points +- [ ] Add configuration system +- [ ] Test both stdio and HTTP modes +- [ ] Update documentation + +### Week 3: Client Integration +- [ ] Test with mcp-remote adapter +- [ ] Create setup scripts +- [ ] Document Claude Desktop configuration +- [ ] Create troubleshooting guide + +### Week 4: Deployment +- [ ] Create Docker container +- [ ] Set up test deployment +- [ ] Configure nginx/SSL +- [ ] Performance testing +- [ ] Security hardening + +## Alternative Approaches + +### 1. Cloudflare Workers +- **Pros**: Global edge deployment, built-in DDoS protection +- **Cons**: Limited execution time, stateless by design + +### 2. AWS Lambda +- **Pros**: Serverless, auto-scaling +- **Cons**: Cold starts, complex state management + +### 3. Dedicated WebSocket Server +- **Pros**: Real-time bidirectional communication +- **Cons**: More complex implementation, not standard MCP transport + +## Success Metrics + +1. **Functionality**: All MCP tools work identically in remote mode +2. **Performance**: Response time < 200ms for most operations +3. **Reliability**: 99.9% uptime +4. **Security**: No unauthorized access incidents +5. **Usability**: Clear documentation and easy setup + +## Risks & Mitigations + +| Risk | Impact | Mitigation | +|------|---------|------------| +| Claude Desktop HTTP support delayed | High | Use mcp-remote adapter as bridge | +| Security breach | High | Regular audits, penetration testing | +| Performance degradation | Medium | Caching, CDN, horizontal scaling | +| Database corruption | Medium | Regular backups, read replicas | +| Cost overruns | Low | Start with single VPS, scale as needed | + +## Next Steps + +1. **Validate Approach**: Test StreamableHTTPServerTransport with simple example +2. **Prototype**: Build minimal HTTP server with single tool +3. **Security Review**: Have security expert review authentication approach +4. **Community Feedback**: Share plan with MCP community for input +5. **Begin Implementation**: Start with Phase 1 core server + +## Conclusion + +Transitioning n8n-MCP to support remote HTTP deployment will significantly expand its usability and reach. While Claude Desktop doesn't yet natively support HTTP transport, the mcp-remote adapter provides a viable bridge solution. The implementation plan balances immediate functionality with future-proofing for when native HTTP support arrives. + +The key to success will be maintaining compatibility with existing stdio users while providing a seamless experience for remote users. With proper security measures and careful implementation, n8n-MCP can become a centrally-hosted service that benefits the entire Claude Desktop community. \ No newline at end of file diff --git a/HTTP_REMOTE_SUMMARY.md b/HTTP_REMOTE_SUMMARY.md new file mode 100644 index 0000000..7cfc9d6 --- /dev/null +++ b/HTTP_REMOTE_SUMMARY.md @@ -0,0 +1,251 @@ +# HTTP Remote Deployment - Executive Summary + +## Current Situation + +The n8n-MCP server currently only works locally on the same machine as Claude Desktop. This limits its usefulness and prevents centralized deployment, updates, and management. + +## Key Finding: Claude Desktop Limitation + +**Critical Discovery**: Claude Desktop does NOT currently support remote MCP servers natively. It only supports the stdio (standard input/output) transport protocol, which requires local execution. + +## The Solution: mcp-remote Bridge + +The MCP community has developed `mcp-remote`, an adapter that bridges the gap: +- Acts as a local stdio server that Claude Desktop can communicate with +- Forwards requests to remote HTTP MCP servers +- Handles authentication and session management +- Provides transparent proxy functionality + +## Implementation Overview + +### 1. Server-Side Changes + +We need to add HTTP transport support to n8n-MCP: + +```typescript +// New capabilities to add: +- HTTP endpoint (/mcp) that accepts JSON-RPC requests +- Session management for stateful connections +- Bearer token authentication +- HTTPS/TLS encryption +- Health check endpoints +``` + +### 2. Dual-Mode Operation + +The server will support both modes: +- **stdio mode**: Current local operation (no changes for existing users) +- **http mode**: New remote operation for internet deployment + +### 3. Client Configuration + +Users will configure Claude Desktop like this: + +```json +{ + "mcpServers": { + "n8n-remote": { + "command": "npx", + "args": [ + "-y", + "mcp-remote@latest", + "connect", + "https://your-mcp-server.com/mcp" + ], + "env": { + "MCP_AUTH_TOKEN": "your-secure-token" + } + } + } +} +``` + +## Technical Architecture + +### Components + +1. **Express.js HTTP Server** + - Handles incoming HTTP requests + - Manages authentication + - Provides CORS support + +2. **StreamableHTTPServerTransport** + - MCP SDK's HTTP transport implementation + - Handles JSON-RPC protocol + - Supports Server-Sent Events for bidirectional communication + +3. **Session Manager** + - Creates unique sessions per client + - Maintains state between requests + - Handles cleanup of inactive sessions + +4. **Database Adapter** + - Our existing adapter works perfectly + - Handles concurrent access + - No changes needed + +## Security Model + +1. **Authentication**: Bearer token in Authorization header +2. **Encryption**: HTTPS/TLS required for production +3. **Rate Limiting**: Prevent abuse and DDoS +4. **Input Validation**: Sanitize all inputs +5. **CORS**: Restrict allowed origins + +## Deployment Options + +### Option 1: VPS/Cloud VM +- Full control over environment +- Can handle many concurrent users +- Requires server management + +### Option 2: Docker Container +- Easy deployment and updates +- Consistent environment +- Good for scaling + +### Option 3: Managed Platforms +- Cloudflare Workers (with limitations) +- AWS Lambda (stateless challenges) +- Heroku/Railway (simple deployment) + +## Implementation Phases + +### Phase 1: Core HTTP Server (Week 1) +- Implement Express server with MCP endpoint +- Add StreamableHTTPServerTransport +- Basic authentication +- Session management + +### Phase 2: Integration (Week 2) +- Modify existing server for dual-mode +- Add configuration system +- Update entry points +- Maintain backward compatibility + +### Phase 3: Deployment (Week 3) +- Create Docker container +- Write deployment scripts +- Set up nginx/SSL +- Document setup process + +### Phase 4: Testing & Launch (Week 4) +- Security testing +- Performance testing +- Documentation +- Community release + +## Benefits + +1. **Centralized Management** + - Single server for multiple users + - Easy updates and maintenance + - Consistent experience + +2. **No Local Installation** + - Users don't need Node.js + - No dependency management + - Works on any OS + +3. **Enterprise Ready** + - Authentication and access control + - Monitoring and logging + - Scalable architecture + +4. **Cost Effective** + - One server serves many users + - Efficient resource usage + - Pay for what you use + +## Challenges & Solutions + +| Challenge | Solution | +|-----------|----------| +| Claude Desktop doesn't support HTTP | Use mcp-remote adapter | +| Session state management | Implement session manager with timeout | +| Security concerns | Strong auth, HTTPS, rate limiting | +| Database concurrency | Our adapter already handles this | +| Performance at scale | Caching, CDN, horizontal scaling | + +## Cost Estimate + +### Small Deployment (< 50 users) +- VPS: $10-20/month +- Domain: $10/year +- SSL: Free (Let's Encrypt) +- Total: ~$15/month + +### Medium Deployment (50-500 users) +- Better VPS: $40-80/month +- CDN: $20/month +- Monitoring: $10/month +- Total: ~$70/month + +### Large Deployment (500+ users) +- Load balanced setup: $200+/month +- Redis for sessions: $30/month +- Advanced monitoring: $50/month +- Total: ~$280/month + +## Success Metrics + +1. **Technical Success** + - All MCP tools work remotely + - Response time < 200ms + - 99.9% uptime + +2. **User Success** + - Easy setup (< 5 minutes) + - Clear documentation + - Positive feedback + +3. **Operational Success** + - Low maintenance overhead + - Automated monitoring + - Smooth updates + +## Recommended Next Steps + +1. **Immediate Actions** + - Review and approve the implementation plan + - Set up development environment + - Begin Phase 1 implementation + +2. **Short Term (1-2 weeks)** + - Complete HTTP server implementation + - Test with mcp-remote + - Deploy beta version + +3. **Medium Term (3-4 weeks)** + - Production deployment + - Documentation and guides + - Community announcement + +4. **Long Term (2-3 months)** + - Gather feedback + - Implement enhancements + - Consider enterprise features + +## Conclusion + +Adding HTTP remote deployment to n8n-MCP is technically feasible and highly beneficial. While Claude Desktop's current limitations require using the mcp-remote adapter, this is a proven solution already in use by other MCP servers. + +The implementation is straightforward, building on our existing robust architecture. The database adapter system we recently implemented will work perfectly in a multi-user environment. + +This enhancement will transform n8n-MCP from a local tool to a cloud-ready service, greatly expanding its reach and usefulness to the Claude Desktop community. + +## Key Decision Points + +1. **Should we proceed with HTTP implementation?** + - Recommendation: Yes, the benefits far outweigh the complexity + +2. **Which deployment option should we prioritize?** + - Recommendation: Start with VPS + Docker for flexibility + +3. **How should we handle authentication?** + - Recommendation: Start with Bearer tokens, consider OAuth2 later + +4. **When should we launch?** + - Recommendation: Beta in 2 weeks, production in 4 weeks + +The path forward is clear, and the technical approach is sound. With careful implementation and testing, n8n-MCP can become a premier remote MCP service for the Claude Desktop ecosystem. \ No newline at end of file diff --git a/README.md b/README.md index 4b570d2..6040a7f 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,22 @@ Current implementation achieves: - ✅ 35 AI-capable tools detected - ✅ All critical nodes validated +## Future Development + +### HTTP Remote Deployment (Planned) + +We are planning to add HTTP transport support to enable remote deployment of the MCP server. This will allow: +- Centralized hosting on cloud servers +- Multiple users connecting to a single instance +- No local installation required +- Enterprise-ready authentication + +For detailed planning documents, see: +- [HTTP Remote Deployment Plan](./HTTP_REMOTE_DEPLOYMENT_PLAN.md) +- [HTTP Implementation Guide](./HTTP_IMPLEMENTATION_GUIDE.md) +- [HTTP Implementation Roadmap](./HTTP_IMPLEMENTATION_ROADMAP.md) +- [HTTP Remote Summary](./HTTP_REMOTE_SUMMARY.md) + ## Contributing 1. Fork the repository