Skip to content

feat: generate specific tools for operations #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added bun.lockb
Binary file not shown.
63 changes: 31 additions & 32 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
{
"name": "mcp-graphql",
"module": "index.ts",
"type": "module",
"version": "2.0.1",
"repository": "github:blurrah/mcp-graphql",
"license": "MIT",
"bin": {
"mcp-graphql": "./dist/index.js"
},
"files": [
"dist"
],
"devDependencies": {
"@graphql-tools/schema": "^10.0.21",
"@types/bun": "latest",
"@types/yargs": "17.0.33",
"graphql-yoga": "^5.13.1",
"typescript": "5.8.2"
},
"dependencies": {
"@modelcontextprotocol/sdk": "1.6.1",
"graphql": "^16.10.0",
"yargs": "17.7.2",
"zod": "3.24.2",
"zod-to-json-schema": "3.24.3"
},
"scripts": {
"dev": "bun --watch src/index.ts",
"build": "bun build src/index.ts --outdir dist --target node && bun -e \"require('fs').chmodSync('dist/index.js', '755')\"",
"start": "bun run dist/index.js"
},
"packageManager": "[email protected]"
"name": "mcp-graphql",
"module": "index.ts",
"type": "module",
"version": "2.0.1",
"repository": "github:blurrah/mcp-graphql",
"license": "MIT",
"bin": {
"mcp-graphql": "./dist/index.js"
},
"files": ["dist"],
"devDependencies": {
"@graphql-tools/schema": "^10.0.21",
"@types/bun": "latest",
"@types/yargs": "17.0.33",
"graphql-yoga": "^5.13.1",
"typescript": "5.8.2"
},
"dependencies": {
"@modelcontextprotocol/sdk": "1.6.1",
"graphql": "^16.10.0",
"yargs": "17.7.2",
"zod": "3.24.2",
"zod-to-json-schema": "3.24.3"
},
"scripts": {
"dev": "bun --watch src/index.ts",
"dev:new": "bun --watch src/server.ts",
"build": "bun build src/index.ts --outdir dist --target node && bun -e \"require('fs').chmodSync('dist/index.js', '755')\"",
"start": "bun run dist/index.js"
},
"packageManager": "[email protected]"
}
91 changes: 91 additions & 0 deletions schema-simple.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
schema {
query: Query
mutation: Mutation
}

type Query {
"""Get a user by ID"""
user(id: ID!): User

"""Get all users"""
users: [User!]!

"""Get a post by ID"""
post(id: ID!): Post

"""Get all posts"""
posts: [Post!]!

"""Get all comments for a post"""
commentsByPost(postId: ID!): [Comment!]!
}

type Mutation {
"""Create a new user"""
createUser(input: CreateUserInput!): User!

"""Update an existing user"""
updateUser(id: ID!, input: UpdateUserInput!): User!

"""Delete a user"""
deleteUser(id: ID!): Boolean!

"""Create a new post"""
createPost(input: CreatePostInput!): Post!

"""Add a comment to a post"""
addComment(input: AddCommentInput!): Comment!
}

type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
comments: [Comment!]!
createdAt: String!
updatedAt: String
}

type Post {
id: ID!
title: String!
content: String!
published: Boolean!
author: User!
comments: [Comment!]!
createdAt: String!
updatedAt: String
}

type Comment {
id: ID!
text: String!
post: Post!
author: User!
createdAt: String!
}

input CreateUserInput {
name: String!
email: String!
}

input UpdateUserInput {
name: String
email: String
}

input CreatePostInput {
title: String!
content: String!
published: Boolean
authorId: ID!
}

input AddCommentInput {
text: String!
postId: ID!
authorId: ID!
}

3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ server.tool(
},
);

/**
* Sets up the transport and starts the server with it
*/
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
Expand Down
69 changes: 69 additions & 0 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { z } from "zod";

export const configSchema = z.object({
name: z.string().default("mcp-graphql"),
// Endpoint for the schema to be introspected and transformed into tools
endpoint: z.string().url(),
// File path alternative to endpoint, will read the file instead of fetching the endpoint
schemaPath: z.string().optional(),
// Headers to be sent with the request to the schema endpoint
headers: z.record(z.string()).optional(),
// Allow MCP clients to use mutations, can potentially be dangerous so we disable by default
allowMutations: z.boolean().optional().default(false),
// Queries to exclude from the generated tools
excludeQueries: z.array(z.string()).optional().default([]),
// Mutations to exclude from the generated tools
excludeMutations: z.array(z.string()).optional().default([]),
});

export type Config = z.infer<typeof configSchema>;

export function parseArgumentsToConfig(): Config {
const argv = yargs(hideBin(process.argv))
.option("name", {
type: "string",
description:
"Name of the MCP server, can be used if you want to override the default name",
})
.option("endpoint", {
type: "string",
description:
"Endpoint for the schema to be introspected and transformed into tools",
})
.option("schemaPath", {
type: "string",
description:
"Alternative path for GraphQL schema file, use this if you cannot introspect the schema from the endpoint",
})
.option("headers", {
type: "string",
description:
"JSON stringified headers to be sent with the request to the schema endpoint",
default: "{}",
})
.option("allowMutations", {
type: "boolean",
description:
"Allow MCP clients to use mutations, can potentially be dangerous so we disable by default",
})
.option("excludeQueries", {
type: "array",
description: "Queries to exclude from the generated tools",
})
.option("excludeMutations", {
type: "array",
description: "Mutations to exclude from the generated tools",
})
.help()
.parseSync();

const parsedArgs = {
...argv,
headers: argv.headers ? JSON.parse(argv.headers) : undefined,
};

// Just let this throw, will catch it during main execution
return configSchema.parse(parsedArgs);
}
Loading