@letoribo/mcp-graphql-enhanced 2.2.2 → 2.3.0
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/README.md +11 -3
- package/dist/index.js +50 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,16 +24,24 @@ This allows external systems, web applications, and direct `curl` commands to ac
|
|
|
24
24
|
| `/mcp` | `POST` | The main JSON-RPC endpoint for tool execution. |
|
|
25
25
|
| `/health` | `GET` | Simple health check, returns `{ status: 'ok' }`. |
|
|
26
26
|
|
|
27
|
+
### Resolving Port Conflicts (EADDRINUSE) and Automatic Port Selection
|
|
28
|
+
|
|
29
|
+
The server defaults to port `6274`. If you encounter an `EADDRINUSE: address already in use :::6274` error (common in local development due to stale processes), the server will automatically **increment the port and retry** (e.g., bind to `6275`, then `6276`, etc., up to 5 times).
|
|
30
|
+
|
|
31
|
+
This ensures the server starts successfully even when the default is blocked. **Always check the server logs for the final bound port** (e.g., `[HTTP] Started server on http://localhost:6275`) if your `curl` or client tool fails on the default `6274`.
|
|
32
|
+
|
|
33
|
+
To **force a specific port** (e.g., for guaranteed external firewall settings), you can still explicitly set the `MCP_PORT` environment variable:
|
|
34
|
+
|
|
27
35
|
### Testing the HTTP Endpoint
|
|
28
36
|
|
|
29
37
|
You can test the endpoint using `curl` as long as the server is running (e.g., via `npm run dev`):
|
|
30
38
|
|
|
31
39
|
```bash
|
|
32
|
-
# Test the health check
|
|
40
|
+
# Test the health check (assuming the server bound to the default or found the next available port)
|
|
33
41
|
curl http://localhost:6274/health
|
|
34
42
|
|
|
35
|
-
# Test the query tool via JSON-RPC
|
|
36
|
-
curl -X POST http://localhost:
|
|
43
|
+
# Example: Test the query tool via JSON-RPC (using port 6275 if 6274 was busy)
|
|
44
|
+
curl -X POST http://localhost:6275/mcp -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"query-graphql","params":{"query":"query { __typename }"},"id":1}'
|
|
37
45
|
|
|
38
46
|
## 🔍 Filtered Introspection (New!)
|
|
39
47
|
Avoid 50k-line schema dumps. Ask for only what you need:
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
3
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
const
|
|
7
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
5
8
|
const { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
6
9
|
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
7
10
|
const { parse } = require("graphql/language");
|
|
8
11
|
const z = require("zod").default;
|
|
9
|
-
const { checkDeprecatedArguments } = require("./helpers/deprecation");
|
|
10
|
-
const { introspectEndpoint, introspectLocalSchema, introspectSchemaFromUrl, introspectTypes, } = require("./helpers/introspection");
|
|
12
|
+
const { checkDeprecatedArguments } = require("./helpers/deprecation.js");
|
|
13
|
+
const { introspectEndpoint, introspectLocalSchema, introspectSchemaFromUrl, introspectTypes, } = require("./helpers/introspection.js");
|
|
11
14
|
const getVersion = () => {
|
|
12
15
|
const pkg = require("../package.json");
|
|
13
16
|
return pkg.version;
|
|
@@ -299,10 +302,51 @@ async function handleHttpRequest(req, res) {
|
|
|
299
302
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
300
303
|
res.end('Not Found. Use POST /mcp for JSON-RPC or GET /health.');
|
|
301
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Tries to listen on a given port, automatically retrying on the next port if EADDRINUSE occurs.
|
|
307
|
+
* @param server - The HTTP server instance.
|
|
308
|
+
* @param port - The port to attempt binding to.
|
|
309
|
+
* @param maxRetries - Maximum number of retries.
|
|
310
|
+
* @param attempt - Current attempt number.
|
|
311
|
+
* @returns Resolves with the bound server instance.
|
|
312
|
+
*/
|
|
313
|
+
function tryListen(server, port, maxRetries = 5, attempt = 0) {
|
|
314
|
+
return new Promise((resolve, reject) => {
|
|
315
|
+
if (attempt >= maxRetries) {
|
|
316
|
+
reject(new Error(`Failed to bind HTTP server after ${maxRetries} attempts, starting from port ${env.MCP_PORT}.`));
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (port > 65535) {
|
|
320
|
+
reject(new Error(`Exceeded maximum port number (65535) during retry.`));
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const errorHandler = (err) => {
|
|
324
|
+
server.removeListener('error', errorHandler); // Remove listener to prevent memory leak
|
|
325
|
+
if (err.code === 'EADDRINUSE') {
|
|
326
|
+
const nextPort = port + 1;
|
|
327
|
+
// Use console.error so it appears in the Inspector log
|
|
328
|
+
console.error(`[HTTP] Port ${port} is in use (EADDRINUSE). Retrying on ${nextPort}...`);
|
|
329
|
+
server.close(() => {
|
|
330
|
+
// Recursively call tryListen with the next port
|
|
331
|
+
resolve(tryListen(server, nextPort, maxRetries, attempt + 1));
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
reject(err);
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
server.on('error', errorHandler);
|
|
339
|
+
server.listen(port, () => {
|
|
340
|
+
server.removeListener('error', errorHandler); // success, remove the error listener
|
|
341
|
+
console.error(`[HTTP] Started server on http://localhost:${port}. Listening for POST /mcp requests.`);
|
|
342
|
+
resolve(server);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
}
|
|
302
346
|
function startHttpTransport() {
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
console.error(`[HTTP]
|
|
347
|
+
const serverInstance = node_http_1.default.createServer(handleHttpRequest);
|
|
348
|
+
tryListen(serverInstance, env.MCP_PORT).catch((error) => {
|
|
349
|
+
console.error(`[HTTP] Failed to start HTTP transport: ${error.message}`);
|
|
306
350
|
});
|
|
307
351
|
}
|
|
308
352
|
async function main() {
|
package/package.json
CHANGED