# MCP Server GraphQL Endpoints

The MCP Server Handler supports GraphQL endpoints through the `x-zuplo-route`
OpenAPI extension. This allows you to expose GraphQL APIs as MCP tools with
automatic schema introspection and query execution capabilities.

When you configure a route with the GraphQL extension, the MCP server
automatically generates two tools:

1. **Introspection tool** - Fetches the GraphQL schema so AI systems can
   understand available queries, mutations, and types
2. **Execute tool** - Executes GraphQL queries against the endpoint

This enables AI systems to dynamically discover and interact with GraphQL APIs
without requiring manual tool definitions for each query.

:::caution

GraphQL endpoint support for MCP Server is currently in beta. The API may change
in future releases.

:::

## Quick Start

### 1. Configure a GraphQL Endpoint

Add a route that forwards to your GraphQL endpoint and include the
`x-zuplo-route.mcp` configuration:

```json
{
  "openapi": "3.1.0",
  "info": {
    "version": "1.0.0"
  },
  "paths": {
    "/graphql": {
      "post": {
        "operationId": "graphql",
        "summary": "GraphQL API endpoint",
        "x-zuplo-route": {
          "handler": {
            "export": "urlForwardHandler",
            "module": "$import(@zuplo/runtime)",
            "options": {
              "baseUrl": "https://api.example.com",
              "followRedirects": true
            }
          },
          "mcp": {
            "type": "graphql"
          }
        }
      }
    }
  }
}
```

### 2. Add to Your MCP Server

Include the GraphQL route in your MCP Server configuration using the
`operations` array:

```json
{
  "paths": {
    "/mcp": {
      "post": {
        "summary": "MCP server",
        "operationId": "mcp-server",
        "x-zuplo-route": {
          "corsPolicy": "none",
          "handler": {
            "export": "mcpServerHandler",
            "module": "$import(@zuplo/runtime)",
            "options": {
              "name": "My MCP Server",
              "version": "1.0.0",
              "operations": [
                {
                  "file": "./config/routes.oas.json",
                  "id": "graphql"
                }
              ]
            }
          }
        }
      }
    }
  }
}
```

This configuration automatically creates:

- `graphql_introspect` - Tool to fetch the GraphQL schema
- `graphql_execute` - Tool to execute GraphQL queries

## Configuration Options

The `x-zuplo-route.mcp` configuration for GraphQL supports the following
options:

- `type`: Must be set to `"graphql"`
- `enabled`: Whether the GraphQL MCP capabilities are enabled (default: `true`).
- `introspectionTool`: Configuration for the introspection tool.
  - `name`: Custom name for the introspection tool.
  - `description`: Custom description for the introspection tool.
- `executeTool`: Configuration for the execute tool.
  - `name`: Custom name for the execute tool.
  - `description`: Custom description for the execute tool.

For example:

```json
{
  "paths": {
    "/graphql": {
      "post": {
        "operationId": "github_graphql",
        "x-zuplo-route": {
          "handler": {
            "export": "urlForwardHandler",
            "module": "$import(@zuplo/runtime)",
            "options": {
              "baseUrl": "https://api.github.com"
            }
          },
          "mcp": {
            "type": "graphql",
            "introspectionTool": {
              "name": "github_schema",
              "description": "Fetch the GitHub GraphQL schema"
            },
            "executeTool": {
              "name": "github_query",
              "description": "Execute a query against the GitHub GraphQL API"
            }
          }
        }
      }
    }
  }
}
```

## Custom GraphQL Tools

For more complex scenarios like bounded mutations or queries with complex logic,
you can create custom GraphQL tools as endpoints using the Zuplo
[custom MCP tool patterns](./custom-tools.mdx) and the `graphql` library.

Here's a simple example of a custom bounded GraphQL query that expects an `id`
input from the MCP client:

```json
{
  "paths": {
    "/graphql/ship": {
      "post": {
        "summary": "Get details about a specific ship",
        "operationId": "get_ship",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id"],
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "The ID of the ship to query"
                  }
                }
              }
            }
          }
        },
        "x-zuplo-route": {
          "handler": {
            "export": "default",
            "module": "$import(./modules/get-ship)"
          }
        }
      }
    }
  }
}
```

In your handler (`modules/get-ship.ts`):

```typescript
import { ZuploContext, ZuploRequest } from "@zuplo/runtime";

export default async function handler(
  request: ZuploRequest,
  context: ZuploContext,
) {
  const { id } = await request.json();

  const query = `
    query GetShip($id: ID!) {
      ship(id: $id) {
        name
        model
        manufacturer
      }
    }
  `;

  const response = await fetch("https://api.example.com/graphql", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query,
      variables: { id },
    }),
  });

  return response;
}
```

For more complex custom tools with validation, error handling, and multi-step
workflows, see the [Custom Tools documentation](./custom-tools.mdx).

## See Also

- [MCP Server Handler](./introduction.mdx) - Main MCP Server documentation
- [Custom Tools](./custom-tools.mdx) - Build custom MCP tools with complex logic
- [GraphQL Best Practices](https://graphql.org/learn/best-practices/) -
  GraphQL.org recommendations
