Skip to main content

graphql-mcp

A library for automatically generating FastMCP tools from a GraphQL schema.

This allows you to expose your GraphQL API as a set of tools that can be used by other systems, such as AI agents or other services that understand the MCP (Multi-Model-Protocol).

Features

  • Automatic Tool Generation: Converts GraphQL queries and mutations into callable Python functions.
  • Type-Safe: Maps GraphQL scalar types, enums, and input objects to corresponding Python types.
  • FastMCP Integration: Seamlessly adds the generated functions as tools to a FastMCP server instance.
  • Modern GraphQL Libraries: Works with modern, code-first GraphQL libraries like strawberry-graphql.
  • Asynchronous Support: While the tool generation is synchronous, the created tools execute GraphQL queries in a way that can be integrated into asynchronous applications.
  • Remote GraphQL Server Support: Connect to any remote GraphQL endpoint and automatically generate MCP tools from its schema.
  • Bearer Token Authentication: Built-in support for bearer token authentication with automatic token refresh capability.
  • Flexible Authentication: Combine bearer tokens with additional headers for complex authentication scenarios.
  • Mutation Control: Optionally disable mutations to create read-only tool interfaces for enhanced security.

Installation

You can install graphql-mcp using pip. To follow the usage example, you'll also need strawberry-graphql:

pip install graphql-mcp "strawberry-graphql[cli]"

Usage with Strawberry

Here's a simple example of how to use graphql-mcp to create tools from a strawberry-graphql schema.

# example.py
import asyncio
import strawberry
from fastmcp import FastMCP
from graphql_mcp.server import add_tools_from_schema

# 1. Define your GraphQL schema using Strawberry
@strawberry.type
class Query:
    @strawberry.field
    def hello(self, name: str = "World") -> str:
        """Returns a greeting."""
        return f"Hello, {name}!"

@strawberry.type
class Mutation:
    @strawberry.mutation
    def send_message(self, message: str) -> str:
        """Prints a message and returns a confirmation."""
        print(f"Received message: {message}")
        return f"Message '{message}' sent successfully."

# The strawberry.Schema object is compatible with graphql-core's GraphQLSchema
schema = strawberry.Schema(query=Query, mutation=Mutation)

# 2. Create a FastMCP server instance
server = FastMCP(name="MyGraphQLServer")

# 3. Add tools from the schema
# The `strawberry.Schema` object can be passed directly.
add_tools_from_schema(schema, server)

# 4. Use the generated tools
async def main():
    # You can inspect the tools
    print("Available tools:", server.get_tool_names())
    
    # You can also inspect a specific tool's signature
    print("Tool 'hello' signature:", server.get_tool_signature("hello"))

    # Call a query tool
    result = await server.acall_tool("hello", name="Bob")
    print("Query result:", result)

    # Call a mutation tool
    result = await server.acall_tool("send_message", message="This is a test")
    print("Mutation result:", result)

if __name__ == "__main__":
    asyncio.run(main())

When you run this script, you will see the following output:

Available tools: ['send_message', 'hello']
Tool 'hello' signature: (name: str = 'World') -> str
Query result: Hello, Bob!
Received message: This is a test
Mutation result: Message 'This is a test' sent successfully.

Alternative Usage: GraphQLMCPServer

For convenience, you can also use the GraphQLMCPServer class, which inherits from FastMCP and provides class methods to create a server directly from a schema.

From a GraphQLSchema object

You can use GraphQLMCPServer.from_schema() and pass any graphql-core-compatible GraphQLSchema object. This includes schemas created with strawberry-graphql.

From a Remote GraphQL Server

You can connect to a remote GraphQL endpoint and automatically generate MCP tools from its schema:

# example_remote_server.py
import asyncio
from graphql_mcp.server import GraphQLMCPServer
from fastmcp.client import Client

# Connect to a remote GraphQL server
server = GraphQLMCPServer.from_remote_url(
    url="https://countries.trevorblades.com/",  # Public GraphQL API
    name="Countries API"
)

# With bearer token authentication
authenticated_server = GraphQLMCPServer.from_remote_url(
    url="https://api.example.com/graphql",
    bearer_token="YOUR_BEARER_TOKEN",  # Bearer token authentication
    timeout=60,  # Custom timeout in seconds
    name="Private API"
)

# With bearer token and additional headers
multi_auth_server = GraphQLMCPServer.from_remote_url(
    url="https://api.example.com/graphql",
    bearer_token="YOUR_BEARER_TOKEN",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "X-Request-ID": "request-123"
    },
    timeout=60,
    name="Multi-Auth API"
)

# Read-only server (queries only, no mutations)
readonly_server = GraphQLMCPServer.from_remote_url(
    url="https://api.example.com/graphql",
    bearer_token="YOUR_BEARER_TOKEN",
    allow_mutations=False,  # Disable mutations for security
    name="Read-Only API"
)

# Use the server - all queries/mutations from the remote schema are now MCP tools
async def main():
    async with Client(server) as client:
        # List available tools
        tools = await client.list_tools()
        print(f"Available tools: {[tool.name for tool in tools]}")
        
        # Call a tool (executes against the remote server)
        # The actual tool names depend on the remote schema
        # result = await client.call_tool("countries", {"filter": {"currency": {"eq": "USD"}}})

if __name__ == "__main__":
    asyncio.run(main())

From a GraphQLSchema object

You can use GraphQLMCPServer.from_schema() and pass any graphql-core-compatible GraphQLSchema object. This includes schemas created with strawberry-graphql.

# example_from_schema.py
import asyncio
import strawberry
from graphql_mcp.server import GraphQLMCPServer

# 1. Define your schema (e.g., with Strawberry)
@strawberry.type
class Query:
    @strawberry.field
    def hello(self, name: str = "World") -> str:
        return f"Hello, {name}!"

schema = strawberry.Schema(query=Query)

# 2. Create the server from the schema
server = GraphQLMCPServer.from_schema(schema, name="MyGraphQLServer")

# 3. Create a read-only server (queries only)
readonly_server = GraphQLMCPServer.from_schema(
    schema, 
    allow_mutations=False,  # Disable mutations
    name="ReadOnlyGraphQLServer"
)

# 4. Use the server
async def main():
    print("Available tools:", server.get_tool_names())
    result = await server.acall_tool("hello", name="From Schema")
    print("Query result:", result)

if __name__ == "__main__":
    asyncio.run(main())

From a graphql-api object

If you are using the graphql-api library, you can use the GraphQLMCPServer.from_api() method.

# example_from_api.py
import asyncio
from graphql_api import GraphQLAPI, field
from graphql_mcp.server import GraphQLMCPServer, HAS_GRAPHQL_API

# The .from_graphql_api() method is only available if `graphql-api` is installed.
if HAS_GRAPHQL_API:
    # 1. Define your API using `graphql-api`
    class MyAPI:
        @field
        def hello(self, name: str = "World") -> str:
            return f"Hello, {name}!"

    api = GraphQLAPI(roottype=MyAPI)

    # 2. Create the server from the API object
    server = GraphQLMCPServer.from_graphql_api(api)

    # 3. Use the server
    async def main():
        print("Available tools:", server.get_tool_names())
        result = await server.acall_tool("hello", name="From API")
        print("Query result:", result)

    if __name__ == "__main__":
        asyncio.run(main())

How It Works

graphql-mcp introspects your GraphQL schema's queries and mutations. For each field, it does the following:

  1. Creates a Python Function: A wrapper function is generated that has a signature matching the GraphQL field's arguments.
  2. Handles Type Conversion: It maps GraphQL types like String, Int, ID, and custom Enum types to their Python equivalents. Input objects are treated as dictionaries.
  3. Constructs a GraphQL Query: When the generated function is called, it dynamically constructs the appropriate GraphQL query or mutation string.
  4. Executes the Query: It uses graphql-sync to execute the query against the schema, passing in the provided arguments as variables.
  5. Returns the Result: The data from the GraphQL response is returned.

The tool names are converted from camelCase (GraphQL convention) to snake_case (Python convention). For example, a mutation sendMessage becomes a tool named send_message.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Metadata

Release files for graphql-mcp 1.3.12

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for graphql-mcp 1.3.12
File Size Uploaded
graphql_mcp-1.3.12.tar.gz 67.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for graphql-mcp 1.3.12
File Interpreter ABI Platform
graphql_mcp-1.3.12-py3-none-any.whl Python 3 none any Details

Total release size: 146.9 kB

Release files / graphql_mcp-1.3.12.tar.gz

Download URL graphql_mcp-1.3.12.tar.gz
Size 67.8 kB
Tags Source
SHA-256 checksum
How to use checksums
3c32da13bc3831e163ada9ab137f1341d5fd422828e0ede01134e552e3617468
BLAKE2b-256 checksum
How to use checksums
4519d3fa6ac1167f48e6ae7c062792f4a8b439d6194af0da4a110319264e7730
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.5

Release files / graphql_mcp-1.3.12-py3-none-any.whl

Download URL graphql_mcp-1.3.12-py3-none-any.whl
Size 79.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e7592cefa50836e5c2811da0afbb78723e27f1ff9436b6d8d4e3569906c84afc
BLAKE2b-256 checksum
How to use checksums
5f48cbacadf008c9c5ba8860412a3e5478c2fa2c6d4625ad953a89629a247d6d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.5

Release history Release notifications | RSS feed

2.3.1

2 release files

2.3.0

2 release files

2.2.0

2 release files

2.1.6

2 release files

2.1.5

2 release files

2.1.4

2 release files

2.1.3

2 release files

2.1.2

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.7.9

2 release files

1.7.8

2 release files

1.7.7

2 release files

1.7.6

2 release files

1.7.4

2 release files

1.7.1

2 release files

1.7.0

2 release files

1.6.1

2 release files

1.6.0

2 release files

1.5.5

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.22

2 release files

1.3.21

2 release files

1.3.20

2 release files

1.3.19

2 release files

1.3.18

2 release files

1.3.17

2 release files

1.3.16

2 release files

1.3.15

2 release files

1.3.13

2 release files

This release

1.3.12 This release

2 release files

1.3.11

2 release files

1.3.10

2 release files

1.3.9

2 release files

1.3.8

2 release files

1.3.7

2 release files

1.3.6

2 release files

1.3.4

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page