Skip to main content
Glama
transports.ts3.15 kB
import type { Transport, CallToolRequest, CallToolResult } from './types.js'; import WebSocket from 'ws'; import * as readline from 'readline'; import { z } from 'zod'; import { StructuredLogger } from './logging.js'; // Define request schema here since it's transport-specific const CallToolRequestSchema = z.object({ name: z.string(), parameters: z.record(z.any()) }); export class WebSocketTransport implements Transport { private ws: WebSocket; private requestHandler?: (request: CallToolRequest) => Promise<CallToolResult>; private logger = StructuredLogger.getInstance(); constructor(url: string) { this.ws = new WebSocket(url); } public async connect(): Promise<void> { return new Promise((resolve, reject) => { this.ws.onopen = () => resolve(); this.ws.onerror = (error) => reject(error); this.ws.onmessage = async (event) => { if (!this.requestHandler) { return; } try { const rawRequest = JSON.parse(event.data.toString()); const request = CallToolRequestSchema.parse(rawRequest); // Validate const response = await this.requestHandler(request); this.ws.send(JSON.stringify(response)); } catch (error) { // Send validation errors this.ws.send(JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Invalid request' })); } }; }); } public async disconnect(): Promise<void> { return new Promise<void>((resolve) => { this.ws.close(); resolve(); }); } public onRequest(handler: (request: CallToolRequest) => Promise<CallToolResult>): void { this.requestHandler = handler; } } export class StdioTransport implements Transport { private requestHandler?: (request: CallToolRequest) => Promise<CallToolResult>; private readline: readline.Interface; private logger = StructuredLogger.getInstance(); constructor() { this.readline = readline.createInterface({ input: process.stdin, output: process.stdout }); } async connect(): Promise<void> { this.readline.on('line', async (line: string) => { if (!this.requestHandler) { this.logger.error('transport', 'No request handler registered'); return; } try { const request = JSON.parse(line) as CallToolRequest; const response = await this.requestHandler(request); this.logger.info('transport', 'Response', { response }); process.stdout.write(`${JSON.stringify(response)}\n`); } catch (error) { this.logger.error('transport', 'Error handling input', error as Error); process.stdout.write(`${JSON.stringify({ id: null, error: { message: error instanceof Error ? error.message : String(error) } })}\n`); } }); return Promise.resolve(); } async disconnect(): Promise<void> { this.readline.close(); return Promise.resolve(); } onRequest(handler: (request: CallToolRequest) => Promise<CallToolResult>): void { this.requestHandler = handler; } }

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/henryhawke/mcp-titan'

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