edouard-claude/mcp-graphql
If you are the rightful owner of mcp-graphql and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
The MCP GraphQL Server is a Go-based server that facilitates the generation and execution of GraphQL queries through a standard MCP transport.
MCP GraphQL Server
A Go-based MCP (Model Context Protocol) server that exposes tools allowing an LLM to generate and execute valid GraphQL queries via HTTP.
🚀 Features
- 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
📦 Installation
Pre-compiled binaries
Download the binary for your platform from releases.
Build from source
git clone https://github.com/edouard-claude/mcp-graphql.git
cd mcp-graphql-server
make build
Docker
docker build -t mcp-graphql-server .
docker run -e GRAPHQL_ENDPOINT=https://api.example.com/graphql mcp-graphql-server
⚙️ Configuration
Environment variables
| 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 | ❌ |
Configuration file (optional)
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: 10
Run with: ./mcp-graphql-server --config=config.yaml
🛠️ MCP Tools
1. graphql.introspectSchema
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-server
2. graphql.printSDL
Generates 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-server
3. graphql.execute
Executes 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-server
4. graphql.validate
Validates 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-server
5. graphql.listOperations
Extracts 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
🔒 Security and Headers
Header merge order (increasing priority)
- Default headers (env/config):
x-api-key,Authorization(ifGRAPHQL_AUTH_BEARER) - Tool parameter headers: Override defaults
Allowed headers
Only these headers can be passed via the headers parameter:
Authorizationx-api-keyx-request-idx-tenant-idcontent-type
Secure configuration example
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"
📝 Complete examples
Complete workflow with jq
#!/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'
Example with curl and a public GraphQL server
# 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
🧪 Tests
# Run all tests
make test
# Tests with coverage
make test-coverage
# Specific tests
go test -v ./internal/graphql/...
go test -v ./internal/util/...
🏗️ Development
Project structure
/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
Development commands
# 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 release
📊 Monitoring and Logs
Log levels
debug: HTTP request details, cache, validationinfo: Important operations, recoverable errorserror: Critical errors only
Example logs
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
🐛 Troubleshooting
Common issues
-
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.
Debugging
# 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 } } }"}'
📄 License
MIT License - see the file for details.
🤝 Contributing
- 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
📞 Support
- 🐛 Issues
- 📖 Documentation
- 💬 Discussions