Skip to main content
Glama
index.ts5.52 kB
import { io, Socket } from 'socket.io-client'; import axios, { AxiosInstance } from 'axios'; import { EventEmitter } from 'eventemitter3'; export interface MCPClientConfig { serverUrl: string; apiKey?: string; jwt?: string; timeout?: number; reconnectionAttempts?: number; debug?: boolean; } export interface MCPMessage { id: string; method: string; params?: any; result?: any; error?: any; } export class SecureMCPClient extends EventEmitter { private socket: Socket | null = null; private http: AxiosInstance; private config: MCPClientConfig; private messageQueue: Map<string, (response: any) => void> = new Map(); private connected: boolean = false; constructor(config: MCPClientConfig) { super(); this.config = { timeout: 30000, reconnectionAttempts: 5, debug: false, ...config, }; // Initialize HTTP client this.http = axios.create({ baseURL: this.config.serverUrl, timeout: this.config.timeout, headers: this.getAuthHeaders(), }); } /** * Connect to the MCP server via WebSocket */ async connect(): Promise<void> { return new Promise((resolve, reject) => { this.socket = io(this.config.serverUrl, { transports: ['websocket'], auth: this.getAuthHeaders(), reconnectionAttempts: this.config.reconnectionAttempts, }); this.socket.on('connect', () => { this.connected = true; this.emit('connected'); if (this.config.debug) console.log('Connected to MCP server'); resolve(); }); this.socket.on('disconnect', (reason) => { this.connected = false; this.emit('disconnected', reason); if (this.config.debug) console.log('Disconnected:', reason); }); this.socket.on('error', (error) => { this.emit('error', error); if (this.config.debug) console.error('Socket error:', error); reject(error); }); this.socket.on('message', (message: MCPMessage) => { this.handleMessage(message); }); // Set connection timeout setTimeout(() => { if (!this.connected) { reject(new Error('Connection timeout')); } }, this.config.timeout); }); } /** * Disconnect from the MCP server */ disconnect(): void { if (this.socket) { this.socket.disconnect(); this.socket = null; this.connected = false; } } /** * Send a request to the MCP server */ async request(method: string, params?: any): Promise<any> { const id = this.generateId(); const message: MCPMessage = { id, method, params }; if (this.socket && this.connected) { return this.sendViaWebSocket(message); } else { return this.sendViaHTTP(message); } } /** * List available tools */ async listTools(): Promise<any> { return this.request('tools/list'); } /** * Execute a tool */ async executeTool(name: string, params: any): Promise<any> { return this.request('tools/execute', { name, params }); } /** * List available resources */ async listResources(): Promise<any> { return this.request('resources/list'); } /** * Read a resource */ async readResource(uri: string): Promise<any> { return this.request('resources/read', { uri }); } /** * Send a completion request */ async complete(prompt: string, options?: any): Promise<any> { return this.request('completion', { prompt, ...options }); } /** * Subscribe to server events */ subscribe(event: string, handler: (data: any) => void): void { if (this.socket) { this.socket.on(event, handler); } this.on(event, handler); } /** * Unsubscribe from server events */ unsubscribe(event: string, handler?: (data: any) => void): void { if (this.socket) { this.socket.off(event, handler); } this.off(event, handler); } private async sendViaWebSocket(message: MCPMessage): Promise<any> { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { this.messageQueue.delete(message.id); reject(new Error('Request timeout')); }, this.config.timeout); this.messageQueue.set(message.id, (response) => { clearTimeout(timeout); if (response.error) { reject(response.error); } else { resolve(response.result); } }); this.socket!.emit('message', message); }); } private async sendViaHTTP(message: MCPMessage): Promise<any> { const response = await this.http.post('/api/mcp', message); if (response.data.error) { throw response.data.error; } return response.data.result; } private handleMessage(message: MCPMessage): void { const handler = this.messageQueue.get(message.id); if (handler) { handler(message); this.messageQueue.delete(message.id); } this.emit('message', message); } private getAuthHeaders(): Record<string, string> { const headers: Record<string, string> = {}; if (this.config.apiKey) { headers['X-API-Key'] = this.config.apiKey; } if (this.config.jwt) { headers['Authorization'] = `Bearer ${this.config.jwt}`; } return headers; } private generateId(): string { return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } } // Export types export * from './types'; // Default export export default SecureMCPClient;

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/perfecxion-ai/secure-mcp'

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