executeGraphQLOperation
Execute GraphQL queries and mutations against target APIs. Use this tool to send operation requests after schema introspection.
Instructions
Executes an arbitrary GraphQL query or mutation against the target API. Use introspectGraphQLSchema first to understand the available operations.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The GraphQL query string to execute. | |
| variables | No | An optional object containing variables for the query. | |
| operationName | No | An optional name for the operation, if the query contains multiple operations. |
Implementation Reference
- src/server.ts:52-57 (registration)Registration of the 'executeGraphQLOperation' tool in the ListTools response, including name, description, and input schema reference.{ name: "executeGraphQLOperation", description: "Executes an arbitrary GraphQL query or mutation against the target API. Use introspectGraphQLSchema first to understand the available operations.", inputSchema: executeInputSchema, },
- src/server.ts:87-92 (registration)Dispatch logic in CallTool handler that routes calls to 'executeGraphQLOperation' to the handleExecution function after validation.case "executeGraphQLOperation": // Validate arguments using the Zod schema const validatedArgs = ExecutorSchemaInput.parse(args); console.error(`Calling handler for ${name}`); result = await handleExecution(validatedArgs); break;
- src/tools/executor.ts:6-18 (schema)Zod schema definition for input validation of the 'executeGraphQLOperation' tool.export const ExecutorSchemaInput = z.object({ query: z.string().describe("The GraphQL query string to execute."), variables: z .record(z.unknown()) .optional() .describe("An optional object containing variables for the query."), operationName: z .string() .optional() .describe( "An optional name for the operation, if the query contains multiple operations." ), });
- src/tools/executor.ts:42-92 (handler)Main handler function for 'executeGraphQLOperation' tool that orchestrates input destructuring, GraphQL execution, error handling, and response formatting.export async function handleExecution( input: z.infer<typeof ExecutorSchemaInput> ): Promise<z.infer<typeof ExecutorSchemaOutput>> { const { query, variables, operationName } = input; try { console.error(`Executing GraphQL query: ${operationName || "unnamed"}...`); const response = await executeGraphQL<z.infer<typeof ExecutorSchemaOutput>>( query, variables, operationName ); // GraphQL endpoints often return 200 OK even if there are query errors. // These are included in the 'errors' array in the response body. if (response.errors && response.errors.length > 0) { const errorMessages = response.errors.map((e) => e.message).join("; "); console.error( `GraphQL query ${ operationName || "unnamed" } returned errors: ${errorMessages}`, response.errors ); // We return the full response including data and errors as per the MCP flow // The client consuming the MCP tool will decide how to handle the errors field. // No McpError is thrown here unless the request itself failed (handled in executeGraphQL) } console.error(`GraphQL query ${operationName || "unnamed"} executed.`); return response; // Return the full response { data?: ..., errors?: ... } } catch (error) { // This catches errors thrown by executeGraphQL (network, HTTP errors, etc.) console.error( `Error executing GraphQL query ${operationName || "unnamed"}:`, error ); if (error instanceof McpError) { // Re-throw McpErrors directly throw error; } // Wrap unexpected errors throw new McpError( ErrorCode.InternalError, `An unexpected error occurred while executing the GraphQL query '${ operationName || "unnamed" }'.`, { cause: error as Error } ); } }
- src/graphqlClient.ts:28-129 (helper)Core helper function 'executeGraphQL' that performs the HTTP POST request to the GraphQL endpoint using axios, handles authentication, and manages various error conditions.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)) } ); } } }