A Model Context Protocol (MCP) server that provides AI agents with flexible access to GraphQL APIs. This tool enables both direct GraphQL query execution and dynamic creation of custom tools that persist across sessions.
MCP servers that wrap existing APIs can be awkward for agents to use. Either they expose everything, leaving the agent to piece everything together from scratch in each new session, or they are too intentional, constraining the agent to just a few possible use-cases. This tool attempts to strike a balance, starting with just a general purpose GraphQL query tool but allowing the agent to save queries as tools to be reused in future sessions.
Work with your agent to build and maintain tools adapted to your workflow.
execute_graphql_query
- Execute arbitrary GraphQL queries directlysave_query
- Create or update custom tools from GraphQL querieslist_saved_queries
- List all saved custom toolsshow_saved_query
- View complete definition of a saved tooldelete_saved_query
- Remove a saved tool
- Direct GraphQL Execution - Execute arbitrary GraphQL queries against any endpoint
- Dynamic Tool Creation - Create custom tools from GraphQL queries that persist across sessions
- Configurable Headers - Flexible header configuration via environment variables for any authentication method
- Parameter Validation - JSON Schema-based parameter validation for custom tools
- Cross-Session Persistence - Tools and configurations persist between sessions via JSON files
- MCP Protocol Compliance - Full support for MCP capabilities including list change notifications
# Clone the repository
git clone https://github.com/dslh/mcp-graphql-metatool.git
cd mcp-graphql-metatool
# Install dependencies
yarn install
# Build the project
yarn build
Set up your GraphQL endpoint and headers using environment variables:
# Required: GraphQL API endpoint
export GRAPHQL_ENDPOINT="https://api.example.com/graphql"
Configure HTTP headers using the GRAPHQL_HEADER_*
pattern. Environment variable names are converted to HTTP header names by:
- Removing the
GRAPHQL_HEADER_
prefix - Converting to lowercase
- Replacing underscores with hyphens
Basic Bearer Token Authentication:
export GRAPHQL_HEADER_AUTHORIZATION="Bearer your-token-here"
Cookie-based Authentication:
export GRAPHQL_HEADER_COOKIE="sessionId=abc123; token=xyz789"
API Key in Custom Header:
export GRAPHQL_HEADER_X_API_KEY="your-api-key"
export GRAPHQL_HEADER_X_CLIENT_ID="your-client-id"
Custom User Agent and Content Type:
export GRAPHQL_HEADER_USER_AGENT="MyApp/1.0"
export GRAPHQL_HEADER_CONTENT_TYPE="application/json"
# Legacy: Bearer token for authentication
export GRAPHQL_AUTH_TOKEN="your-bearer-token-here"
# Legacy: Cookie header for authentication
export GRAPHQL_COOKIE_HEADER="sessionId=abc123; token=xyz789"
Note: GRAPHQL_HEADER_*
variables take precedence over legacy variables.
-
Start the server:
yarn start
-
Execute a GraphQL query directly:
// Use the execute_graphql_query tool { "query": "query GetUser($id: ID!) { user(id: $id) { name email } }", "variables": { "id": "123" } }
-
Create a custom tool from a query:
// Use the save_query tool { "tool_name": "get_user_by_id", "description": "Get user details by ID", "graphql_query": "query GetUser($id: ID!) { user(id: $id) { name email } }", "parameter_schema": { "type": "object", "properties": { "id": { "type": "string", "description": "User ID" } }, "required": ["id"] } }
Execute any GraphQL query directly:
// Tool: execute_graphql_query
{
"query": "{ users(first: 10) { nodes { id name email } } }"
}
Transform frequently used queries into reusable tools:
// Tool: save_query
{
"tool_name": "list_recent_users",
"description": "List recently created users",
"graphql_query": "query ListUsers($limit: Int!, $since: DateTime) { users(first: $limit, createdAfter: $since) { nodes { id name email createdAt } } }",
"parameter_schema": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Number of users to return",
"default": 10,
"minimum": 1,
"maximum": 100
},
"since": {
"type": "string",
"description": "ISO datetime to filter users created after",
"format": "date-time"
}
},
"required": ["limit"]
}
}
// List all saved tools
// Tool: list_saved_queries
// View a specific tool definition
// Tool: show_saved_query
{ "tool_name": "get_user_by_id" }
// Delete a tool
// Tool: delete_saved_query
{ "tool_name": "old_tool_name" }
Execute arbitrary GraphQL queries.
Parameters:
query
(string, required) - The GraphQL query to executevariables
(object, optional) - Variables for the query
Create or update a custom tool from a GraphQL query.
Parameters:
tool_name
(string, required) - Snake_case name for the tooldescription
(string, required) - Human-readable descriptiongraphql_query
(string, required) - GraphQL query with $variable placeholdersparameter_schema
(object, required) - JSON Schema defining tool parametersoverwrite
(boolean, optional) - Whether to overwrite existing tools (default: false)
List all saved custom tools.
View the complete definition of a saved tool.
Parameters:
tool_name
(string, required) - Name of the tool to show
Remove a saved tool.
Parameters:
tool_name
(string, required) - Name of the tool to delete
The server is built with a modular architecture:
- Server Entry Point (
src/index.ts
) - MCP server setup and tool registration - GraphQL Client (
src/client.ts
) - Singleton GraphQL client with authentication - Dynamic Tool Handler (
src/dynamicToolHandler.ts
) - Runtime tool creation from saved configurations - Storage System (
src/storage.ts
) - JSON file-based persistence for tools - Type Validation (
src/jsonSchemaValidator.ts
) - JSON Schema to Zod conversion for parameter validation
Tools are persisted as individual JSON files in the data/tools/
directory:
data/
├── tools/
│ ├── get_user_by_id.json
│ ├── list_recent_users.json
│ └── ...
└── types/
└── (reserved for future custom type definitions)
# Development mode with hot reload
yarn dev
# Build for production
yarn build
# Run production server
yarn start
# Linting and formatting
yarn lint
yarn lint:fix
yarn format
yarn format:check
# Testing
yarn test
yarn test:watch
yarn test:coverage
yarn test:ui
- TypeScript with strict configuration
- ESLint with comprehensive rules for security and code quality
- Prettier for consistent code formatting
- Vitest for testing with coverage reporting
- No default exports - All exports must be named
- Single quotes and semicolons required
Variable | Required | Description |
---|---|---|
GRAPHQL_ENDPOINT |
Yes | GraphQL API endpoint URL |
GRAPHQL_HEADER_* |
No | HTTP headers (see Header Configuration) |
GRAPHQL_AUTH_TOKEN |
No | Legacy: Bearer token for authentication |
GRAPHQL_COOKIE_HEADER |
No | Legacy: Cookie header for authentication |
This project implements Phase 0-1 of the requirements:
- ✅ Basic GraphQL execution (
execute_graphql_query
) - ✅ Tool creation (
save_query
) - ✅ Cross-session persistence (JSON files)
- ✅ MCP list change notifications
- ⏳ Context management (planned)
- ⏳ Schema exploration (planned)
See requirements.md
for the complete roadmap.
MIT License - see LICENSE file for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
yarn test
- Ensure linting passes:
yarn lint
- Submit a pull request
Doug Hammond [email protected]