Skip to content

Commit 649dbc6

Browse files
authored
refactor!: remove per query endpoints and headers (#17)
This opens up the MCP server to lots of security issues by leaking headers and allowing endpoints and headers to be poisoned. If you need this specific use case of allowing different endpoints and headers per query/introspection then please fork the latest v1. Thanks @mweidner037 for notifying on this issue. BREAKING RELEASE: Endpoints and headers input options removed due to inherent security vulnerabilities
1 parent 363a645 commit 649dbc6

File tree

1 file changed

+10
-40
lines changed

1 file changed

+10
-40
lines changed

src/index.ts

Lines changed: 10 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
55
import { parse } from "graphql/language";
66
import { z } from "zod";
77
import { checkDeprecatedArguments } from "./helpers/deprecation.js";
8-
import { parseAndMergeHeaders } from "./helpers/headers.js";
98
import {
109
introspectEndpoint,
1110
introspectLocalSchema,
@@ -18,7 +17,10 @@ checkDeprecatedArguments();
1817
const EnvSchema = z.object({
1918
NAME: z.string().default("mcp-graphql"),
2019
ENDPOINT: z.string().url().default("http://localhost:4000/graphql"),
21-
ALLOW_MUTATIONS: z.enum(['true', 'false']).transform((value) => value === 'true').default("false"),
20+
ALLOW_MUTATIONS: z
21+
.enum(["true", "false"])
22+
.transform((value) => value === "true")
23+
.default("false"),
2224
HEADERS: z
2325
.string()
2426
.default("{}")
@@ -65,30 +67,14 @@ server.resource("graphql-schema", new URL(env.ENDPOINT).href, async (uri) => {
6567
server.tool(
6668
"introspect-schema",
6769
"Introspect the GraphQL schema, use this tool before doing a query to get the schema information if you do not have it available as a resource already.",
68-
{
69-
endpoint: z
70-
.string()
71-
.url()
72-
.optional()
73-
.describe(
74-
`Optional: Override the default endpoint, the already used endpoint is: ${env.ENDPOINT}`,
75-
),
76-
headers: z
77-
.union([z.record(z.string()), z.string()])
78-
.optional()
79-
.describe(
80-
`Optional: Add additional headers, the already used headers are: ${JSON.stringify(env.HEADERS)}`,
81-
),
82-
},
83-
async ({ endpoint, headers }) => {
70+
{},
71+
async () => {
8472
try {
8573
let schema: string;
8674
if (env.SCHEMA) {
8775
schema = await introspectLocalSchema(env.SCHEMA);
8876
} else {
89-
const useEndpoint = endpoint || env.ENDPOINT;
90-
const useHeaders = parseAndMergeHeaders(env.HEADERS, headers);
91-
schema = await introspectEndpoint(useEndpoint, useHeaders);
77+
schema = await introspectEndpoint(env.ENDPOINT, env.HEADERS);
9278
}
9379

9480
return {
@@ -111,21 +97,8 @@ server.tool(
11197
{
11298
query: z.string(),
11399
variables: z.string().optional(),
114-
endpoint: z
115-
.string()
116-
.url()
117-
.optional()
118-
.describe(
119-
`Optional: Override the default endpoint, the already used endpoint is: ${env.ENDPOINT}`,
120-
),
121-
headers: z
122-
.union([z.record(z.string()), z.string()])
123-
.optional()
124-
.describe(
125-
`Optional: Add additional headers, the already used headers are: ${JSON.stringify(env.HEADERS)}`,
126-
),
127100
},
128-
async ({ query, variables, endpoint, headers }) => {
101+
async ({ query, variables }) => {
129102
try {
130103
const parsedQuery = parse(query);
131104

@@ -159,14 +132,11 @@ server.tool(
159132
}
160133

161134
try {
162-
const useEndpoint = endpoint || env.ENDPOINT;
163-
const useHeaders = parseAndMergeHeaders(env.HEADERS, headers);
164-
165-
const response = await fetch(useEndpoint, {
135+
const response = await fetch(env.ENDPOINT, {
166136
method: "POST",
167137
headers: {
168138
"Content-Type": "application/json",
169-
...useHeaders,
139+
...env.HEADERS,
170140
},
171141
body: JSON.stringify({
172142
query,

0 commit comments

Comments
 (0)