- 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>
172 lines
4.6 KiB
Markdown
172 lines
4.6 KiB
Markdown
# 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) |