diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 3f54d9c..a58c0f6 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -35,6 +35,7 @@ jobs: uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry + if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} diff --git a/Dockerfile b/Dockerfile index 4fc7ab8..0e4f1da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,8 +13,6 @@ COPY --from=deps /app/node_modules ./node_modules COPY . . # Build TypeScript RUN npm run build -# Pre-initialize database during build -RUN mkdir -p /app/data && npm run rebuild || echo "Database will be initialized at runtime" # Stage 3: Simple Runtime FROM node:20-alpine AS runtime @@ -32,8 +30,8 @@ RUN npm ci --only=production && \ # Copy built application COPY --from=builder /app/dist ./dist -# Copy pre-built database if it exists -COPY --from=builder /app/data/nodes.db ./data/nodes.db 2>/dev/null || true +# Create data directory +RUN mkdir -p /app/data # Copy necessary source files for database initialization COPY src/database/schema.sql ./src/database/ diff --git a/HTTP_IMPLEMENTATION_GUIDE.md b/HTTP_IMPLEMENTATION_GUIDE.md deleted file mode 100644 index 56a0556..0000000 --- a/HTTP_IMPLEMENTATION_GUIDE.md +++ /dev/null @@ -1,792 +0,0 @@ -# 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 deleted file mode 100644 index a3311d1..0000000 --- a/HTTP_IMPLEMENTATION_ROADMAP.md +++ /dev/null @@ -1,371 +0,0 @@ -# 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 deleted file mode 100644 index 1a2d533..0000000 --- a/HTTP_REMOTE_DEPLOYMENT_PLAN.md +++ /dev/null @@ -1,286 +0,0 @@ -# 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 deleted file mode 100644 index 7cfc9d6..0000000 --- a/HTTP_REMOTE_SUMMARY.md +++ /dev/null @@ -1,251 +0,0 @@ -# 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/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md deleted file mode 100644 index 4b52225..0000000 --- a/IMPLEMENTATION_PLAN.md +++ /dev/null @@ -1,650 +0,0 @@ -# n8n-MCP Enhancement Implementation Plan v2.1 Final - -## Executive Summary - -This ultra-focused MVP implementation plan delivers accurate n8n node documentation in 2 weeks by working directly with n8n's architecture. We prioritize simplicity and accuracy over complex features. - -## Core MVP Principles - -1. **Start with the simplest thing that works** -2. **Test with real nodes early and often** -3. **Don't try to be too clever** - n8n's structure is fine -4. **Focus on accuracy over completeness** -5. **Work WITH n8n's architecture, not against it** - -## Key Insight - -**We're not trying to understand n8n's nodes, we're just accurately cataloging them.** - -## Simplified Architecture - -``` -n8n-mcp/ -├── src/ -│ ├── loaders/ -│ │ └── node-loader.ts # Simple npm package loader -│ ├── parsers/ -│ │ └── simple-parser.ts # Single parser for all nodes -│ ├── mappers/ -│ │ └── docs-mapper.ts # Deterministic documentation mapping -│ ├── scripts/ -│ │ ├── rebuild.ts # One-command rebuild -│ │ └── validate.ts # Validation script -│ └── mcp/ -│ └── server.ts # Enhanced MCP server -└── data/ - └── nodes.db # Minimal SQLite database -``` - -## Implementation Strategy - -### Quick Win Approach -Get *something* working end-to-end on Day 1, even if it only loads 5 nodes. This proves the architecture and builds momentum. - -### Documentation Strategy -Clone the n8n-docs repo locally for simpler file-based access: -```bash -git clone https://github.com/n8n-io/n8n-docs.git ../n8n-docs -``` - -### Test-First Development -Build the rebuild script first as a test harness: -```bash -npm run rebuild && sqlite3 data/nodes.db "SELECT node_type, display_name FROM nodes LIMIT 10" -``` - -## Week 1: Core Implementation - -### Day 1-2: Simple Node Loader + Initial Rebuild Script - -**Start with the rebuild script to enable quick iteration!** - -**File**: `src/scripts/rebuild.ts` (Build this first!) - -```typescript -#!/usr/bin/env node -import Database from 'better-sqlite3'; -import { N8nNodeLoader } from '../loaders/node-loader'; -import { SimpleParser } from '../parsers/simple-parser'; -import { DocsMapper } from '../mappers/docs-mapper'; - -async function rebuild() { - console.log('🔄 Rebuilding n8n node database...\n'); - - const db = new Database('./data/nodes.db'); - const loader = new N8nNodeLoader(); - const parser = new SimpleParser(); - const mapper = new DocsMapper(); - - // Initialize database - const schema = require('fs').readFileSync('./src/database/schema.sql', 'utf8'); - db.exec(schema); - - // Clear existing data - db.exec('DELETE FROM nodes'); - console.log('🗑️ Cleared existing data\n'); - - // Load all nodes - const nodes = await loader.loadAllNodes(); - console.log(`📦 Loaded ${nodes.length} nodes from packages\n`); - - // Statistics - let successful = 0; - let failed = 0; - let aiTools = 0; - - // Process each node - for (const { packageName, nodeName, NodeClass } of nodes) { - try { - // Parse node - const parsed = parser.parse(NodeClass); - - // Get documentation - const docs = await mapper.fetchDocumentation(parsed.nodeType); - - // Insert into database - db.prepare(` - INSERT INTO nodes ( - node_type, package_name, display_name, description, - category, development_style, is_ai_tool, is_trigger, - is_webhook, is_versioned, version, documentation, - properties_schema, operations, credentials_required - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `).run( - parsed.nodeType, - packageName, - parsed.displayName, - parsed.description, - parsed.category, - parsed.style, - parsed.isAITool ? 1 : 0, - parsed.isTrigger ? 1 : 0, - parsed.isWebhook ? 1 : 0, - parsed.isVersioned ? 1 : 0, - parsed.version, - docs, - JSON.stringify(parsed.properties), - JSON.stringify(parsed.operations), - JSON.stringify(parsed.credentials) - ); - - successful++; - if (parsed.isAITool) aiTools++; - - console.log(`✅ ${parsed.nodeType}`); - } catch (error) { - failed++; - console.error(`❌ Failed to process ${nodeName}: ${error.message}`); - } - } - - // Summary - console.log('\n📊 Summary:'); - console.log(` Total nodes: ${nodes.length}`); - console.log(` Successful: ${successful}`); - console.log(` Failed: ${failed}`); - console.log(` AI Tools: ${aiTools}`); - console.log('\n✨ Rebuild complete!'); - - db.close(); -} - -// Run if called directly -if (require.main === module) { - rebuild().catch(console.error); -} -``` - -**File**: `src/loaders/node-loader.ts` - -```typescript -export class N8nNodeLoader { - private readonly CORE_PACKAGES = [ - 'n8n-nodes-base', - '@n8n/n8n-nodes-langchain' - ]; - - async loadAllNodes() { - const results = []; - - for (const pkg of this.CORE_PACKAGES) { - try { - // Direct require - no complex path resolution - const packageJson = require(`${pkg}/package.json`); - const nodes = await this.loadPackageNodes(pkg, packageJson); - results.push(...nodes); - } catch (error) { - console.error(`Failed to load ${pkg}:`, error); - } - } - - return results; - } - - private async loadPackageNodes(packageName: string, packageJson: any) { - const n8nConfig = packageJson.n8n || {}; - const nodes = []; - - // Load from n8n.nodes configuration - for (const [nodeName, nodePath] of Object.entries(n8nConfig.nodes || {})) { - const fullPath = require.resolve(`${packageName}/${nodePath}`); - const nodeModule = require(fullPath); - - // Handle default export - const NodeClass = nodeModule.default || nodeModule[nodeName]; - nodes.push({ packageName, nodeName, NodeClass }); - } - - return nodes; - } -} -``` - -### Day 3: Simple Parser - -**File**: `src/parsers/simple-parser.ts` - -```typescript -export interface ParsedNode { - style: 'declarative' | 'programmatic'; - nodeType: string; - displayName: string; - description?: string; - category?: string; - properties: any[]; - credentials: string[]; - isAITool: boolean; - isTrigger: boolean; - isWebhook: boolean; - operations: any[]; - version?: string; - isVersioned: boolean; -} - -export class SimpleParser { - parse(nodeClass: any): ParsedNode { - const description = nodeClass.description || {}; - const isDeclarative = !!description.routing; - - return { - style: isDeclarative ? 'declarative' : 'programmatic', - nodeType: description.name, - displayName: description.displayName, - description: description.description, - category: description.group?.[0] || description.categories?.[0], - properties: description.properties || [], - credentials: description.credentials || [], - isAITool: description.usableAsTool === true, - isTrigger: description.polling === true || description.trigger === true, - isWebhook: description.webhooks?.length > 0, - operations: isDeclarative ? this.extractOperations(description.routing) : [], - version: this.extractVersion(nodeClass), - isVersioned: this.isVersionedNode(nodeClass) - }; - } - - private extractOperations(routing: any): any[] { - // Simple extraction without complex logic - const operations = []; - const resources = routing?.request?.resource?.options || []; - - resources.forEach(resource => { - operations.push({ - resource: resource.value, - name: resource.name - }); - }); - - return operations; - } - - private extractVersion(nodeClass: any): string { - if (nodeClass.baseDescription?.defaultVersion) { - return nodeClass.baseDescription.defaultVersion.toString(); - } - return nodeClass.description?.version || '1'; - } - - private isVersionedNode(nodeClass: any): boolean { - return !!(nodeClass.baseDescription && nodeClass.nodeVersions); - } -} -``` - -### Day 4: Documentation Mapper - -**File**: `src/mappers/docs-mapper.ts` - -```typescript -import { promises as fs } from 'fs'; -import path from 'path'; - -export class DocsMapper { - private docsPath = path.join(__dirname, '../../../n8n-docs'); - - // Known documentation mapping fixes - private readonly KNOWN_FIXES = { - 'n8n-nodes-base.httpRequest': 'httprequest', - 'n8n-nodes-base.code': 'code', - 'n8n-nodes-base.webhook': 'webhook', - 'n8n-nodes-base.respondToWebhook': 'respondtowebhook' - }; - - async fetchDocumentation(nodeType: string): Promise { - // Apply known fixes first - const fixedType = this.KNOWN_FIXES[nodeType] || nodeType; - - // Extract node name - const nodeName = fixedType.split('.').pop()?.toLowerCase(); - if (!nodeName) return null; - - // Try different documentation paths - const possiblePaths = [ - `docs/integrations/builtin/core-nodes/n8n-nodes-base.${nodeName}.md`, - `docs/integrations/builtin/app-nodes/n8n-nodes-base.${nodeName}.md`, - `docs/integrations/builtin/trigger-nodes/n8n-nodes-base.${nodeName}.md`, - `docs/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.${nodeName}.md` - ]; - - // Try each path - for (const relativePath of possiblePaths) { - try { - const fullPath = path.join(this.docsPath, relativePath); - const content = await fs.readFile(fullPath, 'utf-8'); - return content; - } catch (error) { - // File doesn't exist, try next - continue; - } - } - - return null; - } -} -``` - -### Day 5: Database Setup - -**File**: `src/database/schema.sql` - -```sql --- Ultra-simple schema for MVP -CREATE TABLE IF NOT EXISTS nodes ( - node_type TEXT PRIMARY KEY, - package_name TEXT NOT NULL, - display_name TEXT NOT NULL, - description TEXT, - category TEXT, - development_style TEXT CHECK(development_style IN ('declarative', 'programmatic')), - is_ai_tool INTEGER DEFAULT 0, - is_trigger INTEGER DEFAULT 0, - is_webhook INTEGER DEFAULT 0, - is_versioned INTEGER DEFAULT 0, - version TEXT, - documentation TEXT, - properties_schema TEXT, - operations TEXT, - credentials_required TEXT, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP -); - --- Minimal indexes for performance -CREATE INDEX IF NOT EXISTS idx_package ON nodes(package_name); -CREATE INDEX IF NOT EXISTS idx_ai_tool ON nodes(is_ai_tool); -CREATE INDEX IF NOT EXISTS idx_category ON nodes(category); -``` - -## Week 2: Integration and Testing - -### Day 6-7: Test Priority Nodes - -Focus on these nodes first (they cover most edge cases): - -1. **HTTP Request** - Known documentation mismatch -2. **Slack** - Complex declarative node -3. **Code** - Versioned node with documentation issues -4. **AI Agent** - LangChain node with AI tool flag - -### Day 8-9: MCP Server Updates - -**File**: `src/mcp/tools-update.ts` - -```typescript -// Simplified get_node_info tool -async function getNodeInfo(nodeType: string) { - const node = db.prepare(` - SELECT * FROM nodes WHERE node_type = ? - `).get(nodeType); - - if (!node) { - throw new Error(`Node ${nodeType} not found`); - } - - return { - nodeType: node.node_type, - displayName: node.display_name, - description: node.description, - category: node.category, - developmentStyle: node.development_style, - isAITool: !!node.is_ai_tool, - isTrigger: !!node.is_trigger, - isWebhook: !!node.is_webhook, - version: node.version, - properties: JSON.parse(node.properties_schema), - operations: JSON.parse(node.operations || '[]'), - credentials: JSON.parse(node.credentials_required), - documentation: node.documentation - }; -} - -// New tool: list_ai_tools -{ - name: 'list_ai_tools', - description: 'List all nodes that can be used as AI Agent tools', - inputSchema: { - type: 'object', - properties: {} - } -} - -async function listAITools() { - const tools = db.prepare(` - SELECT node_type, display_name, description, package_name - FROM nodes - WHERE is_ai_tool = 1 - ORDER BY display_name - `).all(); - - return { - tools, - totalCount: tools.length, - requirements: { - environmentVariable: 'N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true', - nodeProperty: 'usableAsTool: true' - } - }; -} -``` - -### Day 10: Validation Script - -**File**: `src/scripts/validate.ts` - -```typescript -#!/usr/bin/env node -import Database from 'better-sqlite3'; - -async function validate() { - const db = new Database('./data/nodes.db'); - - console.log('🔍 Validating critical nodes...\n'); - - const criticalChecks = [ - { - type: 'n8n-nodes-base.httpRequest', - checks: { - hasDocumentation: true, - documentationContains: 'httprequest', - style: 'programmatic' - } - }, - { - type: 'n8n-nodes-base.code', - checks: { - hasDocumentation: true, - documentationContains: 'code', - isVersioned: true - } - }, - { - type: 'n8n-nodes-base.slack', - checks: { - hasOperations: true, - style: 'declarative' - } - }, - { - type: '@n8n/n8n-nodes-langchain.agent', - checks: { - isAITool: true, - packageName: '@n8n/n8n-nodes-langchain' - } - } - ]; - - let passed = 0; - let failed = 0; - - for (const check of criticalChecks) { - const node = db.prepare('SELECT * FROM nodes WHERE node_type = ?').get(check.type); - - if (!node) { - console.log(`❌ ${check.type}: NOT FOUND`); - failed++; - continue; - } - - let nodeOk = true; - const issues = []; - - // Run checks - if (check.checks.hasDocumentation && !node.documentation) { - nodeOk = false; - issues.push('missing documentation'); - } - - if (check.checks.documentationContains && - !node.documentation?.includes(check.checks.documentationContains)) { - nodeOk = false; - issues.push(`documentation doesn't contain "${check.checks.documentationContains}"`); - } - - if (check.checks.style && node.development_style !== check.checks.style) { - nodeOk = false; - issues.push(`wrong style: ${node.development_style}`); - } - - if (check.checks.hasOperations) { - const operations = JSON.parse(node.operations || '[]'); - if (!operations.length) { - nodeOk = false; - issues.push('no operations found'); - } - } - - if (check.checks.isAITool && !node.is_ai_tool) { - nodeOk = false; - issues.push('not marked as AI tool'); - } - - if (check.checks.isVersioned && !node.is_versioned) { - nodeOk = false; - issues.push('not marked as versioned'); - } - - if (nodeOk) { - console.log(`✅ ${check.type}`); - passed++; - } else { - console.log(`❌ ${check.type}: ${issues.join(', ')}`); - failed++; - } - } - - console.log(`\n📊 Results: ${passed} passed, ${failed} failed`); - - // Additional statistics - const stats = db.prepare(` - SELECT - COUNT(*) as total, - SUM(is_ai_tool) as ai_tools, - SUM(is_trigger) as triggers, - SUM(is_versioned) as versioned, - COUNT(DISTINCT package_name) as packages - FROM nodes - `).get(); - - console.log('\n📈 Database Statistics:'); - console.log(` Total nodes: ${stats.total}`); - console.log(` AI tools: ${stats.ai_tools}`); - console.log(` Triggers: ${stats.triggers}`); - console.log(` Versioned: ${stats.versioned}`); - console.log(` Packages: ${stats.packages}`); - - db.close(); - process.exit(failed > 0 ? 1 : 0); -} - -if (require.main === module) { - validate().catch(console.error); -} -``` - -## MVP Deliverables Checklist - -### Week 1 ✅ -- [ ] Clone n8n-docs repository locally -- [ ] Build rebuild script first (test harness) -- [ ] Basic node loader for n8n-nodes-base and langchain packages -- [ ] Simple parser (no complex analysis) -- [ ] Documentation fetcher with file-based access -- [ ] SQLite database setup with minimal schema -- [ ] Get 5 nodes working end-to-end on Day 1 - -### Week 2 ✅ -- [ ] Test priority nodes (HTTP Request, Slack, Code, AI Agent) -- [ ] Fix all documentation mapping issues -- [ ] Update MCP tools for simplified schema -- [ ] Add AI tools listing functionality -- [ ] Create validation script -- [ ] Document usage instructions -- [ ] Run full validation suite - -## What We're Deferring Post-MVP - -1. **Version history tracking** - Just current version -2. **Source code extraction** - Not needed for documentation -3. **Complex property type analysis** - Keep n8n's structure as-is -4. **Custom node directory support** - Focus on npm packages only -5. **Performance optimizations** - SQLite is fast enough -6. **Real-time monitoring** - Static documentation only -7. **Web UI** - CLI tools only -8. **Multi-tenant support** - Single instance -9. **Advanced search** - Basic SQL queries are sufficient -10. **Community nodes** - Just official packages for now - -## Success Metrics - -1. **Accuracy**: 100% correct node-to-documentation mapping for test nodes -2. **Coverage**: All nodes from n8n-nodes-base and n8n-nodes-langchain -3. **Performance**: Full rebuild in <30 seconds -4. **Simplicity**: Single command rebuild (`npm run rebuild`) -5. **Reliability**: No failures on standard nodes -6. **Validation**: All critical nodes pass validation script - -## Quick Start Guide - -```bash -# Setup -git clone https://github.com/n8n-io/n8n-docs.git ../n8n-docs -npm install - -# Build -npm run build - -# Rebuild database -npm run rebuild - -# Validate -npm run validate - -# Start MCP server -npm start -``` - -## NPM Scripts - -```json -{ - "scripts": { - "build": "tsc", - "rebuild": "node dist/scripts/rebuild.js", - "validate": "node dist/scripts/validate.js", - "start": "node dist/mcp/server.js", - "dev": "npm run build && npm run rebuild && npm run validate" - } -} -``` - -## Summary - -This v2.1 Final plan delivers a working MVP in 2 weeks by: -- **Starting with the test harness** - Build rebuild script first -- **Getting quick wins** - 5 nodes on Day 1 -- **Testing critical nodes early** - HTTP Request, Slack, Code, AI Agent -- **Using local documentation** - Clone n8n-docs for file access -- **Validating success** - Automated validation script - -The result: A reliable, accurate node documentation service that can be enhanced incrementally post-MVP. - -**Ready to build! 🚀** \ No newline at end of file diff --git a/README_CLAUDE_SETUP.md b/README_CLAUDE_SETUP.md deleted file mode 100644 index daf7d80..0000000 --- a/README_CLAUDE_SETUP.md +++ /dev/null @@ -1,101 +0,0 @@ -# Claude Desktop Configuration for n8n-MCP - -## Setup Instructions - -1. **Build the project first:** - ```bash - cd /Users/romualdczlonkowski/Pliki/n8n-mcp/n8n-mcp - npm run build - npm run rebuild - ``` - -2. **Locate your Claude Desktop config file:** - - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` - - Windows: `%APPDATA%\Claude\claude_desktop_config.json` - - Linux: `~/.config/Claude/claude_desktop_config.json` - -3. **Add the n8n-documentation server to your config:** - ```json - { - "mcpServers": { - "n8n-documentation": { - "command": "node", - "args": [ - "/Users/johndoe/projects/n8n-mcp/dist/mcp/index.js" - ], - "env": { - "NODE_ENV": "production" - } - } - } - } - ``` - - **Note**: Update the path in `args` to match your actual installation directory. - -4. **Restart Claude Desktop** to load the new configuration. - -## Available Tools - -Once configured, you'll have access to these tools in Claude: - -- **`list_nodes`** - List and filter n8n nodes - ``` - list_nodes({ package: "n8n-nodes-base", limit: 10 }) - ``` - -- **`get_node_info`** - Get detailed information about a specific node - ``` - get_node_info({ nodeType: "httpRequest" }) - ``` - -- **`search_nodes`** - Search across all node documentation - ``` - search_nodes({ query: "webhook", limit: 20 }) - ``` - -- **`list_ai_tools`** - List nodes that can be used as AI Agent tools - ``` - list_ai_tools({}) - ``` - -- **`get_node_documentation`** - Get full documentation for a node - ``` - get_node_documentation({ nodeType: "slack" }) - ``` - -- **`get_database_statistics`** - Get statistics about the node database - ``` - get_database_statistics({}) - ``` - -## Troubleshooting - -1. **If the server doesn't appear in Claude:** - - Check that the path in `args` is absolute and correct - - Ensure you've run `npm run build` and `npm run rebuild` - - Check `~/.n8n-mcp/logs/` for error logs - -2. **If tools return errors:** - - Ensure the database exists: `data/nodes.db` - - Run `npm run validate` to check the database - - Rebuild if necessary: `npm run rebuild` - -3. **For development/testing:** - You can also run with more verbose logging: - ```json - { - "mcpServers": { - "n8n-documentation": { - "command": "node", - "args": [ - "/path/to/your/n8n-mcp/dist/mcp/index.js" - ], - "env": { - "NODE_ENV": "development", - "LOG_LEVEL": "debug" - } - } - } - } - ``` \ No newline at end of file diff --git a/CHANGELOG.md b/docs/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to docs/CHANGELOG.md diff --git a/docs/DOCKER_BUILD_FIX.md b/docs/DOCKER_BUILD_FIX.md new file mode 100644 index 0000000..8f8f8f9 --- /dev/null +++ b/docs/DOCKER_BUILD_FIX.md @@ -0,0 +1,62 @@ +# Docker Build Fix + +## Issue +The Docker build was failing with the error: +``` +ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref: "/data/nodes.db": not found +``` + +## Root Cause +The Dockerfile contained an invalid COPY command that tried to use shell operators: +```dockerfile +# This doesn't work in Docker +COPY --from=builder /app/data/nodes.db ./data/nodes.db 2>/dev/null || true +``` + +Docker's COPY command doesn't support shell operators like `2>/dev/null || true`. + +## Solution +1. Removed the problematic COPY command +2. Created the data directory with RUN instead +3. Removed database pre-initialization from build stage +4. Database is now initialized at runtime by the entrypoint script + +## Changes Made + +### Dockerfile +```diff +- # Pre-initialize database during build +- RUN mkdir -p /app/data && npm run rebuild || echo "Database will be initialized at runtime" ++ # Build TypeScript only ++ RUN npm run build + +- # Copy pre-built database if it exists +- COPY --from=builder /app/data/nodes.db ./data/nodes.db 2>/dev/null || true ++ # Create data directory ++ RUN mkdir -p /app/data +``` + +### GitHub Actions Workflow +Added conditional login to prevent failures on pull requests: +```diff +- name: Log in to GitHub Container Registry ++ if: github.event_name != 'pull_request' + uses: docker/login-action@v3 +``` + +## Result +✅ Docker build now succeeds +✅ Database initialization happens at container startup +✅ GitHub Actions workflow will work properly +✅ No manual intervention required + +## Testing +```bash +# Build locally +docker build -t n8n-mcp:test . + +# Run and verify +docker run -d --name test -e MCP_MODE=http -e AUTH_TOKEN=test -p 3000:3000 n8n-mcp:test +docker logs test +curl http://localhost:3000/health +``` \ No newline at end of file diff --git a/DOCKER_README.md b/docs/DOCKER_README.md similarity index 100% rename from DOCKER_README.md rename to docs/DOCKER_README.md diff --git a/docs/DOCKER_TESTING_RESULTS.md b/docs/DOCKER_TESTING_RESULTS.md index 3bca775..6b464d6 100644 --- a/docs/DOCKER_TESTING_RESULTS.md +++ b/docs/DOCKER_TESTING_RESULTS.md @@ -74,10 +74,11 @@ ### 🔧 Recommended Fixes -1. **Immediate (Phase 1)** - - Include schema.sql in Docker image - - Add scripts directory for rebuild functionality - - Test database initialization in clean environment +1. **Immediate (Phase 1)** ✅ FIXED + - ✅ Include schema.sql in Docker image + - ✅ Add scripts directory for rebuild functionality + - ✅ Removed invalid COPY syntax that caused build errors + - ✅ Database initialization happens at runtime, not build time 2. **Future Improvements (Phase 2)** - Optimize image size with multi-stage pruning diff --git a/docs/HTTP_DEPLOYMENT.md b/docs/HTTP_DEPLOYMENT.md index 9e64461..4833d65 100644 --- a/docs/HTTP_DEPLOYMENT.md +++ b/docs/HTTP_DEPLOYMENT.md @@ -6,17 +6,70 @@ This guide explains how to deploy n8n-MCP as a private HTTP server for remote ac The HTTP mode allows you to run n8n-MCP on a remote server and connect to it from Claude Desktop using the mcp-remote adapter. This is designed for single-user private deployments. -## Requirements +## Deployment Options -- Node.js v16+ on the server -- A server with a public IP or domain -- HTTPS proxy (nginx/caddy) for secure connections -- mcp-remote installed on the client +### Option 1: Docker Deployment (Recommended) 🐳 -## Server Setup +The easiest way to deploy n8n-MCP is using Docker: -### 1. Clone and Build +#### Quick Start +```bash +# 1. Create configuration +echo "AUTH_TOKEN=$(openssl rand -base64 32)" > .env +# 2. Start with Docker Compose +docker compose up -d + +# 3. Check health +curl http://localhost:3000/health +``` + +#### Production Deployment +```bash +# 1. Clone repository +git clone https://github.com/yourusername/n8n-mcp.git +cd n8n-mcp + +# 2. Create production .env +cat > .env << EOF +AUTH_TOKEN=$(openssl rand -base64 32) +NODE_ENV=production +LOG_LEVEL=info +PORT=3000 +EOF + +# 3. Deploy with Docker Compose +docker compose up -d + +# 4. Check logs +docker compose logs -f +``` + +#### Using Pre-built Images +```yaml +# docker-compose.yml +version: '3.8' +services: + n8n-mcp: + image: ghcr.io/czlonkowski/n8n-mcp:latest + environment: + MCP_MODE: http + AUTH_TOKEN: ${AUTH_TOKEN:?Required} + ports: + - "3000:3000" + volumes: + - n8n-mcp-data:/app/data + restart: unless-stopped + +volumes: + n8n-mcp-data: +``` + +### Option 2: Manual Installation + +If you prefer not to use Docker: + +#### 1. Clone and Build ```bash git clone https://github.com/yourusername/n8n-mcp.git cd n8n-mcp @@ -25,8 +78,7 @@ npm run build npm run rebuild ``` -### 2. Configure Environment - +#### 2. Configure Environment ```bash cp .env.example .env ``` @@ -47,13 +99,7 @@ MCP_LOG_LEVEL=info NODE_ENV=production ``` -Generate a secure token: -```bash -openssl rand -base64 32 -``` - -### 3. Start the Server - +#### 3. Start the Server ```bash # Using the deployment script ./scripts/deploy-http.sh @@ -220,33 +266,95 @@ The test script checks: ## Troubleshooting -### Connection Refused +### Docker-specific Issues + +#### Container won't start +```bash +# Check logs +docker compose logs n8n-mcp + +# Check if port is already in use +lsof -i :3000 + +# Rebuild and restart +docker compose down +docker compose up -d --build +``` + +#### Database initialization fails +```bash +# Copy existing database +docker cp data/nodes.db n8n-mcp:/app/data/ + +# Or rebuild inside container +docker compose exec n8n-mcp npm run rebuild +``` + +#### Permission issues +```bash +# Fix volume permissions +docker compose exec n8n-mcp chown -R nodejs:nodejs /app/data +``` + +### General Issues + +#### Connection Refused - Check firewall rules - Verify server is running - Check nginx/proxy configuration - Run the test script to diagnose +- For Docker: ensure ports are mapped correctly -### Authentication Failed +#### Authentication Failed - Verify AUTH_TOKEN matches in both server and client - Check Authorization header format - Token should be at least 32 characters +- Docker: check .env file is loaded -### MCP Tools Not Available +#### MCP Tools Not Available - Restart Claude Desktop - Check mcp-remote installation - Verify server logs for errors - Ensure CORS headers are working +- Docker: check container health status ## Performance Tips 1. Use a VPS with good network connectivity 2. Enable gzip compression in your proxy -3. Consider using PM2 for process management: +3. For Docker deployments: + - Use `--restart unless-stopped` for reliability + - Monitor with `docker stats n8n-mcp` + - Set memory limits in docker-compose.yml +4. For manual deployments, use PM2: ```bash pm2 start npm --name "n8n-mcp" -- run start:http ``` -## Example Systemd Service +## Production Deployment Examples + +### Using Docker with Systemd + +Create `/etc/systemd/system/n8n-mcp-docker.service`: + +```ini +[Unit] +Description=n8n MCP Docker Container +After=docker.service +Requires=docker.service + +[Service] +Type=simple +WorkingDirectory=/opt/n8n-mcp +ExecStart=/usr/bin/docker compose up +ExecStop=/usr/bin/docker compose down +Restart=on-failure + +[Install] +WantedBy=multi-user.target +``` + +### Manual Installation with Systemd Create `/etc/systemd/system/n8n-mcp.service`: diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md new file mode 100644 index 0000000..6b2b152 --- /dev/null +++ b/docs/INSTALLATION.md @@ -0,0 +1,331 @@ +# Installation Guide + +This guide covers all installation methods for n8n-MCP. + +## Table of Contents + +- [Quick Start](#quick-start) +- [Docker Installation](#docker-installation) +- [Manual Installation](#manual-installation) +- [Development Setup](#development-setup) +- [Troubleshooting](#troubleshooting) + +## Quick Start + +The fastest way to get n8n-MCP running: + +```bash +# Using Docker (recommended) +echo "AUTH_TOKEN=$(openssl rand -base64 32)" > .env +docker compose up -d +``` + +## Docker Installation + +### Prerequisites + +- Docker Desktop or Docker Engine +- Docker Compose (included with Docker Desktop) + +### Method 1: Using Pre-built Images + +1. **Create a project directory:** + ```bash + mkdir n8n-mcp && cd n8n-mcp + ``` + +2. **Create docker-compose.yml:** + ```yaml + version: '3.8' + + services: + n8n-mcp: + image: ghcr.io/czlonkowski/n8n-mcp:latest + container_name: n8n-mcp + restart: unless-stopped + + environment: + MCP_MODE: ${MCP_MODE:-http} + AUTH_TOKEN: ${AUTH_TOKEN:?AUTH_TOKEN is required} + NODE_ENV: ${NODE_ENV:-production} + LOG_LEVEL: ${LOG_LEVEL:-info} + PORT: ${PORT:-3000} + + volumes: + - n8n-mcp-data:/app/data + + ports: + - "${PORT:-3000}:3000" + + healthcheck: + test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/health"] + interval: 30s + timeout: 10s + retries: 3 + + volumes: + n8n-mcp-data: + driver: local + ``` + +3. **Create .env file:** + ```bash + echo "AUTH_TOKEN=$(openssl rand -base64 32)" > .env + ``` + +4. **Start the container:** + ```bash + docker compose up -d + ``` + +5. **Verify installation:** + ```bash + curl http://localhost:3000/health + ``` + +### Method 2: Building from Source + +1. **Clone the repository:** + ```bash + git clone https://github.com/czlonkowski/n8n-mcp.git + cd n8n-mcp + ``` + +2. **Build the image:** + ```bash + docker build -t n8n-mcp:local . + ``` + +3. **Run with docker-compose:** + ```bash + docker compose up -d + ``` + +### Docker Management Commands + +```bash +# View logs +docker compose logs -f + +# Stop the container +docker compose stop + +# Remove container and volumes +docker compose down -v + +# Update to latest image +docker compose pull +docker compose up -d + +# Execute commands inside container +docker compose exec n8n-mcp npm run validate + +# Backup database +docker cp n8n-mcp:/app/data/nodes.db ./nodes-backup.db +``` + +## Manual Installation + +### Prerequisites + +- Node.js v16+ (v20+ recommended) +- npm or yarn +- Git + +### Step-by-Step Installation + +1. **Clone the repository:** + ```bash + git clone https://github.com/czlonkowski/n8n-mcp.git + cd n8n-mcp + ``` + +2. **Clone n8n documentation (optional but recommended):** + ```bash + git clone https://github.com/n8n-io/n8n-docs.git ../n8n-docs + ``` + +3. **Install dependencies:** + ```bash + npm install + ``` + +4. **Build the project:** + ```bash + npm run build + ``` + +5. **Initialize the database:** + ```bash + npm run rebuild + ``` + +6. **Validate installation:** + ```bash + npm run test-nodes + ``` + +### Running the Server + +#### stdio Mode (for Claude Desktop) +```bash +npm start +``` + +#### HTTP Mode (for remote access) +```bash +npm run start:http +``` + +### Environment Configuration + +Create a `.env` file in the project root: + +```env +# Server configuration +MCP_MODE=http # or stdio +PORT=3000 +HOST=0.0.0.0 +NODE_ENV=production +LOG_LEVEL=info + +# Authentication (required for HTTP mode) +AUTH_TOKEN=your-secure-token-here + +# Database +NODE_DB_PATH=./data/nodes.db +REBUILD_ON_START=false +``` + +## Development Setup + +### Prerequisites + +- All manual installation prerequisites +- TypeScript knowledge +- Familiarity with MCP protocol + +### Setup Steps + +1. **Clone and install:** + ```bash + git clone https://github.com/czlonkowski/n8n-mcp.git + cd n8n-mcp + npm install + ``` + +2. **Set up development environment:** + ```bash + cp .env.example .env + # Edit .env with your settings + ``` + +3. **Development commands:** + ```bash + # Run in development mode with auto-reload + npm run dev + + # Run tests + npm test + + # Type checking + npm run typecheck + + # Linting + npm run lint + ``` + +### Docker Development + +1. **Use docker-compose override:** + ```bash + cp docker-compose.override.yml.example docker-compose.override.yml + ``` + +2. **Edit override for development:** + ```yaml + version: '3.8' + + services: + n8n-mcp: + build: . + environment: + NODE_ENV: development + LOG_LEVEL: debug + volumes: + - ./src:/app/src:ro + - ./dist:/app/dist + ``` + +3. **Run with live reload:** + ```bash + docker compose up --build + ``` + +## Troubleshooting + +### Common Issues + +#### Port Already in Use +```bash +# Find process using port 3000 +lsof -i :3000 + +# Use a different port +PORT=3001 docker compose up -d +``` + +#### Database Initialization Failed +```bash +# For Docker +docker compose exec n8n-mcp npm run rebuild + +# For manual installation +npm run rebuild +``` + +#### Permission Denied Errors +```bash +# Fix permissions (Linux/macOS) +sudo chown -R $(whoami) ./data + +# For Docker volumes +docker compose exec n8n-mcp chown -R nodejs:nodejs /app/data +``` + +#### Node Version Mismatch +The project includes automatic fallback to sql.js for compatibility. If you still have issues: +```bash +# Check Node version +node --version + +# Use nvm to switch versions +nvm use 20 +``` + +### Getting Help + +1. Check the logs: + - Docker: `docker compose logs` + - Manual: Check console output or `LOG_LEVEL=debug npm start` + +2. Validate the database: + ```bash + npm run validate + ``` + +3. Run tests: + ```bash + npm test + ``` + +4. Report issues: + - GitHub Issues: https://github.com/czlonkowski/n8n-mcp/issues + - Include logs and environment details + +## Next Steps + +After installation, configure Claude Desktop to use n8n-MCP: +- See [Claude Desktop Setup Guide](./README_CLAUDE_SETUP.md) +- For remote deployments, see [HTTP Deployment Guide](./HTTP_DEPLOYMENT.md) +- For Docker details, see [Docker README](../DOCKER_README.md) \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..fd41b80 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,66 @@ +# n8n-MCP Documentation + +Welcome to the n8n-MCP documentation. This directory contains comprehensive guides for installation, configuration, and troubleshooting. + +## 📚 Documentation Index + +### Getting Started +- **[Installation Guide](./INSTALLATION.md)** - All installation methods including Docker, manual, and development setup +- **[Claude Desktop Setup](./README_CLAUDE_SETUP.md)** - Configure Claude Desktop to use n8n-MCP +- **[Quick Start Tutorial](../README.md)** - Basic overview and quick start instructions + +### Deployment +- **[HTTP Deployment Guide](./HTTP_DEPLOYMENT.md)** - Deploy n8n-MCP as an HTTP server for remote access +- **[Docker Deployment](../DOCKER_README.md)** - Comprehensive Docker deployment guide +- **[Docker Testing Results](./DOCKER_TESTING_RESULTS.md)** - Docker implementation test results and findings + +### Development +- **[Implementation Plan](../IMPLEMENTATION_PLAN.md)** - Technical implementation details +- **[HTTP Implementation Guide](./HTTP_IMPLEMENTATION_GUIDE.md)** - HTTP server implementation details +- **[Development Setup](./INSTALLATION.md#development-setup)** - Set up development environment + +### Reference +- **[Troubleshooting Guide](./TROUBLESHOOTING.md)** - Solutions for common issues +- **[API Reference](./API_REFERENCE.md)** - MCP tools and API documentation (if available) +- **[Environment Variables](./INSTALLATION.md#environment-configuration)** - Configuration options + +## 🚀 Quick Links + +### For Users +1. **First Time Setup**: Start with the [Installation Guide](./INSTALLATION.md) +2. **Claude Desktop Users**: Follow [Claude Desktop Setup](./README_CLAUDE_SETUP.md) +3. **Remote Deployment**: See [HTTP Deployment Guide](./HTTP_DEPLOYMENT.md) + +### For Developers +1. **Local Development**: See [Development Setup](./INSTALLATION.md#development-setup) +2. **Docker Development**: Check [Docker README](../DOCKER_README.md) +3. **Contributing**: Read the implementation plans and guides + +## 🐳 Docker Quick Start + +```bash +# Quick start with Docker +echo "AUTH_TOKEN=$(openssl rand -base64 32)" > .env +docker compose up -d + +# Check health +curl http://localhost:3000/health +``` + +## 📖 Documentation Updates + +This documentation is actively maintained. Recent updates include: +- ✅ Docker deployment support (Phase 1 complete) +- ✅ Simplified installation process +- ✅ Enhanced troubleshooting guide +- ✅ Multiple deployment options + +## 🤝 Getting Help + +- **Issues**: [GitHub Issues](https://github.com/czlonkowski/n8n-mcp/issues) +- **Discussions**: [GitHub Discussions](https://github.com/czlonkowski/n8n-mcp/discussions) +- **Troubleshooting**: [Troubleshooting Guide](./TROUBLESHOOTING.md) + +## 📝 License + +This project is licensed under the Sustainable Use License. See [LICENSE](../LICENSE) for details. \ No newline at end of file diff --git a/docs/README_CLAUDE_SETUP.md b/docs/README_CLAUDE_SETUP.md new file mode 100644 index 0000000..574ee63 --- /dev/null +++ b/docs/README_CLAUDE_SETUP.md @@ -0,0 +1,203 @@ +# Claude Desktop Configuration for n8n-MCP + +## Setup Options + +You can set up n8n-MCP with Claude Desktop in three ways: + +### Option 1: Docker (Recommended) 🐳 + +The easiest way to get started is using Docker: + +#### 1a. Docker with HTTP Mode (Remote Access) +```json +{ + "mcpServers": { + "n8n-remote": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/mcp-remote@latest", + "connect", + "http://localhost:3000/mcp" + ], + "env": { + "MCP_AUTH_TOKEN": "your-auth-token-here" + } + } + } +} +``` + +**Setup steps:** +1. Create a `.env` file: + ```bash + echo "AUTH_TOKEN=$(openssl rand -base64 32)" > .env + ``` +2. Start the server: + ```bash + docker compose up -d + ``` +3. Copy the AUTH_TOKEN to your Claude config + +#### 1b. Docker with stdio Mode (Direct) +```json +{ + "mcpServers": { + "n8n-docker": { + "command": "docker", + "args": [ + "run", + "--rm", + "-i", + "-e", "MCP_MODE=stdio", + "-v", "n8n-mcp-data:/app/data", + "ghcr.io/czlonkowski/n8n-mcp:latest" + ] + } + } +} +``` + +### Option 2: Local Installation + +1. **Build the project first:** + ```bash + cd /path/to/n8n-mcp + npm install + npm run build + npm run rebuild + ``` + +2. **Add to Claude Desktop config:** + ```json + { + "mcpServers": { + "n8n-documentation": { + "command": "node", + "args": [ + "/path/to/n8n-mcp/dist/mcp/index.js" + ], + "env": { + "NODE_ENV": "production" + } + } + } + } + ``` + +### Option 3: NPM Global Install (Coming Soon) + +```json +{ + "mcpServers": { + "n8n-documentation": { + "command": "npx", + "args": [ + "-y", + "n8n-mcp@latest" + ] + } + } +} +``` + +## Configuration File Locations + +- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` +- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` +- **Linux**: `~/.config/Claude/claude_desktop_config.json` + +After updating the config, **restart Claude Desktop** to load the new configuration. + +## Available Tools + +Once configured, you'll have access to these tools in Claude: + +- **`list_nodes`** - List and filter n8n nodes + ``` + list_nodes({ package: "n8n-nodes-base", limit: 10 }) + ``` + +- **`get_node_info`** - Get detailed information about a specific node + ``` + get_node_info({ nodeType: "httpRequest" }) + ``` + +- **`search_nodes`** - Search across all node documentation + ``` + search_nodes({ query: "webhook", limit: 20 }) + ``` + +- **`list_ai_tools`** - List nodes that can be used as AI Agent tools + ``` + list_ai_tools({}) + ``` + +- **`get_node_documentation`** - Get full documentation for a node + ``` + get_node_documentation({ nodeType: "slack" }) + ``` + +- **`get_database_statistics`** - Get statistics about the node database + ``` + get_database_statistics({}) + ``` + +## Troubleshooting + +### Docker Issues + +1. **Container fails to start:** + ```bash + # Check logs + docker compose logs -f + + # Check if port is in use + lsof -i :3000 + ``` + +2. **Authentication errors:** + - Ensure AUTH_TOKEN matches in .env and Claude config + - Token should be at least 32 characters + - Check quotes in JSON config + +3. **Database not found:** + - The container will auto-initialize on first run + - To rebuild: `docker compose exec n8n-mcp npm run rebuild` + +### Local Installation Issues + +1. **If the server doesn't appear in Claude:** + - Check that the path in `args` is absolute and correct + - Ensure you've run `npm run build` and `npm run rebuild` + - Verify Node.js version compatibility + +2. **If tools return errors:** + - Ensure the database exists: `data/nodes.db` + - Run `npm run validate` to check the database + - Rebuild if necessary: `npm run rebuild` + +3. **For development/testing:** + ```json + { + "mcpServers": { + "n8n-documentation": { + "command": "node", + "args": [ + "/path/to/your/n8n-mcp/dist/mcp/index.js" + ], + "env": { + "NODE_ENV": "development", + "LOG_LEVEL": "debug" + } + } + } + } + ``` + +### Common Solutions + +- **Restart Claude Desktop** after config changes +- **Check file permissions** on Unix systems +- **Use absolute paths** in configuration +- **Verify JSON syntax** in claude_desktop_config.json \ No newline at end of file diff --git a/SETUP.md b/docs/SETUP.md similarity index 100% rename from SETUP.md rename to docs/SETUP.md diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md new file mode 100644 index 0000000..418b35f --- /dev/null +++ b/docs/TROUBLESHOOTING.md @@ -0,0 +1,402 @@ +# Troubleshooting Guide + +This guide helps resolve common issues with n8n-MCP. + +## Table of Contents + +- [Docker Issues](#docker-issues) +- [Installation Issues](#installation-issues) +- [Runtime Errors](#runtime-errors) +- [Claude Desktop Issues](#claude-desktop-issues) +- [Database Problems](#database-problems) +- [Network and Authentication](#network-and-authentication) +- [Performance Issues](#performance-issues) + +## Docker Issues + +### Container Won't Start + +#### Symptoms +- `docker compose up` fails +- Container exits immediately +- No logs available + +#### Solutions + +1. **Check if port is in use:** + ```bash + lsof -i :3000 + # or + netstat -tulpn | grep 3000 + ``` + +2. **View detailed logs:** + ```bash + docker compose logs -f --tail 100 + ``` + +3. **Check Docker resources:** + ```bash + docker system df + docker system prune -a # Clean up unused resources + ``` + +4. **Verify image download:** + ```bash + docker compose pull + ``` + +### Database Initialization Fails in Docker + +#### Symptoms +- Error: `ENOENT: no such file or directory, open '/app/src/database/schema.sql'` +- Database not found errors + +#### Solutions + +1. **Rebuild the image with latest Dockerfile:** + ```bash + docker compose build --no-cache + docker compose up -d + ``` + +2. **Copy existing database:** + ```bash + # From host to container + docker cp data/nodes.db n8n-mcp:/app/data/ + + # Restart container + docker compose restart + ``` + +3. **Initialize inside container:** + ```bash + docker compose exec n8n-mcp npm run rebuild + ``` + +### Permission Denied in Docker + +#### Symptoms +- Cannot write to /app/data +- Permission denied errors in logs + +#### Solutions + +```bash +# Fix permissions +docker compose exec n8n-mcp chown -R nodejs:nodejs /app/data + +# Or run as root temporarily +docker compose exec -u root n8n-mcp chown -R nodejs:nodejs /app +``` + +### Docker Compose Variables Not Loading + +#### Symptoms +- AUTH_TOKEN not recognized +- Environment variables missing + +#### Solutions + +1. **Check .env file location:** + ```bash + ls -la .env + cat .env + ``` + +2. **Verify compose file:** + ```bash + docker compose config + ``` + +3. **Set variables explicitly:** + ```bash + AUTH_TOKEN=mytoken docker compose up -d + ``` + +## Installation Issues + +### npm install Fails + +#### Symptoms +- Dependency errors +- Node version mismatch +- Native module compilation fails + +#### Solutions + +1. **Clear npm cache:** + ```bash + npm cache clean --force + rm -rf node_modules package-lock.json + npm install + ``` + +2. **Check Node version:** + ```bash + node --version # Should be v16+ + npm --version # Should be v7+ + ``` + +3. **Use fallback for better-sqlite3:** + The project automatically falls back to sql.js if native modules fail. + +### Build Errors + +#### Symptoms +- TypeScript compilation errors +- Missing type definitions + +#### Solutions + +```bash +# Clean build +rm -rf dist +npm run build + +# Check TypeScript version +npx tsc --version + +# Install missing types +npm install --save-dev @types/node +``` + +## Runtime Errors + +### MCP Tools Not Available + +#### Symptoms +- Tools don't appear in Claude Desktop +- "Unknown tool" errors + +#### Solutions + +1. **Verify server is running:** + ```bash + # For Docker + docker compose ps + docker compose logs + + # For local + ps aux | grep node + ``` + +2. **Check database:** + ```bash + npm run validate + npm run test-nodes + ``` + +3. **Restart Claude Desktop** after configuration changes + +### Stream Not Readable Error + +#### Symptoms +- Error: "InternalServerError: stream is not readable" +- MCP endpoint returns errors + +#### Solutions + +1. **Check database initialization:** + ```bash + ls -la data/nodes.db + npm run validate + ``` + +2. **Verify HTTP headers:** + ```bash + curl -H "Accept: application/json, text/event-stream" \ + -H "Authorization: Bearer $AUTH_TOKEN" \ + http://localhost:3000/mcp + ``` + +## Claude Desktop Issues + +### Server Not Appearing + +#### Solutions + +1. **Verify config file location:** + - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` + - Windows: `%APPDATA%\Claude\claude_desktop_config.json` + - Linux: `~/.config/Claude/claude_desktop_config.json` + +2. **Check JSON syntax:** + ```bash + # Validate JSON + cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | jq . + ``` + +3. **Use absolute paths:** + ```json + { + "mcpServers": { + "n8n-documentation": { + "command": "node", + "args": [ + "/absolute/path/to/n8n-mcp/dist/mcp/index.js" + ] + } + } + } + ``` + +### Authentication Errors with Claude + +#### Solutions + +1. **Match tokens exactly:** + ```bash + # In .env + AUTH_TOKEN=your-token-here + + # In Claude config + "MCP_AUTH_TOKEN": "your-token-here" + ``` + +2. **Check for special characters:** + - Avoid quotes in token values + - Use base64 encoding for safety + +## Database Problems + +### Database Corruption + +#### Symptoms +- SQLite errors +- Unexpected results +- Missing nodes + +#### Solutions + +1. **Rebuild database:** + ```bash + # Backup first + cp data/nodes.db data/nodes.db.bak + + # Rebuild + npm run rebuild + ``` + +2. **Validate after rebuild:** + ```bash + npm run validate + npm run test-nodes + ``` + +### Database Locked + +#### Symptoms +- SQLITE_BUSY errors +- Cannot write to database + +#### Solutions + +```bash +# Find processes using the database +lsof data/nodes.db + +# For Docker +docker compose restart +``` + +## Network and Authentication + +### CORS Errors + +#### Symptoms +- Browser console shows CORS errors +- Preflight requests fail + +#### Solutions + +1. **Check server CORS settings:** + - Verify MCP_MODE=http + - Check proxy configuration + +2. **Test with curl:** + ```bash + curl -X OPTIONS http://localhost:3000/mcp \ + -H "Origin: http://localhost" \ + -H "Access-Control-Request-Method: POST" + ``` + +### SSL/HTTPS Issues + +#### Solutions + +1. **For development, use HTTP:** + ```json + "connect", "http://localhost:3000/mcp" + ``` + +2. **For production, use reverse proxy:** + - See nginx/Caddy examples in HTTP_DEPLOYMENT.md + +## Performance Issues + +### Slow Response Times + +#### Solutions + +1. **Check resource usage:** + ```bash + # Docker + docker stats n8n-mcp + + # System + top + htop + ``` + +2. **Increase memory limits:** + ```yaml + # docker-compose.yml + deploy: + resources: + limits: + memory: 1G + ``` + +3. **Enable query logging:** + ```bash + LOG_LEVEL=debug npm start + ``` + +### High Memory Usage + +#### Solutions + +1. **Monitor with Docker:** + ```bash + docker compose exec n8n-mcp ps aux + ``` + +2. **Restart periodically:** + ```bash + # Add to crontab + 0 */6 * * * docker compose restart + ``` + +## Getting More Help + +1. **Enable debug logging:** + ```bash + LOG_LEVEL=debug docker compose up + ``` + +2. **Collect diagnostic info:** + ```bash + # System info + uname -a + node --version + docker --version + + # Project info + git rev-parse HEAD + npm list + ``` + +3. **Report issues:** + - GitHub: https://github.com/czlonkowski/n8n-mcp/issues + - Include logs, environment, and steps to reproduce \ No newline at end of file