Skip to main content
Glama
README.md
**Experimental PoC**

# graphql-mcp

An MCP (Model Context Protocol) server that exposes GraphQL operations as
tools for AI models. Point it at any GraphQL endpoint and a schema, and it
turns your operations into typed MCP tools — with schema exploration tools,
hot reload, OAuth resource-server auth, MCP prompts, MCP Apps widgets, and
OpenTelemetry built in.

Configuration is plain TypeScript — no YAML, no env-var templating; read
`process.env` directly in your config file.

## Quick start

```bash
npm install graphql-mcp   # or pnpm add / vp add
```

Create `graphql-mcp.config.ts`:

```ts
import { defineConfig } from "graphql-mcp";

export default defineConfig({
  endpoint: "http://localhost:4000/graphql",
  schema: { source: "local", path: "./schema.graphql" },
  operations: { source: "local", paths: ["./operations"] },
  tools: {
    introspect: { enabled: true },
    search: { enabled: true },
    validate: { enabled: true },
    execute: { enabled: true },
  },
});
```

Run it:

```bash
graphql-mcp                     # stdio transport (default)
graphql-mcp path/to/config.ts   # explicit config path
```

Local schema files, operation files, prompt files, and the config file itself
are watched: edits hot reload without dropping connected sessions (config
changes trigger a validated in-process restart; `SIGHUP` forces one).

## How operations become tools

Every named GraphQL operation in your operation files becomes one MCP tool:

- The tool name is the operation name; leading `#` comments become the tool
  description (otherwise one is generated from schema descriptions plus the
  tree-shaken SDL of the types the operation touches).
- The input schema is derived from the operation's variables (non-null
  variables are required; input objects, enums, lists, and custom scalars are
  fully expanded). `#` comments before individual variables override their
  descriptions.
- Queries are annotated read-only and idempotent; mutations destructive.
  Mutations are skipped unless `overrides.mutationMode` is `explicit` or
  `all`.
- Fields marked `@private` are stripped from the query sent downstream and
  filtered out of the structured result the model sees (the full response is
  preserved in `_meta.structuredContent` for the host client).

Operation sources: `local` (watched `.graphql` files/directories), `manifest`
(a local `apollo-persisted-query-manifest` v1 JSON file), or `none`.

## Schema tools

Four individually toggleable tools under `tools`:

| Tool         | What it does                                                                                                                |
| ------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `introspect` | Returns the SDL for a named type, recursing to a `depth`; optional token-cheap minified encoding.                           |
| `search`     | Full-text search over type names, descriptions, and fields; returns tree-shaken SDL along scored paths from the root types. |
| `validate`   | Validates an operation against the schema without executing it.                                                             |
| `execute`    | Executes an ad hoc operation written by the model (mutations only when `mutationMode: "all"`).                              |

Each accepts an optional `hint` appended to its description.

## Transports

- `stdio` (default) — for local MCP clients.
- `http` — streamable HTTP on `/mcp` with per-session state (or stateless via
  `statefulMode: false`), CORS, Host/Origin validation against DNS rebinding,
  a `/health` endpoint (`?live` / `?ready`), and graceful shutdown.

### OAuth 2.1 resource server

Nest `auth` under the HTTP transport to require bearer tokens:

```ts
transport: {
  type: "http",
  port: 8000,
  auth: {
    servers: ["https://auth.example.com"], // OIDC/OAuth discovery + JWKS
    audiences: ["my-api"],
    scopes: ["read:graphql"],
    scopeMode: "require_all",
  },
},
overrides: {
  requiredScopes: { DeleteUser: ["admin"] }, // per-operation step-up
},
```

The server publishes RFC 9728 protected-resource metadata at
`/.well-known/oauth-protected-resource`, answers challenges with
`WWW-Authenticate` (including `insufficient_scope`), and passes validated
tokens through to the GraphQL endpoint (disable with
`disableAuthTokenPassthrough`).

## Prompts and MCP Apps

- `prompts: { directory: "./prompts" }` serves Markdown files with YAML
  frontmatter (`name`, `description`, `arguments`) as MCP prompts, with
  `{{arg}}` substitution and hot reload.
- `apps: { directory: "./apps" }` serves MCP Apps: each subdirectory with an
  `.application-manifest.json` contributes a `ui://widget/...` HTML resource
  and entrypoint tools backed by GraphQL operations, including prefetch
  operations, extra inputs/outputs, CSP and widget settings, and
  OpenAI-Apps-SDK/MCP-Apps targeting via `?appTarget=` or client capabilities.

## Telemetry

```ts
telemetry: {
  serviceName: "my-graphql-mcp",
  exporters: {
    metrics: { otlp: { protocol: "http/protobuf" } },
    tracing: { otlp: { endpoint: "http://collector:4318/v1/traces" } },
  },
},
```

Emits `graphql_mcp.operation.count` / `graphql_mcp.operation.duration`
metrics and per-tool-call spans, with configurable attribute omission,
export interval, and sampler.

## Config reference

Top-level keys (all optional except `schema`):

| Key                          | Purpose                                                                                                                                      |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `endpoint`                   | Target GraphQL URL (default `http://localhost:4000/graphql`).                                                                                |
| `schema`                     | `{ source: "local", path, watch? }` — the SDL file to serve from.                                                                            |
| `operations`                 | `local` paths, `manifest` file, or `none`.                                                                                                   |
| `transport`                  | `{ type: "stdio" }` or `{ type: "http", address?, port?, statefulMode?, hostValidation?, auth? }`.                                           |
| `tools`                      | Enable/configure `introspect`, `search`, `validate`, `execute`.                                                                              |
| `overrides`                  | `mutationMode`, `descriptions`, `annotations`, `requiredScopes`, `enableOutputSchema`, `disableTypeDescription`, `disableSchemaDescription`. |
| `headers` / `forwardHeaders` | Static headers and client headers forwarded to GraphQL.                                                                                      |
| `cors`, `healthCheck`        | HTTP transport policies.                                                                                                                     |
| `serverInfo`, `instructions` | MCP identity and initialize instructions.                                                                                                    |
| `customScalars`              | Inline map of scalar name to JSON Schema, or a path to a JSON file.                                                                          |
| `prompts`, `apps`            | Prompt and MCP App directories.                                                                                                              |
| `logging`                    | `level`, optional `path` (rotating file logs), `rotation`.                                                                                   |
| `telemetry`                  | OpenTelemetry metrics/tracing via OTLP.                                                                                                      |

The config is validated with helpful errors; unknown keys are rejected. See
[examples/graphql-mcp.config.ts](examples/graphql-mcp.config.ts) for a
commented full example.

## Development

```bash
vp install   # install dependencies
vp check     # format, lint, type check
vp test      # run the test suite
vp pack      # build dist/ (library + CLI)
```

## Acknowledgements

The behavior of this server is a TypeScript reimplementation inspired by the
MIT-licensed [Apollo MCP Server](https://github.com/apollographql/apollo-mcp-server)
(Rust), excluding its GraphOS-specific functionality.

## License

MIT