@yashwant.dharmdas/elementor-mcp 3.5.0 → 3.6.0

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 +51 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1934,6 +1934,57 @@ function createMcpServer(sites) {
1934
1934
  return { content: [{ type: "text", text: `Error setting Z-index: ${error.response?.data?.message || error.message}` }], isError: true };
1935
1935
  }
1936
1936
  });
1937
+ // ── Group 27: Content Audit (text extraction & bulk fix application) ────────
1938
+ server.tool("extract-pages-text", "Extract clean text content from one or many Elementor pages — returns ONLY the words, not the JSON or HTML noise. Designed for grammar/spelling/sentence audits across many pages at once. Uses a key-name heuristic so it works for ANY widget (built-in, Elementor Pro, WooCommerce, third-party, custom) without widget-specific code. Each block includes element_id + field_path so fixes can be written back precisely with apply-text-fixes.", {
1939
+ page_ids: z.array(z.number()).optional().describe("Specific page IDs to extract from"),
1940
+ scope: z.enum(["all_pages"]).optional().describe("Use 'all_pages' to extract from every published Elementor page"),
1941
+ post_type: z.string().optional().describe("Limit to a specific post type (e.g. 'page', 'post', 'astra-portfolio')"),
1942
+ site: siteParam,
1943
+ }, async ({ page_ids, scope, post_type, site }) => {
1944
+ try {
1945
+ if (!page_ids && !scope && !post_type) {
1946
+ return { content: [{ type: "text", text: "Provide page_ids, scope='all_pages', or post_type." }], isError: true };
1947
+ }
1948
+ const { wpUrl, authHeader } = resolveSite(sites, site);
1949
+ const body = {};
1950
+ if (page_ids)
1951
+ body.page_ids = page_ids;
1952
+ if (scope)
1953
+ body.scope = scope;
1954
+ if (post_type)
1955
+ body.post_type = post_type;
1956
+ const r = await axios.post(`${wpUrl}/wp-json/erc/v1/site/extract-text`, body, { headers: { Authorization: authHeader, "Content-Type": "application/json" } });
1957
+ return { content: [{ type: "text", text: JSON.stringify(r.data, null, 2) }] };
1958
+ }
1959
+ catch (error) {
1960
+ return { content: [{ type: "text", text: `Error extracting page text: ${error.response?.data?.message || error.message}` }], isError: true };
1961
+ }
1962
+ });
1963
+ server.tool("apply-text-fixes", "Write text corrections (grammar/spelling/sentence fixes) back to many Elementor pages in one call. Pair with extract-pages-text. Each fix uses 'old_text' for safe substring replacement (recommended — preserves surrounding HTML/markup and only touches the broken phrase). Omit old_text to fully overwrite the field with new_text.", {
1964
+ fixes: z.string().describe('JSON array of fix objects. Schema: [{"page_id": number, "element_id": string, "field_path": string, "old_text"?: string, "new_text": string}]. ' +
1965
+ "Recommended: always provide old_text — only that exact substring is replaced, leaving surrounding HTML untouched. " +
1966
+ "field_path supports nested paths returned by extract-pages-text (e.g. 'editor', 'title', 'tabs.0.tab_title')."),
1967
+ site: siteParam,
1968
+ }, async ({ fixes, site }) => {
1969
+ let parsed;
1970
+ try {
1971
+ parsed = JSON.parse(fixes);
1972
+ }
1973
+ catch {
1974
+ return { content: [{ type: "text", text: "Invalid JSON in fixes parameter." }], isError: true };
1975
+ }
1976
+ if (!Array.isArray(parsed) || parsed.length === 0) {
1977
+ return { content: [{ type: "text", text: "fixes must be a non-empty JSON array." }], isError: true };
1978
+ }
1979
+ try {
1980
+ const { wpUrl, authHeader } = resolveSite(sites, site);
1981
+ const r = await axios.post(`${wpUrl}/wp-json/erc/v1/site/apply-text-fixes`, { fixes: parsed }, { headers: { Authorization: authHeader, "Content-Type": "application/json" } });
1982
+ return { content: [{ type: "text", text: JSON.stringify(r.data, null, 2) }] };
1983
+ }
1984
+ catch (error) {
1985
+ return { content: [{ type: "text", text: `Error applying text fixes: ${error.response?.data?.message || error.message}` }], isError: true };
1986
+ }
1987
+ });
1937
1988
  // ── Group 26: Favicon ─────────────────────────────────────────────────────────
1938
1989
  server.tool("upload-favicon", "Set the WordPress Site Icon (favicon) — equivalent to Customize → Site Identity → Select Site Icon. Accepts either a URL of an image already in the media library, a media attachment ID, or a remote URL to fetch and upload first.", {
1939
1990
  favicon_url: z.string().optional().describe("URL of the favicon image. If the URL is from the same WP media library, the existing attachment is reused; otherwise the image is downloaded and uploaded as a new media item."),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yashwant.dharmdas/elementor-mcp",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "description": "MCP server for controlling Elementor via Claude — supports multiple WordPress sites",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",