GC-301f · Module 1

GraphQL Integration

3 min read

GraphQL tools differ from REST tools in one critical way: the query is part of the tool logic, not the URL structure. Each tool encapsulates a specific GraphQL query or mutation with predefined selection sets. Do not expose a generic "run any GraphQL query" tool — Gemini will generate malformed queries, request fields that do not exist, and burn tokens on schema discovery. Hardcode the queries. Parameterize only the variables.

Schema introspection is a setup-time operation, not a runtime one. Before building GraphQL tools, run an introspection query against the API to understand available types, fields, and relationships. Use the schema to design tight selection sets that return only what Gemini needs. If a User type has 30 fields, your tool should select the 5 that matter: id, name, email, role, lastActive. Every extra field is wasted context.

Mutation safety requires guardrails. Read operations are safe to retry and cache. Mutations change state. Wrap destructive mutations — delete, archive, bulk update — with confirmation patterns. The tool returns a preview of what will change, and a second tool call confirms the action. For non-destructive mutations like creating a draft or adding a comment, execute immediately. The risk profile of the mutation determines the interaction pattern.

const ISSUE_QUERY = `
  query GetIssue($id: ID!) {
    issue(id: $id) {
      id
      title
      state
      assignee { login }
      labels(first: 5) { nodes { name } }
    }
  }
`;

async function getIssue(id: string) {
  const res = await fetch(process.env.GRAPHQL_ENDPOINT!, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${process.env.GH_TOKEN}`,
    },
    body: JSON.stringify({ query: ISSUE_QUERY, variables: { id } }),
  });

  const { data, errors } = await res.json();
  if (errors?.length) {
    return { error: errors.map((e: any) => e.message).join("; ") };
  }
  return data.issue;
}