@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.
- package/dist/index.js +59 -38
- 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
|
|
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
|
|
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
|
|
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
|
|
1033
|
-
"
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
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