run_graphql
Run complex read-only GraphQL queries for nested relations and custom filtering beyond simple record queries.
Instructions
Run an arbitrary read-only GraphQL query against the Gadget app. Use this for complex queries with nested relations or custom filtering that query_records can't express.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | GraphQL query string | |
| variables | No | GraphQL variables |
Implementation Reference
- src/tools.ts:430-441 (handler)Handler case within handleTool() for 'run_graphql'. Destructures query and variables, blocks mutations, and executes the query via the gql helper.
case "run_graphql": { const { query, variables } = args as { query: string; variables?: Record<string, unknown> }; const trimmed = query.trim().toLowerCase(); if (trimmed.startsWith("mutation")) { return { content: [{ type: "text", text: "Mutations are not allowed — this server is read-only." }], isError: true, }; } const data = await gql(query, variables); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] }; } - src/tools.ts:552-563 (schema)Tool definition with input schema for run_graphql. Declares required 'query' (string) and optional 'variables' (object) parameters.
name: "run_graphql", description: "Run an arbitrary read-only GraphQL query against the Gadget app. Use this for complex queries with nested relations or custom filtering that query_records can't express.", inputSchema: { type: "object", required: ["query"], properties: { query: { type: "string", description: "GraphQL query string" }, variables: { type: "object", description: "GraphQL variables" }, }, }, }, - src/index.ts:48-53 (registration)MCP server registration. ListTools exposes TOOL_DEFINITIONS (which includes run_graphql), and CallTool dispatches all tool calls to handleTool.
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOL_DEFINITIONS })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; return handleTool(name, (args ?? {}) as Record<string, any>); }); - src/tools.ts:12-38 (helper)The gql() helper function used by run_graphql (and other tools). Sends an authenticated POST request to the Gadget GraphQL endpoint and handles permission-denied errors.
export async function gql(query: string, variables?: Record<string, unknown>): Promise<any> { const res = await fetch(GRAPHQL_URL, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${GADGET_API_KEY}`, }, body: JSON.stringify({ query, variables }), }); if (!res.ok) { throw new Error(`GraphQL HTTP ${res.status}: ${await res.text()}`); } const json = await res.json() as any; if (json.errors?.length) { const permissionError = json.errors.find((e: any) => e.extensions?.code === "GGT_PERMISSION_DENIED"); if (permissionError) { throw new Error( `Permission denied (GGT_PERMISSION_DENIED): your API key has no role assigned, or the role lacks read access to this model.\n` + `Fix: go to ${GADGET_APP}.gadget.app/edit/${GADGET_ENVIRONMENT}/settings/api-keys and assign a role with read permissions to your key.` ); } throw new Error(json.errors.map((e: any) => e.message).join("; ")); } return json.data; }