server.ts•5.01 kB
import { EventEmitter } from 'events';
import { Server } from 'net';
import { Logger } from './logger';
import { ConfigManager } from './config';
import { MetricsCollector } from './metrics';
import { SessionManager } from './session-manager';
/**
* MCP Server
*
* Implements the Model Context Protocol server and manages MCP client connections
*/
export class MCPServer extends EventEmitter {
private logger: Logger;
private config: ConfigManager;
private metrics: MetricsCollector;
private server: Server | null = null;
private sessionManager: SessionManager;
private isRunning = false;
private port: number;
private host: string;
constructor() {
super();
this.logger = new Logger('MCPServer');
this.config = ConfigManager.getInstance();
this.metrics = MetricsCollector.getInstance();
this.sessionManager = new SessionManager();
this.port = this.config.get('server.port', 0);
this.host = this.config.get('server.host', '127.0.0.1');
}
/**
* Start the MCP server
*/
async start(): Promise<void> {
if (this.isRunning) {
this.logger.warn('Server is already running');
return;
}
this.logger.info('Starting MCP server...');
this.metrics.startTimer('server.start');
try {
this.server = this.createServer();
this.setupServerHandlers();
// Start listening
await new Promise<void>((resolve, reject) => {
this.server!.listen(this.port, this.host, () => {
this.port = (this.server!.address() as any).port;
this.logger.info(`MCP server listening on ${this.host}:${this.port}`);
resolve();
});
this.server!.on('error', error => {
this.logger.error('Server error:', error);
reject(error);
});
});
this.isRunning = true;
this.metrics.increment('server.start.count');
this.metrics.stopTimer('server.start');
this.emit('started');
} catch (error) {
this.logger.error('Failed to start server:', error);
throw error;
}
}
/**
* Stop the MCP server
*/
async stop(): Promise<void> {
if (!this.isRunning || !this.server) {
this.logger.warn('Server is not running');
return;
}
this.logger.info('Stopping MCP server...');
this.metrics.startTimer('server.stop');
try {
// Stop accepting new connections
await new Promise<void>((resolve, reject) => {
this.server!.close(error => {
if (error) {
this.logger.error('Error closing server:', error);
reject(error);
} else {
this.logger.info('Server stopped');
resolve();
}
});
});
// Close all active sessions
await this.sessionManager.shutdown();
this.server = null;
this.isRunning = false;
this.metrics.increment('server.stop.count');
this.metrics.stopTimer('server.stop');
this.emit('stopped');
} catch (error) {
this.logger.error('Error stopping server:', error);
throw error;
}
}
/**
* Get server status
*/
getStatus(): {
isRunning: boolean;
port: number;
host: string;
sessionsCount: number;
uptime: number;
} {
return {
isRunning: this.isRunning,
port: this.port,
host: this.host,
sessionsCount: this.sessionManager.getSessionCount(),
uptime: process.uptime() * 1000,
};
}
/**
* Create TCP server
*/
private createServer(): Server {
const server = new Server();
// Handle connections
server.on('connection', socket => {
this.logger.info(`New connection from ${socket.remoteAddress}:${socket.remotePort}`);
this.metrics.increment('server.connections.count');
// Set timeout for inactive connections
socket.setTimeout(this.config.get('server.idleTimeout', 300000));
socket.on('timeout', () => {
this.logger.warn(`Connection ${socket.remoteAddress}:${socket.remotePort} timed out`);
socket.destroy();
});
socket.on('error', error => {
this.logger.error(`Connection error:`, error);
});
socket.on('close', () => {
this.logger.info(`Connection ${socket.remoteAddress}:${socket.remotePort} closed`);
});
});
return server;
}
/**
* Setup server event handlers
*/
private setupServerHandlers(): void {
if (!this.server) return;
this.server.on('error', error => {
this.logger.error('Server error:', error);
this.emit('error', error);
});
this.server.on('close', () => {
this.logger.info('Server closed');
this.emit('closed');
});
}
/**
* Get session manager
*/
getSessionManager(): SessionManager {
return this.sessionManager;
}
}
/**
* Create MCP server instance
*/
export async function createServer(_config: ConfigManager): Promise<MCPServer> {
const server = new MCPServer();
await server.start();
return server;
}