@yashwant.dharmdas/elementor-mcp 3.2.1 → 3.2.3
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 +83 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -993,24 +993,58 @@ function createMcpServer(sites) {
|
|
|
993
993
|
}
|
|
994
994
|
});
|
|
995
995
|
// ── Group 9: Screenshot ──────────────────────────────────────────────────────
|
|
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
|
|
997
|
-
page_id: z.string().describe("WordPress
|
|
996
|
+
server.tool("screenshot-page", "Take a screenshot of a published WordPress page using system Chrome. Works with any post type (page, post, custom post types like astra-portfolio). Pass either page_id OR a direct url. 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.", {
|
|
997
|
+
page_id: z.string().optional().describe("WordPress post/page ID (works for any post type). Either page_id OR url must be provided."),
|
|
998
|
+
url: z.string().optional().describe("Direct URL to screenshot (e.g. https://site.com/services/xyz/). Use this for custom post types or external URLs. Takes precedence over page_id."),
|
|
998
999
|
full_page: z.boolean().optional().describe("Capture full scrollable page (default: true)"),
|
|
999
1000
|
width: z.number().optional().describe("Viewport width in pixels (default: 1440)"),
|
|
1000
1001
|
format: z.enum(["jpeg", "png"]).optional().describe("Image format — jpeg is much smaller and recommended (default: jpeg)"),
|
|
1001
1002
|
quality: z.number().min(1).max(100).optional().describe("JPEG quality 1–100 (default: 82). Lower = smaller file size."),
|
|
1002
1003
|
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."),
|
|
1004
|
+
wait: z.number().optional().describe("Extra milliseconds to wait after page load + auto-scroll before capturing (default: 2000). Increase for heavy animations/videos."),
|
|
1005
|
+
auto_scroll: z.boolean().optional().describe("Scroll through the page to trigger lazy-loaded images and content (default: true). Disable only for pages with infinite scroll."),
|
|
1003
1006
|
site: siteParam,
|
|
1004
|
-
}, async ({ page_id, full_page, width, format, quality, max_height, site }) => {
|
|
1007
|
+
}, async ({ page_id, url, full_page, width, format, quality, max_height, wait, auto_scroll, site }) => {
|
|
1005
1008
|
try {
|
|
1009
|
+
if (!page_id && !url) {
|
|
1010
|
+
throw new Error("Provide either page_id or url.");
|
|
1011
|
+
}
|
|
1006
1012
|
const { wpUrl, authHeader } = resolveSite(sites, site);
|
|
1007
|
-
// ── 1. Resolve the
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1013
|
+
// ── 1. Resolve the target URL ────────────────────────────────────
|
|
1014
|
+
let pageUrl;
|
|
1015
|
+
if (url) {
|
|
1016
|
+
pageUrl = url;
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
// Try /pages/ first (most common), then fall back to universal search
|
|
1020
|
+
// (search endpoint works for ANY post type: page, post, astra-portfolio, etc.)
|
|
1021
|
+
try {
|
|
1022
|
+
const r = await axios.get(`${wpUrl}/wp-json/wp/v2/pages/${page_id}`, {
|
|
1023
|
+
headers: { Authorization: authHeader },
|
|
1024
|
+
});
|
|
1025
|
+
pageUrl = r.data.link;
|
|
1026
|
+
}
|
|
1027
|
+
catch (e) {
|
|
1028
|
+
if (e.response?.status === 404) {
|
|
1029
|
+
// Fallback: universal search endpoint — supports all post types
|
|
1030
|
+
const s = await axios.get(`${wpUrl}/wp-json/wp/v2/search`, {
|
|
1031
|
+
params: { include: page_id },
|
|
1032
|
+
headers: { Authorization: authHeader },
|
|
1033
|
+
});
|
|
1034
|
+
if (!Array.isArray(s.data) || s.data.length === 0 || !s.data[0].url) {
|
|
1035
|
+
throw new Error(`Could not resolve URL for post ID ${page_id}. ` +
|
|
1036
|
+
`Tried /wp/v2/pages/${page_id} (404) and /wp/v2/search?include=${page_id} (no results). ` +
|
|
1037
|
+
`Pass the 'url' parameter directly instead.`);
|
|
1038
|
+
}
|
|
1039
|
+
pageUrl = s.data[0].url;
|
|
1040
|
+
}
|
|
1041
|
+
else {
|
|
1042
|
+
throw e;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1012
1046
|
if (!pageUrl)
|
|
1013
|
-
throw new Error("Could not resolve
|
|
1047
|
+
throw new Error("Could not resolve URL.");
|
|
1014
1048
|
// ── 2. Detect system Chrome ───────────────────────────────────────
|
|
1015
1049
|
const chromePaths = [
|
|
1016
1050
|
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
@@ -1054,8 +1088,44 @@ function createMcpServer(sites) {
|
|
|
1054
1088
|
const vpWidth = width ?? 1440;
|
|
1055
1089
|
const vpHeight = max_height ?? 900;
|
|
1056
1090
|
await page.setViewport({ width: vpWidth, height: vpHeight, deviceScaleFactor: 1 });
|
|
1057
|
-
|
|
1058
|
-
await
|
|
1091
|
+
// Navigate and wait for network to go idle
|
|
1092
|
+
await page.goto(pageUrl, { waitUntil: "networkidle2", timeout: 45_000 });
|
|
1093
|
+
// ── Auto-scroll: trigger lazy-loaded images/content ─────────────
|
|
1094
|
+
if (auto_scroll !== false) {
|
|
1095
|
+
await page.evaluate(async () => {
|
|
1096
|
+
await new Promise((resolve) => {
|
|
1097
|
+
let totalHeight = 0;
|
|
1098
|
+
const distance = 200;
|
|
1099
|
+
const timer = setInterval(() => {
|
|
1100
|
+
const scrollHeight = document.body.scrollHeight;
|
|
1101
|
+
window.scrollBy(0, distance);
|
|
1102
|
+
totalHeight += distance;
|
|
1103
|
+
if (totalHeight >= scrollHeight) {
|
|
1104
|
+
clearInterval(timer);
|
|
1105
|
+
resolve();
|
|
1106
|
+
}
|
|
1107
|
+
}, 80);
|
|
1108
|
+
});
|
|
1109
|
+
});
|
|
1110
|
+
// Scroll back to top for the capture
|
|
1111
|
+
await page.evaluate(() => window.scrollTo(0, 0));
|
|
1112
|
+
}
|
|
1113
|
+
// ── Wait for all <img> tags to finish loading ──────────────────
|
|
1114
|
+
await page.evaluate(async () => {
|
|
1115
|
+
const images = Array.from(document.querySelectorAll("img"));
|
|
1116
|
+
await Promise.all(images.map((img) => {
|
|
1117
|
+
if (img.complete && img.naturalWidth > 0)
|
|
1118
|
+
return Promise.resolve();
|
|
1119
|
+
return new Promise((resolve) => {
|
|
1120
|
+
img.addEventListener("load", () => resolve(), { once: true });
|
|
1121
|
+
img.addEventListener("error", () => resolve(), { once: true });
|
|
1122
|
+
// Safety timeout per image
|
|
1123
|
+
setTimeout(() => resolve(), 5000);
|
|
1124
|
+
});
|
|
1125
|
+
}));
|
|
1126
|
+
});
|
|
1127
|
+
// Extra settle time for fonts, animations, videos
|
|
1128
|
+
await new Promise(resolve => setTimeout(resolve, wait ?? 2000));
|
|
1059
1129
|
const fmt = format ?? "jpeg";
|
|
1060
1130
|
const screenshotOptions = { type: fmt, fullPage: !max_height && (full_page ?? true) };
|
|
1061
1131
|
if (fmt === "jpeg")
|
|
@@ -1066,7 +1136,8 @@ function createMcpServer(sites) {
|
|
|
1066
1136
|
const buf = Buffer.isBuffer(screenshotBuffer) ? screenshotBuffer : Buffer.from(screenshotBuffer);
|
|
1067
1137
|
// ── 5. Save to disk ─────────────────────────────────────────────
|
|
1068
1138
|
const ext = fmt === "jpeg" ? "jpg" : "png";
|
|
1069
|
-
const
|
|
1139
|
+
const idPart = page_id ?? (pageUrl.replace(/https?:\/\//, "").replace(/[^a-z0-9]/gi, "_").slice(0, 40));
|
|
1140
|
+
const filename = `page_${idPart}_${Date.now()}.${ext}`;
|
|
1070
1141
|
const filePath = path.join(screenshotsDir, filename);
|
|
1071
1142
|
fs.writeFileSync(filePath, buf);
|
|
1072
1143
|
const sizeKB = Math.round(buf.length / 1024);
|
package/package.json
CHANGED