@yashwant.dharmdas/elementor-mcp 3.2.2 → 3.2.4
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 +87 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -993,8 +993,9 @@ 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)"),
|
|
@@ -1003,16 +1004,47 @@ function createMcpServer(sites) {
|
|
|
1003
1004
|
wait: z.number().optional().describe("Extra milliseconds to wait after page load + auto-scroll before capturing (default: 2000). Increase for heavy animations/videos."),
|
|
1004
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."),
|
|
1005
1006
|
site: siteParam,
|
|
1006
|
-
}, async ({ page_id, full_page, width, format, quality, max_height, wait, auto_scroll, site }) => {
|
|
1007
|
+
}, async ({ page_id, url, full_page, width, format, quality, max_height, wait, auto_scroll, site }) => {
|
|
1007
1008
|
try {
|
|
1009
|
+
if (!page_id && !url) {
|
|
1010
|
+
throw new Error("Provide either page_id or url.");
|
|
1011
|
+
}
|
|
1008
1012
|
const { wpUrl, authHeader } = resolveSite(sites, site);
|
|
1009
|
-
// ── 1. Resolve the
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
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
|
+
}
|
|
1014
1046
|
if (!pageUrl)
|
|
1015
|
-
throw new Error("Could not resolve
|
|
1047
|
+
throw new Error("Could not resolve URL.");
|
|
1016
1048
|
// ── 2. Detect system Chrome ───────────────────────────────────────
|
|
1017
1049
|
const chromePaths = [
|
|
1018
1050
|
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
@@ -1095,43 +1127,65 @@ function createMcpServer(sites) {
|
|
|
1095
1127
|
// Extra settle time for fonts, animations, videos
|
|
1096
1128
|
await new Promise(resolve => setTimeout(resolve, wait ?? 2000));
|
|
1097
1129
|
const fmt = format ?? "jpeg";
|
|
1098
|
-
const
|
|
1099
|
-
if (fmt === "jpeg")
|
|
1100
|
-
screenshotOptions.quality = quality ?? 82;
|
|
1130
|
+
const baseOptions = { type: fmt, fullPage: !max_height && (full_page ?? true) };
|
|
1101
1131
|
if (max_height)
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1132
|
+
baseOptions.clip = { x: 0, y: 0, width: vpWidth, height: vpHeight };
|
|
1133
|
+
// ── Adaptive quality: always fit under the MCP 1MB tool-result limit ──
|
|
1134
|
+
// (base64 overhead ~33%, so raw buffer must be ≤ ~780KB)
|
|
1135
|
+
const PREVIEW_LIMIT = 750 * 1024;
|
|
1136
|
+
let buf;
|
|
1137
|
+
let usedQuality = undefined;
|
|
1138
|
+
if (fmt === "jpeg") {
|
|
1139
|
+
// Try user-requested quality first; fall back progressively lower until it fits.
|
|
1140
|
+
const q0 = quality ?? 82;
|
|
1141
|
+
const qualitySteps = Array.from(new Set([q0, 70, 55, 40, 25, 15])).filter(q => q <= q0);
|
|
1142
|
+
for (const q of qualitySteps) {
|
|
1143
|
+
const raw = await page.screenshot({ ...baseOptions, quality: q });
|
|
1144
|
+
buf = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
|
|
1145
|
+
usedQuality = q;
|
|
1146
|
+
if (buf.length <= PREVIEW_LIMIT)
|
|
1147
|
+
break;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
else {
|
|
1151
|
+
const raw = await page.screenshot(baseOptions);
|
|
1152
|
+
buf = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
|
|
1153
|
+
}
|
|
1154
|
+
buf = buf;
|
|
1105
1155
|
// ── 5. Save to disk ─────────────────────────────────────────────
|
|
1106
1156
|
const ext = fmt === "jpeg" ? "jpg" : "png";
|
|
1107
|
-
const
|
|
1157
|
+
const idPart = page_id ?? (pageUrl.replace(/https?:\/\//, "").replace(/[^a-z0-9]/gi, "_").slice(0, 40));
|
|
1158
|
+
const filename = `page_${idPart}_${Date.now()}.${ext}`;
|
|
1108
1159
|
const filePath = path.join(screenshotsDir, filename);
|
|
1109
1160
|
fs.writeFileSync(filePath, buf);
|
|
1110
1161
|
const sizeKB = Math.round(buf.length / 1024);
|
|
1111
1162
|
const mimeType = `image/${fmt}`;
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
text: [
|
|
1118
|
-
`✅ Screenshot saved successfully.`,
|
|
1119
|
-
`📁 file_path: ${filePath}`,
|
|
1120
|
-
`📐 Size: ${sizeKB} KB | Format: ${ext.toUpperCase()} | URL: ${pageUrl}`,
|
|
1121
|
-
``,
|
|
1122
|
-
`👉 To upload to Basecamp, call upload_attachment with:`,
|
|
1123
|
-
` file_path = "${filePath}"`,
|
|
1124
|
-
` project_id = <your Basecamp project ID>`,
|
|
1125
|
-
].join("\n"),
|
|
1126
|
-
},
|
|
1127
|
-
];
|
|
1163
|
+
const qualityNote = usedQuality !== undefined && usedQuality !== (quality ?? 82)
|
|
1164
|
+
? ` | Auto-downscaled to quality ${usedQuality} to fit MCP limit`
|
|
1165
|
+
: "";
|
|
1166
|
+
// ── 6. Always return the image so Claude can analyse it ──────
|
|
1167
|
+
const content = [];
|
|
1128
1168
|
if (buf.length <= PREVIEW_LIMIT) {
|
|
1129
|
-
content.
|
|
1169
|
+
content.push({
|
|
1130
1170
|
type: "image",
|
|
1131
1171
|
data: buf.toString("base64"),
|
|
1132
1172
|
mimeType,
|
|
1133
1173
|
});
|
|
1134
1174
|
}
|
|
1175
|
+
content.push({
|
|
1176
|
+
type: "text",
|
|
1177
|
+
text: [
|
|
1178
|
+
`✅ Screenshot captured and saved.`,
|
|
1179
|
+
`📁 file_path: ${filePath}`,
|
|
1180
|
+
`📐 Size: ${sizeKB} KB | Format: ${ext.toUpperCase()}${qualityNote}`,
|
|
1181
|
+
`🌐 URL: ${pageUrl}`,
|
|
1182
|
+
buf.length > PREVIEW_LIMIT
|
|
1183
|
+
? `\n⚠️ Image still exceeds the 1MB MCP return limit even at lowest quality. The file is saved to disk and can be used via upload_attachment(file_path).`
|
|
1184
|
+
: ``,
|
|
1185
|
+
``,
|
|
1186
|
+
`👉 To upload to Basecamp: upload_attachment with file_path = "${filePath}"`,
|
|
1187
|
+
].filter(Boolean).join("\n"),
|
|
1188
|
+
});
|
|
1135
1189
|
return { content };
|
|
1136
1190
|
}
|
|
1137
1191
|
finally {
|
package/package.json
CHANGED