Skip to main content
Glama
2389-research

MCP Agent Social Media Server

http-server.ts7.25 kB
// ABOUTME: HTTP server implementation for MCP social media server // ABOUTME: Provides HTTP/SSE transport as an alternative to stdio import { randomUUID } from 'node:crypto'; import { type IncomingMessage, type ServerResponse, createServer } from 'node:http'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import type { ApiClient } from './api-client.js'; import { config } from './config.js'; import { logger } from './logger.js'; import type { SessionManager } from './session-manager.js'; export interface HttpServerOptions { port?: number; host?: string; enableJsonResponse?: boolean; corsOrigin?: string; } export class HttpMcpServer { private httpServer: ReturnType<typeof createServer> | null = null; private mcpServer: McpServer | null = null; private transport: StreamableHTTPServerTransport | null = null; private readonly options: Required<HttpServerOptions>; constructor( private readonly sessionManager: SessionManager, private readonly apiClient: ApiClient, options: HttpServerOptions = {}, ) { this.options = { port: options.port ?? 3000, host: options.host ?? 'localhost', enableJsonResponse: options.enableJsonResponse ?? false, corsOrigin: options.corsOrigin ?? '*', }; } /** * Start the HTTP server */ async start(): Promise<void> { if (this.httpServer) { throw new Error('HTTP server already started'); } // Create single MCP server instance await this.createMcpServer(); this.httpServer = createServer(async (req, res) => { // Add CORS headers res.setHeader('Access-Control-Allow-Origin', this.options.corsOrigin); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Mcp-Session-Id'); res.setHeader('Access-Control-Max-Age', '86400'); // Handle preflight requests if (req.method === 'OPTIONS') { res.writeHead(204); res.end(); return; } // Log request logger.debug('HTTP request received', { method: req.method, url: req.url, headers: req.headers, }); try { await this.handleRequest(req, res); } catch (error) { logger.error('Error handling HTTP request', { error }); if (!res.headersSent) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Internal server error' })); } } }); return new Promise((resolve, reject) => { this.httpServer?.listen(this.options.port, this.options.host, () => { logger.info('HTTP MCP server started', { host: this.options.host, port: this.options.port, enableJsonResponse: this.options.enableJsonResponse, }); resolve(); }); this.httpServer?.on('error', (error) => { logger.error('HTTP server error', { error }); reject(error); }); }); } /** * Stop the HTTP server */ async stop(): Promise<void> { if (!this.httpServer) { return; } // Close MCP server connection if (this.mcpServer) { try { await this.mcpServer.close(); logger.debug('Closed MCP server'); } catch (error) { logger.error('Error closing MCP server', { error }); } this.mcpServer = null; this.transport = null; } // Close HTTP server return new Promise((resolve, reject) => { this.httpServer?.close((error) => { if (error) { logger.error('Error closing HTTP server', { error }); reject(error); } else { logger.info('HTTP MCP server stopped'); this.httpServer = null; resolve(); } }); }); } /** * Handle incoming HTTP requests */ private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> { const url = new URL(req.url || '/', `http://${req.headers.host}`); // Only handle requests to /mcp endpoint if (url.pathname !== '/mcp') { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not found' })); return; } // Get or create session ID const sessionId = (req.headers['mcp-session-id'] as string) || randomUUID(); // Set session ID in response header for client tracking res.setHeader('Mcp-Session-Id', sessionId); if (!this.transport) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Transport not found' })); return; } // Parse body if POST let body: unknown; if (req.method === 'POST') { body = await this.parseRequestBody(req); } // Let transport handle the request await this.transport.handleRequest(req, res, body); } /** * Create the MCP server instance with HTTP transport */ private async createMcpServer(): Promise<void> { // Import the registration functions dynamically to avoid circular dependencies const { hooksManager } = await import('./hooks/index.js'); const { registerPrompts } = await import('./prompts/index.js'); const { registerResources } = await import('./resources/index.js'); const { registerRoots } = await import('./roots/index.js'); const { registerTools } = await import('./tools/index.js'); // Import version from config const { version } = await import('./config.js'); // Create MCP server this.mcpServer = new McpServer({ name: 'mcp-agent-social', version, }); // Create HTTP transport this.transport = new StreamableHTTPServerTransport({ sessionIdGenerator: randomUUID, enableJsonResponse: this.options.enableJsonResponse, onsessioninitialized: (id) => { logger.debug('Session initialized', { sessionId: id }); }, }); // Register all capabilities registerTools(this.mcpServer, { sessionManager: this.sessionManager, apiClient: this.apiClient, hooksManager, }); registerResources(this.mcpServer, { apiClient: this.apiClient, sessionManager: this.sessionManager, hooksManager, }); registerPrompts(this.mcpServer, { apiClient: this.apiClient, sessionManager: this.sessionManager, hooksManager, }); registerRoots(this.mcpServer, { apiClient: this.apiClient, sessionManager: this.sessionManager, hooksManager, }); // Connect transport await this.mcpServer.connect(this.transport); } /** * Parse request body as JSON */ private async parseRequestBody(req: IncomingMessage): Promise<unknown> { return new Promise((resolve, reject) => { let body = ''; req.on('data', (chunk) => { body += chunk.toString(); }); req.on('end', () => { try { resolve(body ? JSON.parse(body) : undefined); } catch (_error) { reject(new Error('Invalid JSON body')); } }); req.on('error', reject); }); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/2389-research/mcp-socialmedia'

If you have feedback or need assistance with the MCP directory API, please join our Discord server