Skip to main content
Glama

mcp-graphql-forge

by toolprint
GraphQL-to-AI-Tools-MCP-Guide.ipynbโ€ข22.9 kB
{ "cells": [ { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "# ๐Ÿš€ GraphQL to MCP Starterkit\n", "\n", "**Do you want to use your GraphQL APIs with agents? Let's give it a shot.**\n", "\n", "## ๐Ÿ“‹ Goals\n", "\n", "### The Basics\n", "1. **GraphQL โ†” AI Concepts**: How schemas become tool contracts\n", "2. **Safety First**: Queries vs mutations in AI context \n", "3. **Hands-On Examples**: Real GraphQL APIs โ†’ MCP\n", "\n", "## Connect your GQL APIs to real AI apps\n", "4. **AI Client Integration**: Claude & Cursor setup\n", "5. **Schema Design**: Writing AI-friendly documentation\n", "\n", "## Beyond the homelab setup\n", "6. **Production Ready**: Authentication, governance, monitoring\n", "7. **Toolprint Integration**: Smart tool orchestration\n", "\n", "## ๐ŸŽฏ Prerequisites\n", "\n", "- Basic GraphQL knowledge (queries, mutations, schemas)\n", "- Command line comfort\n", "- Node.js installed\n", "- An existing GraphQL API (or we'll use examples)\n", "\n", "\n", "---\n" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "## ๐Ÿง  Chapter 1: GraphQL Meets AI - The Conceptual Bridge\n", "\n", "### Why GraphQL + AI = Perfect Match\n", "\n", "GraphQL APIs are uniquely suited for AI tool integration because they are:\n", "\n", "- **๐Ÿ” Self-Documenting**: Schemas contain type information and descriptions\n", "- **๐ŸŽฏ Strongly Typed**: Clear parameter validation and return types \n", "- **๐Ÿ”Ž Introspectable**: APIs can describe themselves programmatically\n", "- **โšก Efficient**: Single endpoint, precise field selection\n", "\n", "### The Challenge: Raw GraphQL โ‰  AI-Ready Tools\n", "\n", "However, GraphQL APIs aren't immediately AI-accessible:\n", "\n", "```graphql\n", "# This GraphQL query...\n", "query GetUser($id: ID!) {\n", " user(id: $id) {\n", " id\n", " name\n", " posts {\n", " title\n", " author { # ๐Ÿšจ Circular reference!\n", " name\n", " }\n", " }\n", " }\n", "}\n", "```\n", "\n", "**AI agents struggle with:**\n", "- Writing complex field selections\n", "- Handling circular references \n", "- Understanding parameter requirements\n", "- Knowing which tools exist\n" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "### The MCP Solution: Universal Tool Protocol\n", "\n", "**Model Context Protocol (MCP)** bridges this gap by providing a standardized way for AI tools to communicate with data sources and APIs.\n", "\n", "The solution requires something that can:\n", "1. **Introspect the GraphQL schema** to understand available operations\n", "2. **Generate individual tools** for each query and mutation\n", "3. **Handle field selection automatically** to avoid GraphQL validation errors\n", "4. **Provide proper parameter validation** before execution\n", "\n", "\n", "<img alt=\"Basic architecture of a MCP <> GraphQL Proxy\" src=\"./assets/mcp-graphql-proxy.png\" width=\"50%\" height=\"50%\">" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "plaintext" } }, "source": [ "### ๐Ÿฑ Some Food for Thought\n", "\n", "Before we dive into implementation, there are important caveats to consider:\n", "\n", "#### 1. **Mutation Safety**: Should mutations be exposed as tools?\n", "```graphql\n", "# This becomes a tool that could delete data!\n", "type Mutation {\n", " deleteUser(id: ID!): Boolean\n", " chargeCard(amount: Float!): PaymentResult \n", "}\n", "```\n", "**Question**: Should AI agents have unrestricted access to write operations?\n", "\n", "#### 2. **Data Shape**: How much data should we return?\n", "```graphql\n", "# Minimal - fast, fits in context\n", "{ id, name }\n", "\n", "# Expansive - comprehensive, but large\n", "{ id, name, email, posts { title, content, comments { author, text } } }\n", "```\n", "**Consideration**: Context window limits vs completeness\n", "\n", "#### 3. **Query Composition**: Some queries only make sense together\n", "```graphql\n", "# Step 1: Get user ID\n", "user(username: \"john\") { id }\n", "\n", "# Step 2: Get user's posts (needs ID from step 1) \n", "posts(authorId: \"user-123\") { title }\n", "```\n", "#### 4. **Challenge**: Individual tools may not provide complete workflows" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "## ๐Ÿ”ฌ Chapter 3: DEMO - make a real GraphQL service an MCP\n", "\n", "Option 1 - **connect to toolprint graphql api without authentication**\n", "_Note that this may take a few seconds to load up because it's running on Strapi's free tier_\n", "\n", "This will be your environment variable for the next step:\n", "```\n", "export GRAPHQL_ENDPOINT=https://patient-song-383e3762d2.strapiapp.com/graphql\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "plaintext" } }, "outputs": [], "source": [ "GRAPHQL_ENDPOINT=https://patient-song-383e3762d2.strapiapp.com/graphql \\\n", "npx -y @toolprint/mcp-graphql-forge --transport http --port 3001" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Option 2 - **connect to the github graphql API**\n", "1. Grab your existing Github Personal Access Token (! Ensure that it only has READ perms for safety) OR [follow this guide](https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api?apiVersion=2022-11-28) to create a new one. \n", "\n", "These will be your environment variables for the next step:\n", "```\n", "export GRAPHQL_ENDPOINT=https://api.github.com/graphql\n", "export GRAPHQL_AUTH_HEADER=Bearer ${GH_TOKEN}\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "plaintext" } }, "outputs": [], "source": [ "GRAPHQL_ENDPOINT=https://api.github.com/graphql \\\n", "GRAPHQL_AUTH_HEADER=Bearer ${GH_TOKEN} \\\n", "npx -y @toolprint/mcp-graphql-forge --transport http --port 3001" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we'll inspect our tools using [mcp inspector](https://github.com/modelcontextprotocol/inspector)\n", "When we launch the inspector, grab the URL outputted in the terminal and open it up. Then, connect to our launched MCP <> GraphQL Proxy on the connection menu like so:\n", "\n", "<img alt=\"Basic architecture of a MCP <> GraphQL Proxy\" src=\"./assets/connect-via-inspector.png\" width=\"30%\" height=\"30%\">\n", "\n", "**Note that our mcp <> graphql proxy is using the Streamable HTTP transport via the --transport http flag**\n", "\n", "## Exploring Our Tools in MCP Inspector\n", "\n", "Now that we have our MCP server running, let's explore the tools it generated using the MCP Inspector. The inspector provides a visual interface to:\n", "1. Browse all available tools\n", "2. Understand tool parameters and requirements\n", "3. Test tool execution in real-time\n", "\n", "### Connecting to the Inspector\n", "\n", "1. Open the MCP Inspector URL shown in your terminal\n", "2. Click \"Connect to MCP Server\" in the top right\n", "3. Enter the connection URL: `http://localhost:3001/mcp`\n", "4. Click \"Connect\"\n", "\n", "You should now see a list of all tools generated from your GraphQL schema!\n", "\n", "### Understanding Tool Structure\n", "\n", "Let's examine some tools in detail:\n", "\n", "#### Query Tools (Safe Read Operations)\n", "- `query_articles` - List content articles\n", "- `query_categories` - Get content categories\n", "- `query_users` - Retrieve user information\n", "\n", "Notice how each tool shows:\n", "- ๐Ÿ“ **Description** - From your GraphQL schema documentation\n", "- ๐Ÿ” **Parameters** - Required (marked with *) vs Optional\n", "- ๐Ÿ“Š **Response Type** - Expected return data structure\n", "\n", "### Try These Examples\n", "\n", "1. **Simple Query (Optional Parameters)**\n", " - Tool: `query_articles`\n", " - Parameters:\n", " ```json\n", " {\n", " \"pagination\": {\n", " \"limit\": 5\n", " }\n", " }\n", " ```\n", " - Notice: `pagination` is optional, but when provided must follow the schema\n", "\n", "2. **Query with Required Parameters**\n", " - Tool: `query_article`\n", " - Parameters:\n", " ```json\n", " {\n", " \"id\": \"1\" // ! Use an id value from the previous example.\n", " }\n", " ```\n", " - Try: Remove the `id` and see validation prevent execution\n", "\n", "### Understanding the Magic\n", "\n", "This clear parameter structure exists because `mcp-graphql-forge` has:\n", "1. **Introspected** your GraphQL schema\n", "2. **Analyzed** field types and nullability\n", "3. **Generated** JSON Schema validation\n", "4. **Created** individual tools with precise contracts\n", "\n", "No more guessing about:\n", "- Which fields are required\n", "- What types parameters should be\n", "- How to structure nested objects\n", "- What the tool actually does\n", "\n", "The inspector makes all this visible and testable in a user-friendly interface!" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "## ๐Ÿค– Chapter 4: Connecting to AI Clients (Claude/Cursor)\n", "\n", "Now that we've tested our GraphQL-to-MCP bridge, let's connect it to actual AI clients where the real magic happens.\n", "\n", "### The Transport Switch: HTTP โ†’ Stdio\n", "\n", "**Important**: AI clients like Claude and Cursor use **stdio transport**, not Streamable HTTP.\n", "\n", "- **HTTP Transport** = Use with real deployed AI applications / Inspector\n", "- **Stdio Transport** = For hyperlocal AI applications\n", "\n", "### Optional Step: Configure for Claude Desktop\n", "\n", "Create or edit your `claude_desktop_config.json` file:\n", "\n", "**Location**:\n", "- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`\n", "- **Windows**: `%APPDATA%\\Claude\\claude_desktop_config.json`\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "json" } }, "outputs": [], "source": [ "{\n", " \"mcpServers\": {\n", " \"mcp-graphql-forge\": {\n", " \"command\": \"npx\",\n", " \"args\": [\n", " \"-y\",\n", " \"@toolprint/mcp-graphql-forge\"\n", " ],\n", " \"env\": {\n", " \"GRAPHQL_ENDPOINT\": \"https://patient-song-383e3762d2.strapiapp.com/graphql\"\n", " }\n", " }\n", " }\n", "}\n" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "### Optional Step 2: Configure for Cursor\n", "\n", "Create or edit your `mcp.json` - Settings > Cursor Settings > Tools & Integrations > MCP Tools\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "json" } }, "outputs": [], "source": [ "{\n", " \"mcpServers\": {\n", " \"mcp-graphql-forge\": {\n", " \"command\": \"npx\",\n", " \"args\": [\n", " \"-y\", \n", " \"@toolprint/mcp-graphql-forge\"\n", " ],\n", " \"env\": {\n", " \"GRAPHQL_ENDPOINT\": \"https://patient-song-383e3762d2.strapiapp.com/graphql\"\n", " }\n", " }\n", " }\n", "}\n" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "### Step 3: Test the Integration\n", "\n", "#### For Claude Desktop:\n", "1. **Save the config file** and restart Claude Desktop\n", "2. **Look for the ๐Ÿ”Œ icon** in the Claude interface\n", "3. **Start a conversation**: \"What articles are available in the CMS?\"\n", "4. **Watch Claude use the tools** automatically!\n", "\n", "#### For Cursor:\n", "1. **Save the mcp.json file** in your project root\n", "2. Toggle the MCP server until the icon shows greens and shows tools (you may notice that it has tool overload!).\n", "3. **Ask about your CMS**: \"Show me the latest articles from the CMS\"\n", "4. **See Cursor query your GraphQL API** through the generated tools\n", "\n", "### ๐ŸŽฏ Test Prompts to Try\n", "\n", "#### Safe Exploration (Queries Only)\n", "- \"What content types are available in the CMS?\"\n", "- \"Show me the 5 most recent articles\"\n", "- \"List all categories and their article counts\"\n", "- \"Find articles containing 'tutorial' in the title\"\n", "\n", "#### Advanced Analysis \n", "- \"Analyze the content strategy - which categories have the most articles?\"\n", "- \"Create a summary of all article titles and their publication dates\"\n", "- \"What are the top authors by article count?\"\n", "\n", "### ๐Ÿ›ก๏ธ Safety Note\n", "\n", "Remember: The tools generated include both **queries** (safe) and **mutations** (potentially destructive). For production use, consider:\n", "- Starting with query-only mode\n", "- Adding authentication requirements\n", "- Implementing audit logging for mutations\n" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "## ๐Ÿค” Did Your AI Assistant Seem Lost?\n", "\n", "If you tried the examples above with Claude or Cursor, you might have noticed something interesting:\n", "- Did the AI seem to hallucinate tools that don't exist?\n", "- Did it struggle to find the right tool for your task?\n", "- Did it get overwhelmed by the number of available tools?\n", "\n", "**You're not alone!** This is a common challenge when exposing large GraphQL APIs as MCP tools.\n", "\n", "### The Tool Discovery Challenge\n", "\n", "Consider what happened when we connected to GitHub's GraphQL API:\n", "- 100+ generated tools\n", "- Complex nested parameters\n", "- Similar-sounding tool names\n", "- Tools that work better together\n", "\n", "Even for a sophisticated AI like Claude or Cursor, this creates a **cognitive overload**. The AI needs to:\n", "1. Search through a massive tool list\n", "2. Understand complex parameter requirements\n", "3. Figure out tool relationships\n", "4. Plan multi-step workflows\n", "\n", "### Enter Toolprint: Smart Tool Discovery\n", "\n", "This is exactly why we built [Toolprint](https://toolprint.ai) - to make large tool collections manageable through:\n", "\n", "#### 1. Semantic Tool Search\n", "Instead of having LLMs have an overflowing context of 100s of tools, they can search and find the BEST tools given their goals using\n", "the toolprint's tool_search functionality.\n", "```\n", "\"Find repository information\" โ†’ [github::query_repository, 9 more tools...]\n", "\"Create an issue on linear\" โ†’ [linear::create_issue, ...]\n", "```\n", "\n", "Using these tool references, the LLM can call toolprint to execute the chosen tools using a referential ID and the correct\n", "parameters given the shape of the tools offered by tool search.\n", "\n", "#### 2. Baking in relationships between tools & building real workflows!\n", "Toolprint also offers up the concept of a \"toolprint\" which is a workflow that can be crafted in plain English \n", "with tools across all your MCPs. Passing a toolprint to an LLM gives it clear instructions on how to execute\n", "a workflow without having to write a single line of code.\n", "\n", "The best part is that if you connect your IDE to the `toolprint mcp` server, it can author it all for you with the right references!\n", "\n", "```yaml\n", "# Example -\n", "\n", "goal: Track, analyze, and action changes in the MCP protocol repository by monitoring PRs, issues, and discussions, then creating linear tickets for required implementation work.\n", "\n", "instructions: |\n", " 1. Fetch recent activity from the MCP protocol repository:\n", " - Get merged PRs from the last 2 weeks\n", " - Get active issues with the 'spec' label\n", " - Get discussions tagged with 'protocol'\n", " \n", " 2. For each PR and issue:\n", " - Extract key comments and decisions\n", " - Note any breaking changes\n", " - Identify implementation requirements\n", " \n", " 3. Generate a summary report:\n", " - Group changes by protocol component\n", " - Highlight breaking changes\n", " - List pending decisions\n", " \n", " 4. For each implementation requirement:\n", " - Create a Linear ticket with appropriate context\n", " - Link back to source PR/issue\n", " - Tag with 'mcp-protocol-update'\n", " - Set priority based on breaking change status\n", "\n", "tools:\n", " - ref:\n", " name: github_list_prs\n", " usage_hints: |\n", " # Use to fetch recent PRs\n", " - Filter by merged status and date range\n", " - Sort by update date descending\n", " - Include labels and review status\n", " \n", " - ref:\n", " name: github_list_issues\n", " usage_hints: |\n", " # Use to fetch active issues\n", " - Filter by 'spec' label\n", " - Include comments and reactions\n", " - Sort by activity\n", " \n", " - ref:\n", " name: github_get_discussions\n", " usage_hints: |\n", " # Use to fetch relevant discussions\n", " - Filter by 'protocol' category\n", " - Include all comments\n", " - Sort by last activity\n", " \n", " - ref:\n", " name: linear_create_ticket\n", " usage_hints: |\n", " # Use to create implementation tickets\n", " - Set title with clear context\n", " - Include links to source PR/issue\n", " - Add 'mcp-protocol-update' label\n", " - Set priority field\n", " - Add implementation requirements to description\n", "```\n", "\n", "#### 3. Use the tool better next time\n", "Toolprint offers meta tools to have LLMs (or humans) reflect on how to use tools better beyond their meager descriptions!\n", "\n", "Have the AI reflect on tool use and add annotations on the tool itself so that the next time the AI needs to use the tool, it can use the annotations to understand the tool better.\n", "\n", "Ex. The Linear `list_issues` tool on its own does not instruct an LLM that it needs to provide a REAL project identifier so an LLM will hallucinate values. Solution: add a tool annotation: `ai_note: find the available teams using list_teams in order to populate the team value in this tool`\n", "\n", "\n", "### Getting Started with Toolprint\n", "\n", "1. **Install the Toolprint CLI**:\n", "```bash\n", "brew install toolprint/tap/toolprint\n", "```\n", "\n", "2. **Join our free sandbox to see how it all works across 8 MCPs and over 70 tools**:\n", "```bash\n", "toolprint\n", "```\n", "\n", "Visit [toolprint.ai](https://toolprint.ai) to learn more about making your GraphQL tools more discoverable and usable for AI agents!\n" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 2 }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/toolprint/mcp-graphql-forge'

If you have feedback or need assistance with the MCP directory API, please join our Discord server