@yashwant.dharmdas/elementor-mcp 3.2.0 → 3.2.1

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 +59 -38
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -993,29 +993,29 @@ function createMcpServer(sites) {
993
993
  }
994
994
  });
995
995
  // ── Group 9: Screenshot ──────────────────────────────────────────────────────
996
- server.tool("screenshot-page", "Take a full-page screenshot of a published WordPress page using the system-installed Google Chrome browser. Returns the screenshot as an image so you can visually review design, layout, and content. Requires the page to be publicly accessible (status: publish).", {
996
+ server.tool("screenshot-page", "Take a screenshot of a published WordPress page using system Chrome. Saves the file to disk and returns both a preview image and the saved file path. Pass the file_path to Basecamp MCP's upload_attachment tool to attach it — never relay the raw image data yourself.", {
997
997
  page_id: z.string().describe("WordPress Page ID"),
998
- full_page: z.boolean().optional().describe("Capture the full scrollable page height (default: true)"),
998
+ full_page: z.boolean().optional().describe("Capture full scrollable page (default: true)"),
999
999
  width: z.number().optional().describe("Viewport width in pixels (default: 1440)"),
1000
+ format: z.enum(["jpeg", "png"]).optional().describe("Image format — jpeg is much smaller and recommended (default: jpeg)"),
1001
+ quality: z.number().min(1).max(100).optional().describe("JPEG quality 1–100 (default: 82). Lower = smaller file size."),
1002
+ max_height: z.number().optional().describe("Cap the captured height in pixels (e.g. 4000). Useful for very long pages to stay under size limits."),
1000
1003
  site: siteParam,
1001
- }, async ({ page_id, full_page, width, site }) => {
1004
+ }, async ({ page_id, full_page, width, format, quality, max_height, site }) => {
1002
1005
  try {
1003
1006
  const { wpUrl, authHeader } = resolveSite(sites, site);
1004
- // ── 1. Resolve the page's public URL from WP REST API ──────────────
1007
+ // ── 1. Resolve the page's public URL ─────────────────────────────
1005
1008
  const pageRes = await axios.get(`${wpUrl}/wp-json/wp/v2/pages/${page_id}`, {
1006
1009
  headers: { Authorization: authHeader },
1007
1010
  });
1008
1011
  const pageUrl = pageRes.data.link;
1009
1012
  if (!pageUrl)
1010
1013
  throw new Error("Could not resolve public URL for this page.");
1011
- // ── 2. Detect system Chrome ──────────────────────────────────────
1014
+ // ── 2. Detect system Chrome ───────────────────────────────────────
1012
1015
  const chromePaths = [
1013
- // Windows
1014
1016
  "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
1015
1017
  "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
1016
- // macOS
1017
1018
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
1018
- // Linux
1019
1019
  "/usr/bin/google-chrome",
1020
1020
  "/usr/bin/google-chrome-stable",
1021
1021
  "/usr/bin/chromium-browser",
@@ -1029,51 +1029,72 @@ function createMcpServer(sites) {
1029
1029
  }
1030
1030
  }
1031
1031
  if (!executablePath) {
1032
- throw new Error("Google Chrome not found on this machine.\n" +
1033
- "Install Chrome from https://www.google.com/chrome/ and ensure it is in a standard location.\n" +
1034
- "Checked paths:\n" + chromePaths.map(p => ` • ${p}`).join("\n"));
1032
+ throw new Error("Google Chrome not found. Install it from https://www.google.com/chrome/\n" +
1033
+ "Checked:\n" + chromePaths.map(p => ` • ${p}`).join("\n"));
1035
1034
  }
1036
- // ── 3. Launch puppeteer-core with system Chrome ─────────────────
1035
+ // ── 3. Ensure screenshots directory exists ───────────────────────
1036
+ const screenshotsDir = path.join(CONFIG_DIR, "screenshots");
1037
+ if (!fs.existsSync(screenshotsDir))
1038
+ fs.mkdirSync(screenshotsDir, { recursive: true });
1039
+ // ── 4. Launch puppeteer-core ──────────────────────────────────────
1037
1040
  let puppeteer;
1038
1041
  try {
1039
1042
  puppeteer = await import("puppeteer-core");
1040
1043
  }
1041
1044
  catch {
1042
- throw new Error("puppeteer-core is not installed. Run: npm install puppeteer-core\n" +
1043
- "(or reinstall @yashwant.dharmdas/elementor-mcp — it is bundled as a dependency)");
1045
+ throw new Error("puppeteer-core is not installed. Reinstall @yashwant.dharmdas/elementor-mcp to get it.");
1044
1046
  }
1045
1047
  const browser = await puppeteer.launch({
1046
1048
  executablePath,
1047
1049
  headless: true,
1048
- args: [
1049
- "--no-sandbox",
1050
- "--disable-setuid-sandbox",
1051
- "--disable-dev-shm-usage",
1052
- "--disable-gpu",
1053
- ],
1050
+ args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage", "--disable-gpu"],
1054
1051
  });
1055
1052
  try {
1056
1053
  const page = await browser.newPage();
1057
- await page.setViewport({ width: width ?? 1440, height: 900, deviceScaleFactor: 1 });
1054
+ const vpWidth = width ?? 1440;
1055
+ const vpHeight = max_height ?? 900;
1056
+ await page.setViewport({ width: vpWidth, height: vpHeight, deviceScaleFactor: 1 });
1058
1057
  await page.goto(pageUrl, { waitUntil: "networkidle2", timeout: 30_000 });
1059
- // Small pause to let JS-heavy pages finish rendering
1060
1058
  await new Promise(resolve => setTimeout(resolve, 1000));
1061
- const screenshotBuffer = await page.screenshot({
1062
- fullPage: full_page ?? true,
1063
- type: "png",
1064
- });
1065
- const base64 = Buffer.isBuffer(screenshotBuffer)
1066
- ? screenshotBuffer.toString("base64")
1067
- : Buffer.from(screenshotBuffer).toString("base64");
1068
- return {
1069
- content: [
1070
- {
1071
- type: "image",
1072
- data: base64,
1073
- mimeType: "image/png",
1074
- },
1075
- ],
1076
- };
1059
+ const fmt = format ?? "jpeg";
1060
+ const screenshotOptions = { type: fmt, fullPage: !max_height && (full_page ?? true) };
1061
+ if (fmt === "jpeg")
1062
+ screenshotOptions.quality = quality ?? 82;
1063
+ if (max_height)
1064
+ screenshotOptions.clip = { x: 0, y: 0, width: vpWidth, height: vpHeight };
1065
+ const screenshotBuffer = await page.screenshot(screenshotOptions);
1066
+ const buf = Buffer.isBuffer(screenshotBuffer) ? screenshotBuffer : Buffer.from(screenshotBuffer);
1067
+ // ── 5. Save to disk ─────────────────────────────────────────────
1068
+ const ext = fmt === "jpeg" ? "jpg" : "png";
1069
+ const filename = `page_${page_id}_${Date.now()}.${ext}`;
1070
+ const filePath = path.join(screenshotsDir, filename);
1071
+ fs.writeFileSync(filePath, buf);
1072
+ const sizeKB = Math.round(buf.length / 1024);
1073
+ const mimeType = `image/${fmt}`;
1074
+ // ── 6. Return image preview if small enough, always return path ─
1075
+ const PREVIEW_LIMIT = 750 * 1024; // 750 KB raw → ~1 MB base64
1076
+ const content = [
1077
+ {
1078
+ type: "text",
1079
+ text: [
1080
+ `✅ Screenshot saved successfully.`,
1081
+ `📁 file_path: ${filePath}`,
1082
+ `📐 Size: ${sizeKB} KB | Format: ${ext.toUpperCase()} | URL: ${pageUrl}`,
1083
+ ``,
1084
+ `👉 To upload to Basecamp, call upload_attachment with:`,
1085
+ ` file_path = "${filePath}"`,
1086
+ ` project_id = <your Basecamp project ID>`,
1087
+ ].join("\n"),
1088
+ },
1089
+ ];
1090
+ if (buf.length <= PREVIEW_LIMIT) {
1091
+ content.unshift({
1092
+ type: "image",
1093
+ data: buf.toString("base64"),
1094
+ mimeType,
1095
+ });
1096
+ }
1097
+ return { content };
1077
1098
  }
1078
1099
  finally {
1079
1100
  await browser.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yashwant.dharmdas/elementor-mcp",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "MCP server for controlling Elementor via Claude — supports multiple WordPress sites",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",