@yashwant.dharmdas/elementor-mcp 3.18.0 → 3.18.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.
Files changed (2) hide show
  1. package/dist/index.js +63 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
6
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
7
7
  import { createServer } from "node:http";
8
+ import { randomUUID } from "node:crypto";
8
9
  import { z } from "zod";
9
10
  import axios from "axios";
10
11
  import fs from "fs";
@@ -4107,19 +4108,39 @@ else {
4107
4108
  console.error("No sites configured. Run first: npx elementor-mcp setup");
4108
4109
  process.exit(1);
4109
4110
  }
4110
- const useStdio = process.argv.includes("--stdio");
4111
- if (useStdio) {
4112
- // ── Stdio mode for Claude Desktop ──────────────────────────────────
4111
+ // Auto-detect transport:
4112
+ // • No TTY (spawned by Claude Desktop via pipe) → stdio, unless --http forces HTTP
4113
+ // TTY present (user ran manually in terminal) → HTTP, unless --stdio forces stdio
4114
+ const forceStdio = process.argv.includes("--stdio");
4115
+ const forceHttp = process.argv.includes("--http");
4116
+ const hasTTY = Boolean(process.stdin.isTTY);
4117
+ const useHttp = forceHttp || (!forceStdio && hasTTY);
4118
+ if (!useHttp) {
4119
+ // ── Stdio mode — for Claude Desktop (or --stdio flag) ────────────────
4113
4120
  const server = createMcpServer(sites);
4114
4121
  const transport = new StdioServerTransport();
4115
4122
  await server.connect(transport);
4116
4123
  }
4117
4124
  else {
4118
- // ── HTTP mode (default) — for browser-based MCP testers ──────────────
4125
+ // ── HTTP mode — for browser-based MCP testers (or --http flag) ───────
4119
4126
  const port = parseInt(process.env.PORT ?? "3001");
4120
- const mcpServer = createMcpServer(sites);
4121
- const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
4122
- await mcpServer.connect(transport);
4127
+ // Session map: sessionId → transport (one MCP server instance per browser session)
4128
+ const sessions = new Map();
4129
+ async function readBody(req) {
4130
+ return new Promise((resolve, reject) => {
4131
+ const chunks = [];
4132
+ req.on("data", (c) => chunks.push(c));
4133
+ req.on("end", () => {
4134
+ try {
4135
+ resolve(JSON.parse(Buffer.concat(chunks).toString()));
4136
+ }
4137
+ catch {
4138
+ resolve(undefined);
4139
+ }
4140
+ });
4141
+ req.on("error", reject);
4142
+ });
4143
+ }
4123
4144
  const httpServer = createServer(async (req, res) => {
4124
4145
  // CORS — allow browser clients and Chrome Private Network Access
4125
4146
  res.setHeader("Access-Control-Allow-Origin", "*");
@@ -4137,20 +4158,44 @@ else {
4137
4158
  return;
4138
4159
  }
4139
4160
  if (req.url === "/mcp") {
4140
- let body;
4141
- if (req.method === "POST") {
4142
- const chunks = [];
4143
- await new Promise((resolve, reject) => {
4144
- req.on("data", (c) => chunks.push(c));
4145
- req.on("end", resolve);
4146
- req.on("error", reject);
4161
+ const sessionId = req.headers["mcp-session-id"];
4162
+ let transport;
4163
+ if (sessionId && sessions.has(sessionId)) {
4164
+ // Resume existing session
4165
+ transport = sessions.get(sessionId);
4166
+ }
4167
+ else if (!sessionId) {
4168
+ // New session — create a fresh server + transport pair
4169
+ transport = new StreamableHTTPServerTransport({
4170
+ sessionIdGenerator: () => randomUUID(),
4147
4171
  });
4148
- try {
4149
- body = JSON.parse(Buffer.concat(chunks).toString());
4172
+ const mcpServer = createMcpServer(sites);
4173
+ await mcpServer.connect(transport);
4174
+ transport.onclose = () => {
4175
+ if (transport.sessionId)
4176
+ sessions.delete(transport.sessionId);
4177
+ };
4178
+ }
4179
+ else {
4180
+ // Unknown session ID
4181
+ res.writeHead(404, { "Content-Type": "application/json" });
4182
+ res.end(JSON.stringify({ error: "Session not found" }));
4183
+ return;
4184
+ }
4185
+ const body = req.method === "POST" ? await readBody(req) : undefined;
4186
+ try {
4187
+ await transport.handleRequest(req, res, body);
4188
+ }
4189
+ catch (err) {
4190
+ if (!res.headersSent) {
4191
+ res.writeHead(500, { "Content-Type": "application/json" });
4192
+ res.end(JSON.stringify({ error: String(err) }));
4150
4193
  }
4151
- catch { /* non-JSON body */ }
4152
4194
  }
4153
- await transport.handleRequest(req, res, body);
4195
+ // Store the session after initialize sets the ID
4196
+ if (!sessionId && transport.sessionId && !sessions.has(transport.sessionId)) {
4197
+ sessions.set(transport.sessionId, transport);
4198
+ }
4154
4199
  return;
4155
4200
  }
4156
4201
  res.writeHead(404);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yashwant.dharmdas/elementor-mcp",
3
- "version": "3.18.0",
3
+ "version": "3.18.2",
4
4
  "description": "MCP server for controlling Elementor via Claude — supports multiple WordPress sites",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",