@letoribo/mcp-graphql-enhanced 3.9.1 → 3.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +91 -52
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10,7 +10,6 @@ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
|
10
10
|
const language_1 = require("graphql/language");
|
|
11
11
|
const zod_1 = __importDefault(require("zod"));
|
|
12
12
|
const graphiql_js_1 = require("./helpers/graphiql.js");
|
|
13
|
-
const graphql_1 = require("graphql");
|
|
14
13
|
// Helper imports
|
|
15
14
|
const deprecation_js_1 = require("./helpers/deprecation.js");
|
|
16
15
|
const introspection_js_1 = require("./helpers/introspection.js");
|
|
@@ -25,7 +24,7 @@ const getVersion = () => {
|
|
|
25
24
|
return pkg.version;
|
|
26
25
|
}
|
|
27
26
|
catch {
|
|
28
|
-
return "3.9.
|
|
27
|
+
return "3.9.2";
|
|
29
28
|
}
|
|
30
29
|
};
|
|
31
30
|
(0, deprecation_js_1.checkDeprecatedArguments)();
|
|
@@ -128,62 +127,76 @@ async function performUpdate(force) {
|
|
|
128
127
|
isUpdating = true;
|
|
129
128
|
const startTime = Date.now();
|
|
130
129
|
try {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
schema._originUrl = url;
|
|
147
|
-
return { url, schema };
|
|
148
|
-
}));
|
|
149
|
-
const successful = results
|
|
150
|
-
.filter((r) => r.status === 'fulfilled')
|
|
151
|
-
.map(r => r.value);
|
|
152
|
-
const failures = results
|
|
153
|
-
.filter((r) => r.status === 'rejected')
|
|
154
|
-
.map(r => r.reason.message);
|
|
155
|
-
if (successful.length === 0) {
|
|
156
|
-
throw new Error(`Federation failed. All nodes unreachable: ${failures.join(', ')}`);
|
|
130
|
+
const { buildClientSchema, getIntrospectionQuery, printSchema, buildASTSchema, parse: gqlParse, isObjectType } = require("graphql");
|
|
131
|
+
let tempSchemas = [];
|
|
132
|
+
// --- FETCHING LOGIC: LOCAL SDL OR REMOTE BROADCAST ---
|
|
133
|
+
if (env.SCHEMA) {
|
|
134
|
+
let sdl;
|
|
135
|
+
if (env.SCHEMA.startsWith("http")) {
|
|
136
|
+
const response = await fetch(env.SCHEMA);
|
|
137
|
+
if (!response.ok)
|
|
138
|
+
throw new Error(`Remote_SDL_Fetch_Failed: ${response.statusText}`);
|
|
139
|
+
sdl = await response.text();
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
sdl = await (0, introspection_js_1.introspectLocalSchema)(env.SCHEMA);
|
|
143
|
+
}
|
|
144
|
+
tempSchemas = [buildASTSchema(gqlParse(sdl))];
|
|
157
145
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
146
|
+
else {
|
|
147
|
+
const endpoints = env.ENDPOINT.split(',').map(url => url.trim());
|
|
148
|
+
const results = await Promise.all(endpoints.map(async (url) => {
|
|
149
|
+
try {
|
|
150
|
+
const response = await fetch(url, {
|
|
151
|
+
method: "POST",
|
|
152
|
+
headers: { "Content-Type": "application/json", ...env.HEADERS },
|
|
153
|
+
body: JSON.stringify({ query: getIntrospectionQuery() }),
|
|
154
|
+
});
|
|
155
|
+
if (!response.ok)
|
|
156
|
+
return null;
|
|
157
|
+
const result = await response.json();
|
|
158
|
+
return result.data ? buildClientSchema(result.data) : null;
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
console.error(`[SYNC-WARN] Failed to reach ${url}`);
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}));
|
|
165
|
+
tempSchemas = results.filter((s) => s !== null);
|
|
166
|
+
}
|
|
167
|
+
if (tempSchemas.length === 0) {
|
|
168
|
+
throw new Error("No valid schemas could be retrieved.");
|
|
169
|
+
}
|
|
170
|
+
// Use the primary schema for the UI/Metadata context
|
|
171
|
+
cachedSchemaObject = tempSchemas[0];
|
|
172
|
+
const currentSDL = printSchema(cachedSchemaObject);
|
|
173
|
+
const typeMap = cachedSchemaObject.getTypeMap();
|
|
174
|
+
const businessTypes = Object.keys(typeMap).filter(typeName => {
|
|
175
|
+
const type = typeMap[typeName];
|
|
176
|
+
return !typeName.startsWith('__') &&
|
|
177
|
+
!['Query', 'Mutation', 'Subscription'].includes(typeName) &&
|
|
178
|
+
isObjectType(type);
|
|
174
179
|
});
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
180
|
+
if (currentSDL !== cachedSDL) {
|
|
181
|
+
cachedSDL = currentSDL;
|
|
182
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
183
|
+
const sourceInfo = env.SCHEMA ? 'SDL File' : `${tempSchemas.length} Active Nodes`;
|
|
184
|
+
return [
|
|
185
|
+
`✨ SCHEMA EVOLVED (${duration}s)`,
|
|
186
|
+
`📊 Source: ${sourceInfo}`,
|
|
187
|
+
`🧬 Types: ${businessTypes.length}`,
|
|
188
|
+
`---`,
|
|
189
|
+
`The bridge has updated the graph model.`
|
|
190
|
+
].join('\n');
|
|
191
|
+
}
|
|
192
|
+
return `✅ Status: Schema stable (${businessTypes.length} types).`;
|
|
178
193
|
}
|
|
179
194
|
catch (error) {
|
|
180
195
|
console.error(`[CRITICAL] Sync failure: ${error.message}`);
|
|
181
|
-
|
|
182
|
-
return `❌ SYNC ERROR: ${error.message}`;
|
|
196
|
+
throw error;
|
|
183
197
|
}
|
|
184
198
|
finally {
|
|
185
199
|
isUpdating = false;
|
|
186
|
-
updatePromise = null;
|
|
187
200
|
}
|
|
188
201
|
}
|
|
189
202
|
// --- TOOLS IMPLEMENTATION ---
|
|
@@ -337,23 +350,45 @@ async function handleHttpRequest(req, res) {
|
|
|
337
350
|
return;
|
|
338
351
|
}
|
|
339
352
|
const url = new URL(req.url || '', `http://${req.headers.host}`);
|
|
353
|
+
// Render GraphiQL UI
|
|
340
354
|
if (req.method === 'GET' && (url.pathname === '/' || url.pathname === '/graphiql')) {
|
|
341
355
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
342
356
|
return res.end((0, graphiql_js_1.renderGraphiQL)(`http://localhost:${env.MCP_PORT}/mcp`, env.HEADERS));
|
|
343
357
|
}
|
|
358
|
+
// Process MCP/GraphQL requests
|
|
344
359
|
if (url.pathname === '/mcp' && req.method === 'POST') {
|
|
345
360
|
let body = '';
|
|
346
361
|
req.on('data', chunk => { body += chunk; });
|
|
347
362
|
req.on('end', async () => {
|
|
363
|
+
let requestId = null;
|
|
348
364
|
try {
|
|
349
365
|
const payload = JSON.parse(body);
|
|
366
|
+
// Handle raw GraphQL queries sent directly to /mcp without JSON-RPC structure
|
|
367
|
+
if (!payload.method && payload.query) {
|
|
368
|
+
const handler = toolHandlers.get("query-graphql");
|
|
369
|
+
if (handler) {
|
|
370
|
+
const mcpResult = await handler({
|
|
371
|
+
query: payload.query,
|
|
372
|
+
variables: payload.variables
|
|
373
|
+
});
|
|
374
|
+
const parsed = JSON.parse(mcpResult.content[0].text);
|
|
375
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
376
|
+
const graphQLResponse = parsed.data ? parsed : { data: parsed };
|
|
377
|
+
return res.end(JSON.stringify(graphQLResponse));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
350
380
|
const { method, id, params } = payload;
|
|
381
|
+
requestId = id;
|
|
351
382
|
const target = (method === "call-tool" || method === "tools/call") ? params.name : method;
|
|
352
383
|
const args = (method === "call-tool" || method === "tools/call") ? params.arguments : params;
|
|
353
384
|
const handler = toolHandlers.get(target);
|
|
354
385
|
if (!handler) {
|
|
355
386
|
res.writeHead(404);
|
|
356
|
-
return res.end(JSON.stringify({
|
|
387
|
+
return res.end(JSON.stringify({
|
|
388
|
+
jsonrpc: '2.0',
|
|
389
|
+
id: requestId,
|
|
390
|
+
error: { code: -32601, message: `Method ${target} not found` }
|
|
391
|
+
}));
|
|
357
392
|
}
|
|
358
393
|
const result = await handler(args);
|
|
359
394
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -361,7 +396,11 @@ async function handleHttpRequest(req, res) {
|
|
|
361
396
|
}
|
|
362
397
|
catch (e) {
|
|
363
398
|
res.writeHead(500);
|
|
364
|
-
res.end(JSON.stringify({
|
|
399
|
+
res.end(JSON.stringify({
|
|
400
|
+
jsonrpc: '2.0',
|
|
401
|
+
id: requestId,
|
|
402
|
+
error: { message: e.message }
|
|
403
|
+
}));
|
|
365
404
|
}
|
|
366
405
|
});
|
|
367
406
|
return;
|
package/package.json
CHANGED