Skip to main content
Glama
mcp-client.ts5.71 kB
import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js"; export interface MCPClientConfig { command: string; args: string[]; env?: Record<string, string>; cwd?: string; } export class MCPTestClient { private client: Client; private transport: StdioClientTransport | null = null; private connected = false; constructor(private config: MCPClientConfig) { this.client = new Client( { name: "mcp-fetch-test-client", version: "1.0.0" }, { capabilities: {} } ); } async connect(): Promise<void> { if (this.connected) { throw new Error("Client is already connected"); } // Filter out undefined values from process.env const processEnv = Object.entries(process.env).reduce((acc, [key, value]) => { if (value !== undefined) { acc[key] = value; } return acc; }, {} as Record<string, string>); this.transport = new StdioClientTransport({ command: this.config.command, args: this.config.args, env: { ...processEnv, ...this.config.env } }); try { await this.client.connect(this.transport); this.connected = true; } catch (error) { throw error; } } async disconnect(): Promise<void> { if (!this.connected) { return; } await this.client.close(); this.transport = null; this.connected = false; } async connectWithRetry(maxRetries = 3): Promise<void> { for (let i = 0; i < maxRetries; i++) { try { await this.connect(); return; } catch (error) { if (i === maxRetries - 1) throw error; await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } } } async discoverCapabilities(): Promise<{ tools: any[]; resources: any[]; prompts: any[]; }> { if (!this.connected) { throw new Error("Client is not connected"); } const [tools, resources, prompts] = await Promise.all([ this.listTools(), this.listResources(), this.listPrompts() ]); return { tools, resources, prompts }; } async listTools(): Promise<any[]> { try { const result = await this.client.listTools(); return result.tools; } catch (error) { throw error; } } async listResources(): Promise<any[]> { const result = await this.client.listResources(); return result.resources; } async listPrompts(): Promise<any[]> { const result = await this.client.listPrompts(); return result.prompts; } // Generic tool call with error handling async callTool(name: string, args: any): Promise<any> { if (!this.connected) { throw new Error("Client is not connected"); } try { const result = await this.client.callTool({ name, arguments: args }); // Parse the result based on the CallToolResultSchema const validatedResult = CallToolResultSchema.parse(result); // Extract the actual content from the result if (validatedResult.content && validatedResult.content.length > 0) { const firstContent = validatedResult.content[0]; if (firstContent.type === 'text') { const text = firstContent.text; // Special handling for get-rules which returns a JSON string if (name === 'get-rules') { try { const parsed = JSON.parse(text); return parsed; } catch { return text; } } // For other tools, try to parse as JSON if it looks like JSON try { const parsed = JSON.parse(text); return parsed; } catch { // If not JSON, return as text return text; } } return firstContent; } return validatedResult; } catch (error: any) { if (error.code === -32601) { throw new Error(`Tool '${name}' not found`); } if (error.code === -32602) { throw new Error(`Invalid parameters for tool '${name}': ${error.message}`); } throw error; } } // HTTP/Fetch tool async callFetchTool(params: any): Promise<any> { return await this.callTool("fetch", params); } // WebSocket tools async callSocketTool(action: any): Promise<any> { return await this.callTool("socket", action); } // Puppeteer consolidated tool async callPuppeteerTool(action: any): Promise<any> { return await this.callTool("puppeteer", action); } // Puppeteer browser tools async callBrowserTool(action: any): Promise<any> { return await this.callTool("puppeteer", action); } async callPageTool(action: any): Promise<any> { return await this.callTool("puppeteer", action); } async callExecPageTool(pageId: string, source: string): Promise<any> { return await this.callTool("puppeteer", { pageId, source }); } // GraphQL tools async callGraphQLTool(action: any): Promise<any> { return await this.callTool("graphql", action); } async callGraphQLIntrospectTool(params: any): Promise<any> { // Convert old introspect params to new merged tool format const mergedParams = { action: { type: "introspect", ...params } }; return await this.callTool("graphql", mergedParams); } // Documentation tool async callGetRulesTool(rules?: string[]): Promise<any> { return await this.callTool("get-rules", { rules: rules || ["quickStart"] }); } }

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/matiasngf/mcp-fetch'

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