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)
      }
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate readOnlyHint=false, idempotentHint=false, and destructiveHint=false, covering basic safety. The description adds that it handles 'queries and mutations' and supports variables/headers, which clarifies it's a general GraphQL client. However, it lacks details on error handling, rate limits, or authentication requirements beyond headers, missing deeper behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that front-loads the core functionality ('Execute GraphQL queries and mutations') and includes key features. There is no wasted verbiage, making it highly concise and well-structured for quick comprehension.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (handling GraphQL queries/mutations and introspection) and lack of output schema, the description is somewhat incomplete. It doesn't explain return values, error formats, or the introspection capability implied by the schema. However, annotations provide basic hints, and the schema covers inputs thoroughly, making it minimally adequate but with gaps for a multi-action tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so parameters are well-documented in the schema. The description mentions 'variables and custom headers,' aligning with schema properties but adding no extra semantic meaning. With high schema coverage, the baseline score of 3 is appropriate as the description doesn't significantly enhance parameter understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Execute GraphQL queries and mutations with support for variables and custom headers.' It specifies the verb ('execute'), resource ('GraphQL queries and mutations'), and key features. However, it doesn't distinguish this from sibling tools like 'fetch' which might also make HTTP requests, leaving room for improvement.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'fetch' for general HTTP requests or other siblings. It mentions support for variables and headers but doesn't clarify specific use cases, prerequisites, or exclusions for GraphQL versus REST APIs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

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