@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.
Files changed (3) hide show
  1. package/README.md +11 -3
  2. package/dist/index.js +50 -6
  3. 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:6274/mcp -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"query-graphql","params":{"query":"query { __typename }"},"id":1}'
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 http = require("node:http");
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 server = http.createServer(handleHttpRequest);
304
- server.listen(env.MCP_PORT, () => {
305
- console.error(`[HTTP] Started server on http://localhost:${env.MCP_PORT}. Listening for POST /mcp requests.`);
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
@@ -50,5 +50,5 @@
50
50
  "ts-node": "^10.9.2",
51
51
  "typescript": "5.8.3"
52
52
  },
53
- "version": "2.2.2"
53
+ "version": "2.3.0"
54
54
  }