Skip to main content
Glama
graphqlClient.ts4.12 kB
// Initial empty file for the GraphQL client helper import axios from "axios"; import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js"; import config from "./config"; // Import the loaded configuration interface GraphQLErrorResponse { message: string; locations?: { line: number; column: number }[]; path?: string[]; extensions?: Record<string, any>; } interface GraphQLResponse<T = any> { data: T | null; errors?: GraphQLErrorResponse[]; } /** * Executes a GraphQL query or mutation against the configured endpoint. * * @param query The GraphQL query or mutation string. * @param variables Optional variables object for the operation. * @param operationName Optional operation name for the operation. * @returns A promise resolving to the GraphQL response data. * @throws {McpError} If the request fails due to network issues, HTTP errors, or GraphQL errors. */ export async function executeGraphQL<T = any>( query: string, variables?: Record<string, any>, operationName?: string ): Promise<GraphQLResponse<T>> { const { graphqlEndpoint, authToken } = config; if (!graphqlEndpoint) { // Use PascalCase for ErrorCode members throw new McpError( ErrorCode.InternalError, "GraphQL endpoint URL is not configured." ); } // We check authToken existence in config.ts, assume it's present if needed or proceed if not. const headers: Record<string, string> = { "Content-Type": "application/json", Accept: "application/json", }; if (authToken) { headers["Authorization"] = `Bearer ${authToken}`; } try { const response = await axios.post<GraphQLResponse<T>>( graphqlEndpoint, { query, variables, ...(operationName && { operationName }), }, { headers, timeout: 30000, // 30 second timeout } ); // Axios considers 2xx successful, return the body directly // The caller should check for response.data.errors return response.data; } catch (error: any) { // Use the imported isAxiosError type guard if (error.response) { // Now variable 'error' is narrowed to AxiosError type const statusCode = error.response?.status; const responseData = error.response?.data as any; const errorMessageBase = `GraphQL request failed: ${error.message}`; let detailedMessage = errorMessageBase; if (responseData?.errors?.[0]?.message) { detailedMessage = `${errorMessageBase} - ${responseData.errors[0].message}`; } if (statusCode === 401) { // Use PascalCase for ErrorCode members throw new McpError( ErrorCode.InvalidRequest, "Authentication failed. Check your AUTH_TOKEN.", { cause: error } ); } if (statusCode === 403) { // Use PascalCase for ErrorCode members throw new McpError( ErrorCode.InvalidRequest, "Permission denied for GraphQL operation.", { cause: error } ); } if (statusCode && statusCode >= 400 && statusCode < 500) { // Use PascalCase for ErrorCode members throw new McpError(ErrorCode.InvalidRequest, detailedMessage, { cause: error, }); } // Includes 5xx errors and network errors (statusCode is undefined) // Use PascalCase for ErrorCode members throw new McpError(ErrorCode.InternalError, detailedMessage, { cause: error, }); } else if (error instanceof Error) { console.error("Unexpected error during GraphQL request:", error); // Use PascalCase for ErrorCode members throw new McpError( ErrorCode.InternalError, `An unexpected error occurred: ${error.message}`, { cause: error } ); } else { console.error( "Unexpected non-error thrown during GraphQL request:", error ); throw new McpError( ErrorCode.InternalError, "An unexpected non-error value was thrown during the GraphQL request.", { cause: new Error(String(error)) } ); } } }

Implementation Reference

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/jorgeraad/mcp4gql'

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