Skip to main content
Glama

graphql

Execute GraphQL queries and mutations or introspect schemas with support for variables, custom headers, and request configuration.

Instructions

Execute GraphQL queries and mutations with support for variables and custom headers

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesThe action to perform with GraphQL

Implementation Reference

  • Main GraphQL tool handler function that switches between 'execute' and 'introspect' actions, delegating to respective helper functions with comprehensive error handling.
    export default async function graphql({ action }: InferSchema<typeof schema>) { try { switch (action.type) { case "execute": return await executeGraphQL( action.endpoint, action.query, action.variables, action.headers, action.operationName, action.timeout ) case "introspect": return await introspectGraphQL( action.endpoint, action.headers || {}, action.action, action.typeName, action.useCache, action.cacheTTL ) default: return JSON.stringify({ success: false, error: "Invalid action type", }, null, 2) } } catch (error) { return JSON.stringify({ success: false, error: error instanceof Error ? error.message : "Unknown error occurred", }, null, 2) } }
  • Zod schema defining discriminated union for 'execute' (query/mutation with vars, headers) and 'introspect' (schema actions with cache) parameters.
    export const schema = { action: z.discriminatedUnion("type", [ // GraphQL execution action z.object({ type: z.literal("execute"), endpoint: z.string().describe("The GraphQL endpoint URL"), query: z.string().describe("The GraphQL query or mutation string"), variables: z.record(z.any()) .optional() .describe("Variables to pass to the GraphQL query/mutation"), headers: z.record(z.string()) .optional() .describe("HTTP headers to include in the request (e.g., authorization tokens)"), operationName: z.string() .optional() .describe("Name of the operation to execute (useful when query contains multiple operations)"), timeout: z.number() .optional() .default(30000) .describe("Request timeout in milliseconds. Defaults to 30 seconds"), }), // GraphQL introspection action z.object({ type: z.literal("introspect"), endpoint: z.string().describe("The GraphQL endpoint URL to introspect"), headers: z.record(z.string()) .optional() .describe("HTTP headers to include in the request (e.g., authorization tokens)"), action: z.enum(["full-schema", "list-operations", "get-type"]) .describe("What to fetch: full-schema gets the complete schema, list-operations lists available queries/mutations, get-type gets a specific type definition"), typeName: z.string() .optional() .describe("The name of the type to fetch (required when action is 'get-type')"), useCache: z.boolean() .optional() .default(true) .describe("Whether to use cached schema if available"), cacheTTL: z.number() .optional() .default(300000) .describe("Cache time-to-live in milliseconds. Defaults to 5 minutes"), }), ]).describe("The action to perform with GraphQL"), }
  • Tool metadata registration exporting name 'graphql', description, and annotations.
    export const metadata: ToolMetadata = { name: "graphql", description: "Execute GraphQL queries and mutations with support for variables and custom headers", annotations: { title: "GraphQL Client", readOnlyHint: false, destructiveHint: false, idempotentHint: false, }, }
  • Core helper for executing GraphQL queries/mutations using graphql-request, with timeout, detailed errors, operation type detection, and sensitive header masking.
    export async function executeGraphQL( endpoint: string, query: string, variables?: Record<string, any>, headers?: Record<string, string>, operationName?: string, timeout: number = 30000 ): Promise<string> { try { // Validate query syntax const document = gql`${query}` // Create GraphQL client with configuration const client = new GraphQLClient(endpoint, { headers: headers || {}, }) // Execute the GraphQL request const startTime = Date.now() // Set up timeout if specified let timeoutId: NodeJS.Timeout | undefined const timeoutPromise = timeout ? new Promise((_, reject) => { timeoutId = setTimeout(() => reject(new Error(`Request timed out after ${timeout}ms`)), timeout) }) : null // Race between request and timeout const data = await (timeoutPromise ? Promise.race([ client.request(document, variables || {}), timeoutPromise ]) : client.request(document, variables || {})) const responseTime = Date.now() - startTime // Clear timeout if set if (timeoutId) clearTimeout(timeoutId) // Parse operation type from query const operationType = detectOperationType(query) return JSON.stringify({ success: true, data, operationType, responseTime: `${responseTime}ms`, request: { endpoint, operationName, variables: variables || {}, headers: maskSensitiveHeaders(headers) } }, null, 2) } catch (error) { // Handle different error types let errorDetails: any = { success: false, error: "Unknown error occurred", errorType: "UnknownError", } if (error instanceof Error) { // GraphQL errors from graphql-request if ('response' in error && error.response) { const graphqlError = error as any errorDetails = { success: false, errorType: "GraphQLError", errors: graphqlError.response.errors || [], data: graphqlError.response.data || null, status: graphqlError.response.status, headers: graphqlError.response.headers, } } // Network or other errors else { errorDetails.error = error.message if (error.message.includes('timeout')) { errorDetails.errorType = "TimeoutError" errorDetails.error = `Request timed out after ${timeout}ms` } else if (error.message.includes('Network') || error.message.includes('fetch')) { errorDetails.errorType = "NetworkError" } else if (error.message.includes('Syntax Error')) { errorDetails.errorType = "SyntaxError" errorDetails.error = "Invalid GraphQL query syntax" } } } // Add request details to error response errorDetails.request = { endpoint, operationName, variables: variables || {}, headers: maskSensitiveHeaders(headers) } return JSON.stringify(errorDetails, null, 2) } }
  • Core helper for GraphQL introspection supporting full schema, operation lists, type details with schema caching.
    export async function introspectGraphQL( endpoint: string, headers: Record<string, string> = {}, action: string, typeName?: string, useCache: boolean = true, cacheTTL: number = 300000 ): Promise<string> { try { // Get schema (from cache or fetch) const introspectionData = await getSchema(endpoint, headers, useCache, cacheTTL) // Build schema from introspection result const schema = buildClientSchema(introspectionData) switch (action) { case "full-schema": return handleFullSchema(schema) case "list-operations": return handleListOperations(schema) case "get-type": if (!typeName) { return JSON.stringify({ success: false, error: "typeName is required when action is 'get-type'", }, null, 2) } return handleGetType(schema, typeName) default: return JSON.stringify({ success: false, error: `Unknown action: ${action}`, }, null, 2) } } catch (error) { return JSON.stringify({ success: false, error: error instanceof Error ? error.message : "Unknown error occurred", errorType: error instanceof Error && error.message.includes("Network") ? "NetworkError" : "IntrospectionError", endpoint, }, null, 2) } }

Other Tools

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