diff --git a/.github/workflows/docker-build-n8n.yml b/.github/workflows/docker-build-n8n.yml index 1134bb4..d7c4b95 100644 --- a/.github/workflows/docker-build-n8n.yml +++ b/.github/workflows/docker-build-n8n.yml @@ -52,6 +52,9 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 609de27..efe2a58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.28.4] - 2025-12-05 + +### Features + +**Configurable MAX_SESSIONS Limit (#468)** + +The `MAX_SESSIONS` limit is now configurable via the `N8N_MCP_MAX_SESSIONS` environment variable, addressing scalability issues for multi-tenant SaaS deployments. + +- **Problem**: Hardcoded limit of 100 concurrent sessions caused "Session limit reached" errors during peak usage +- **Solution**: `MAX_SESSIONS` now reads from `N8N_MCP_MAX_SESSIONS` env var (default: 100) +- **Usage**: Set `N8N_MCP_MAX_SESSIONS=1000` for higher capacity deployments +- **Safety**: Includes `Math.max(1, ...)` floor to prevent invalid configurations +- **Files**: `src/http-server-single-session.ts:44` + +```bash +# Example: Allow up to 1000 concurrent sessions +N8N_MCP_MAX_SESSIONS=1000 +``` + ## [2.28.3] - 2025-12-02 ### Changed @@ -596,7 +615,7 @@ Added export/restore functionality for MCP sessions to enable zero-downtime depl - `restoreSessionState(sessions)` method for session recovery - Validates session structure using existing `validateInstanceContext()` - Handles null/invalid sessions gracefully with warnings -- Enforces MAX_SESSIONS limit (100 concurrent sessions) +- Enforces MAX_SESSIONS limit (default 100, configurable via N8N_MCP_MAX_SESSIONS env var) - Skips expired sessions during restore **3. SessionState Type** diff --git a/CLAUDE.md b/CLAUDE.md index 6e4dc35..e3a58a4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -209,7 +209,7 @@ The MCP server exposes tools in several categories: - **Security-first**: API keys exported as plaintext - downstream MUST encrypt - **Dormant sessions**: Restored sessions recreate transports on first request - **Automatic expiration**: Respects `sessionTimeout` setting (default 30 min) -- **MAX_SESSIONS limit**: Caps at 100 concurrent sessions +- **MAX_SESSIONS limit**: Caps at 100 concurrent sessions (configurable via N8N_MCP_MAX_SESSIONS env var) **Important Implementation Notes:** - Only exports sessions with valid n8nApiUrl and n8nApiKey in context diff --git a/docs/LIBRARY_USAGE.md b/docs/LIBRARY_USAGE.md index f3fbebd..928c24d 100644 --- a/docs/LIBRARY_USAGE.md +++ b/docs/LIBRARY_USAGE.md @@ -558,7 +558,7 @@ DISABLE_CONSOLE_OUTPUT=false # Optional: Session configuration SESSION_TIMEOUT=1800000 # 30 minutes in milliseconds -MAX_SESSIONS=100 +N8N_MCP_MAX_SESSIONS=100 # Maximum concurrent sessions (default: 100) # Optional: Performance NODE_ENV=production diff --git a/docs/SESSION_PERSISTENCE.md b/docs/SESSION_PERSISTENCE.md index d31ffc0..bb99662 100644 --- a/docs/SESSION_PERSISTENCE.md +++ b/docs/SESSION_PERSISTENCE.md @@ -93,7 +93,7 @@ console.log(`Restored ${count} sessions`); - Validates session metadata (timestamps, required fields) - Skips expired sessions (age > sessionTimeout) - Skips duplicate sessions (idempotent) -- Respects MAX_SESSIONS limit (100 per container) +- Respects MAX_SESSIONS limit (default 100, configurable via N8N_MCP_MAX_SESSIONS env var) - Recreates transports/servers lazily on first request - Logs security events for restore success/failure @@ -595,19 +595,19 @@ console.log(`Export size: ${sizeKB.toFixed(2)} KB`); ### MAX_SESSIONS Limit -Hard limit: 100 sessions per container +Default limit: 100 sessions per container (configurable via `N8N_MCP_MAX_SESSIONS` env var) ```typescript // Restore respects limit const sessions = createSessions(150); // 150 sessions const restored = engine.restoreSessionState(sessions); -// restored = 100 (only first 100 restored) +// restored = 100 (only first 100 restored, or N8N_MCP_MAX_SESSIONS value) ``` -For >100 sessions per tenant: -- Deploy multiple containers -- Use session routing/sharding -- Implement session affinity +For higher session limits: +- Set `N8N_MCP_MAX_SESSIONS=1000` (or desired limit) +- Monitor memory usage as sessions consume resources +- Alternatively, deploy multiple containers with session routing/sharding ## Troubleshooting @@ -676,10 +676,11 @@ Reached MAX_SESSIONS limit (100), skipping remaining sessions **Solutions:** -1. Scale horizontally (more containers) -2. Implement session sharding -3. Reduce sessionTimeout -4. Clean up inactive sessions +1. Increase limit: Set `N8N_MCP_MAX_SESSIONS=1000` (or desired value) +2. Scale horizontally (more containers) +3. Implement session sharding +4. Reduce sessionTimeout +5. Clean up inactive sessions ```typescript // Pre-filter by activity diff --git a/package-lock.json b/package-lock.json index e47edf7..da68c4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "n8n-mcp", - "version": "2.28.2", + "version": "2.28.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "n8n-mcp", - "version": "2.28.2", + "version": "2.28.4", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "1.20.1", diff --git a/package.json b/package.json index 02a4ee3..1893e6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n-mcp", - "version": "2.28.3", + "version": "2.28.4", "description": "Integration between n8n workflow automation and Model Context Protocol (MCP)", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/http-server-single-session.ts b/src/http-server-single-session.ts index 7400fc2..58d3406 100644 --- a/src/http-server-single-session.ts +++ b/src/http-server-single-session.ts @@ -41,7 +41,7 @@ interface MultiTenantHeaders { } // Session management constants -const MAX_SESSIONS = 100; +const MAX_SESSIONS = Math.max(1, parseInt(process.env.N8N_MCP_MAX_SESSIONS || '100', 10)); const SESSION_CLEANUP_INTERVAL = 5 * 60 * 1000; // 5 minutes interface Session { diff --git a/tests/unit/http-server/session-persistence.test.ts b/tests/unit/http-server/session-persistence.test.ts index e7ff177..143f8f4 100644 --- a/tests/unit/http-server/session-persistence.test.ts +++ b/tests/unit/http-server/session-persistence.test.ts @@ -427,7 +427,7 @@ describe('SingleSessionHTTPServer - Session Persistence', () => { }); it('should respect MAX_SESSIONS limit during restore', () => { - // Create 99 existing sessions (MAX_SESSIONS is 100) + // Create 99 existing sessions (MAX_SESSIONS defaults to 100, configurable via N8N_MCP_MAX_SESSIONS env var) const serverAny = server as any; const now = new Date(); for (let i = 0; i < 99; i++) {