A Go-based MCP (Model Context Protocol) server that exposes tools allowing an LLM to generate and execute valid GraphQL queries via HTTP.
- Standard MCP transport: JSON-RPC 2.0 over stdio
- GraphQL HTTP client: Uses only Go standard library
- 5 MCP tools:
graphql.introspectSchemaβ GraphQL schema introspectiongraphql.printSDLβ SDL generation from introspectiongraphql.executeβ Query/mutation execution with variablesgraphql.validateβ Query validation against schemagraphql.listOperationsβ Operations and variables extraction
- Header management: Automatic injection of
x-api-key, optionalAuthorization - Security: Secret redaction in logs, timeouts, exponential retries
- Schema cache: Configurable TTL with
forceRefreshoption
Download the binary for your platform from releases.
git clone https://github.com/edouard-claude/mcp-graphql.git
cd mcp-graphql-server
make builddocker build -t mcp-graphql-server .
docker run -e GRAPHQL_ENDPOINT=https://api.example.com/graphql mcp-graphql-server| Variable | Description | Default | Required |
|---|---|---|---|
GRAPHQL_ENDPOINT |
GraphQL endpoint URL | - | β |
GRAPHQL_X_API_KEY |
API key for x-api-key header |
- | β |
GRAPHQL_AUTH_BEARER |
Default Bearer token | - | β |
HTTP_TIMEOUT_SECONDS |
HTTP timeout in seconds | 30 |
β |
HTTP_MAX_RETRIES |
Maximum number of retries | 2 |
β |
LOG_LEVEL |
Log level (info, debug, error) |
info |
β |
HTTP_MAX_PAYLOAD_MB |
Maximum payload size in MB | 2 |
β |
SCHEMA_CACHE_TTL_MINUTES |
Schema cache TTL in minutes | 10 |
β |
Create a config.yaml or config.json file:
endpoint: "https://api.example.com/graphql"
defaultHeaders:
x-api-key: "${GRAPHQL_X_API_KEY}"
retry:
maxRetries: 2
backoffMs: 300
httpTimeout: 30
httpMaxRetries: 2
logLevel: "info"
maxPayloadSize: 2097152
schemaCacheTTL: 10Run with: ./mcp-graphql-server --config=config.yaml
Introspects the GraphQL schema and returns the introspection result.
Parameters:
{
"headers": { "Authorization": "Bearer xxx" },
"withDescriptions": true,
"forceRefresh": false
}Example call:
echo '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "graphql.introspectSchema",
"arguments": { "withDescriptions": true }
}
}' | ./mcp-graphql-serverGenerates the GraphQL schema in SDL format.
Parameters:
{
"headers": {},
"preferFederation": false,
"forceRefresh": false
}Example call:
echo '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "graphql.printSDL",
"arguments": { "preferFederation": false }
}
}' | ./mcp-graphql-serverExecutes a GraphQL query or mutation.
Parameters:
{
"operationName": "GetUser",
"query": "query GetUser($id: ID!) { user(id: $id) { id name } }",
"variables": { "id": "123" },
"headers": { "Authorization": "Bearer xxx" },
"timeoutSeconds": 30
}Example call:
echo '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "graphql.execute",
"arguments": {
"operationName": "GetUser",
"query": "query GetUser($id: ID!) { user(id: $id) { id name } }",
"variables": { "id": "123" },
"headers": { "Authorization": "Bearer XYZ" }
}
}
}' | ./mcp-graphql-serverValidates a GraphQL query against the schema.
Parameters:
{
"query": "query GetUser($id: ID!) { user(id: $id) { id name } }",
"operationName": "GetUser",
"headers": {}
}Example call:
echo '{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "graphql.validate",
"arguments": {
"query": "query GetUser($id: ID!) { user(id: $id) { id name } }",
"operationName": "GetUser"
}
}
}' | ./mcp-graphql-serverExtracts all operations and their variables from a GraphQL document.
Parameters:
{
"query": "query GetUser($id: ID!) { user(id: $id) { id name } } mutation CreateUser($name: String!) { createUser(name: $name) { id } }"
}Example call:
echo '{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "graphql.listOperations",
"arguments": {
"query": "query GetUser($id: ID!) { user(id: $id) { id name } } mutation CreateUser($name: String!) { createUser(name: $name) { id } }"
}
}
}' | ./mcp-graphql-server- Default headers (env/config):
x-api-key,Authorization(ifGRAPHQL_AUTH_BEARER) - Tool parameter headers: Override defaults
Only these headers can be passed via the headers parameter:
Authorizationx-api-keyx-request-idx-tenant-idcontent-type
export GRAPHQL_ENDPOINT="https://api.example.com/graphql"
export GRAPHQL_X_API_KEY="your-api-key"
export GRAPHQL_AUTH_BEARER="your-default-token"
export LOG_LEVEL="info"#!/bin/bash
# Configuration
ENDPOINT="https://api.example.com/graphql"
API_KEY="your-api-key"
# 1. List available tools
echo "=== Available tools ==="
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | \
./mcp-graphql-server | jq '.result.tools[].name'
# 2. Introspect schema
echo -e "\n=== Schema introspection ==="
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"graphql.introspectSchema","arguments":{"withDescriptions":true}}}' | \
./mcp-graphql-server | jq '.result.content[0].text' | jq '.introspection.queryType.name'
# 3. Generate SDL
echo -e "\n=== SDL generation ==="
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"graphql.printSDL","arguments":{}}}' | \
./mcp-graphql-server | jq -r '.result.content[0].text' | jq -r '.sdl' | head -20
# 4. List operations from a query
echo -e "\n=== Operations extraction ==="
QUERY='query GetUser($id: ID!) { user(id: $id) { id name email } } mutation CreateUser($name: String!, $email: String!) { createUser(name: $name, email: $email) { id } }'
echo "{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"tools/call\",\"params\":{\"name\":\"graphql.listOperations\",\"arguments\":{\"query\":\"$QUERY\"}}}" | \
./mcp-graphql-server | jq '.result.content[0].text' | jq '.operations[]'
# 5. Validate a query
echo -e "\n=== Query validation ==="
echo "{\"jsonrpc\":\"2.0\",\"id\":5,\"method\":\"tools/call\",\"params\":{\"name\":\"graphql.validate\",\"arguments\":{\"query\":\"$QUERY\",\"operationName\":\"GetUser\"}}}" | \
./mcp-graphql-server | jq '.result.content[0].text' | jq '.isValid'
# 6. Execute a query
echo -e "\n=== Query execution ==="
echo "{\"jsonrpc\":\"2.0\",\"id\":6,\"method\":\"tools/call\",\"params\":{\"name\":\"graphql.execute\",\"arguments\":{\"operationName\":\"GetUser\",\"query\":\"query GetUser(\$id: ID!) { user(id: \$id) { id name } }\",\"variables\":{\"id\":\"123\"}}}}}" | \
./mcp-graphql-server | jq '.result.content[0].text'# Use Rick and Morty GraphQL API as example
export GRAPHQL_ENDPOINT="https://rickandmortyapi.com/graphql"
# Introspection
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"graphql.introspectSchema","arguments":{"withDescriptions":true}}}' | \
./mcp-graphql-server | jq '.result.content[0].text' | jq '.introspection.queryType.name'
# Query execution
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"graphql.execute","arguments":{"query":"{ characters { results { name } } }"}}}' | \
./mcp-graphql-server | jq '.result.content[0].text'
# SDL generation
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"graphql.printSDL","arguments":{}}}' | \
./mcp-graphql-server | jq -r '.result.content[0].text' | jq -r '.sdl' | head -20# Run all tests
make test
# Tests with coverage
make test-coverage
# Specific tests
go test -v ./internal/graphql/...
go test -v ./internal/util/.../cmd/mcp-graphql-server
main.go # Entry point
/internal/mcp
server.go # JSON-RPC server, tool registry
tools.go # Tool definitions and handlers
types.go # MCP request/response structures
/internal/graphql
client.go # HTTP client, execution
introspection.go # Introspection request and cache
sdl.go # SDL generation
validate.go # Basic schema validation
ops.go # Operation and variable extraction
/internal/config
config.go # Environment + file + flag configuration
/internal/logging
logger.go # Logger with redaction
/internal/util
redact.go # Secret redaction
retry.go # Backoff/retry
# Formatting and linting
make fmt vet
# Build and test
make all
# Run in development mode
make run-example
# Build for all platforms
make build-all
# Create a release
make releasedebug: HTTP request details, cache, validationinfo: Important operations, recoverable errorserror: Critical errors only
2024-01-15T10:30:00Z INFO Starting MCP GraphQL server endpoint=https://api.example.com/graphql
2024-01-15T10:30:01Z DEBUG Executing GraphQL request endpoint=https://api.example.com/graphql operationName=GetUser headers=map[Authorization:**** x-api-key:****]
2024-01-15T10:30:01Z DEBUG GraphQL response received hasData=true errorCount=0
-
Error "GRAPHQL_ENDPOINT is required"
export GRAPHQL_ENDPOINT="https://your-api.com/graphql"
-
Timeout on requests
export HTTP_TIMEOUT_SECONDS=60 -
Authentication errors
export GRAPHQL_X_API_KEY="your-api-key" # or export GRAPHQL_AUTH_BEARER="your-token"
-
Stale schema cache Use
"forceRefresh": truein tool parameters.
# Enable detailed logs
export LOG_LEVEL=debug
./mcp-graphql-server
# Test connectivity
curl -X POST https://your-api.com/graphql \
-H "Content-Type: application/json" \
-H "x-api-key: your-key" \
-d '{"query":"{ __schema { queryType { name } } }"}'MIT License - see the LICENSE file for details.
- Fork the project
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- π Issues
- π Documentation
- π¬ Discussions