fix: implement Single-Session architecture to resolve MCP stream errors
- Add ConsoleManager to prevent console output interference with StreamableHTTPServerTransport - Implement SingleSessionHTTPServer with persistent session reuse - Create N8NMCPEngine for clean service integration - Add automatic session expiry after 30 minutes of inactivity - Update logger to be HTTP-aware during active requests - Maintain backward compatibility with existing deployments This fixes the "stream is not readable" error by implementing the Hybrid Single-Session architecture as documented in MCP_ERROR_FIX_PLAN.md 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
172
docs/SINGLE_SESSION_IMPLEMENTATION.md
Normal file
172
docs/SINGLE_SESSION_IMPLEMENTATION.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# Single-Session HTTP Server Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the implementation of the Hybrid Single-Session architecture that fixes the "stream is not readable" error in the n8n-MCP HTTP server.
|
||||
|
||||
## Architecture
|
||||
|
||||
The Single-Session architecture maintains one persistent MCP session that is reused across all requests, providing:
|
||||
- Protocol compliance with StreamableHTTPServerTransport
|
||||
- Simple state management (one session only)
|
||||
- Automatic session expiry after 30 minutes of inactivity
|
||||
- Clean console output management
|
||||
|
||||
## Key Components
|
||||
|
||||
### 1. ConsoleManager (`src/utils/console-manager.ts`)
|
||||
Prevents console output from interfering with the StreamableHTTPServerTransport:
|
||||
- Silences all console methods during MCP request handling
|
||||
- Automatically restores console after request completion
|
||||
- Only active in HTTP mode
|
||||
|
||||
### 2. SingleSessionHTTPServer (`src/http-server-single-session.ts`)
|
||||
Core implementation of the single-session architecture:
|
||||
- Maintains one persistent session with StreamableHTTPServerTransport
|
||||
- Automatically creates/resets session as needed
|
||||
- Wraps all operations with ConsoleManager
|
||||
- Handles authentication and request routing
|
||||
|
||||
### 3. N8NMCPEngine (`src/mcp-engine.ts`)
|
||||
Clean interface for service integration:
|
||||
- Simple API for processing MCP requests
|
||||
- Health check capabilities
|
||||
- Graceful shutdown support
|
||||
- Ready for multi-tenant wrapper services
|
||||
|
||||
## Usage
|
||||
|
||||
### Standalone Mode
|
||||
```bash
|
||||
# Start the single-session HTTP server
|
||||
MCP_MODE=http npm start
|
||||
|
||||
# Or use the legacy stateless server
|
||||
npm run start:http:legacy
|
||||
```
|
||||
|
||||
### As a Library
|
||||
```typescript
|
||||
import { N8NMCPEngine } from 'n8n-mcp';
|
||||
|
||||
const engine = new N8NMCPEngine();
|
||||
|
||||
// In your Express app
|
||||
app.post('/api/mcp', authenticate, async (req, res) => {
|
||||
await engine.processRequest(req, res);
|
||||
});
|
||||
|
||||
// Health check
|
||||
app.get('/health', async (req, res) => {
|
||||
const health = await engine.healthCheck();
|
||||
res.json(health);
|
||||
});
|
||||
```
|
||||
|
||||
### Docker Deployment
|
||||
```yaml
|
||||
services:
|
||||
n8n-mcp:
|
||||
image: ghcr.io/czlonkowski/n8n-mcp:latest
|
||||
environment:
|
||||
- MCP_MODE=http
|
||||
- AUTH_TOKEN=${AUTH_TOKEN}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Manual Testing
|
||||
```bash
|
||||
# Run the test script
|
||||
npm run test:single-session
|
||||
```
|
||||
|
||||
### Unit Tests
|
||||
```bash
|
||||
# Run Jest tests
|
||||
npm test -- single-session.test.ts
|
||||
```
|
||||
|
||||
### Health Check
|
||||
```bash
|
||||
curl http://localhost:3000/health
|
||||
```
|
||||
|
||||
Response includes session information:
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"mode": "single-session",
|
||||
"version": "2.3.1",
|
||||
"sessionActive": true,
|
||||
"sessionAge": 45,
|
||||
"uptime": 120,
|
||||
"memory": {
|
||||
"used": 45,
|
||||
"total": 128,
|
||||
"unit": "MB"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
- `AUTH_TOKEN` - Required authentication token (min 32 chars recommended)
|
||||
- `MCP_MODE` - Set to "http" for HTTP mode
|
||||
- `PORT` - Server port (default: 3000)
|
||||
- `HOST` - Server host (default: 0.0.0.0)
|
||||
- `CORS_ORIGIN` - CORS allowed origin (default: *)
|
||||
|
||||
### Session Timeout
|
||||
The session automatically expires after 30 minutes of inactivity. This is configurable in the SingleSessionHTTPServer constructor.
|
||||
|
||||
## Migration from Stateless
|
||||
|
||||
The single-session implementation is backward compatible:
|
||||
1. Same API endpoints
|
||||
2. Same authentication mechanism
|
||||
3. Same request/response format
|
||||
4. Only internal architecture changed
|
||||
|
||||
To migrate:
|
||||
1. Update to latest version
|
||||
2. No configuration changes needed
|
||||
3. Monitor logs for any issues
|
||||
4. Session management is automatic
|
||||
|
||||
## Performance
|
||||
|
||||
The single-session architecture provides:
|
||||
- Lower memory usage (one session vs many)
|
||||
- Faster response times (no session creation overhead)
|
||||
- Automatic cleanup (session expiry)
|
||||
- No session accumulation issues
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Stream is not readable" error
|
||||
This error should no longer occur with the single-session implementation. If it does:
|
||||
1. Check console output isn't being written during requests
|
||||
2. Verify ConsoleManager is properly wrapping operations
|
||||
3. Check for third-party libraries writing to console
|
||||
|
||||
### Session expiry issues
|
||||
If sessions are expiring too quickly:
|
||||
1. Increase the timeout in SingleSessionHTTPServer
|
||||
2. Monitor session age in health endpoint
|
||||
3. Check for long gaps between requests
|
||||
|
||||
### Authentication failures
|
||||
1. Verify AUTH_TOKEN is set correctly
|
||||
2. Check authorization header format: `Bearer <token>`
|
||||
3. Monitor logs for auth failures
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Configurable session timeout** - Allow timeout configuration via environment variable
|
||||
2. **Session metrics** - Track session lifetime, request count, etc.
|
||||
3. **Graceful session migration** - Handle session updates without dropping requests
|
||||
4. **Multi-session support** - For future scaling needs (separate repository)
|
||||
Reference in New Issue
Block a user