@noleemits/vision-builder-control-mcp 4.46.1 → 4.47.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.
- package/index.js +60 -4
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -111,7 +111,7 @@ process.on('SIGINT', () => {
|
|
|
111
111
|
// CONFIG
|
|
112
112
|
// ================================================================
|
|
113
113
|
|
|
114
|
-
const VERSION = '4.
|
|
114
|
+
const VERSION = '4.47.0';
|
|
115
115
|
const MIN_PLUGIN_VERSION = '4.13.0'; // Minimum WP plugin version required by this MCP server
|
|
116
116
|
|
|
117
117
|
// ================================================================
|
|
@@ -2429,7 +2429,8 @@ function getToolDefinitions() {
|
|
|
2429
2429
|
featured_image_id: { type: 'number', description: 'Media library attachment ID' },
|
|
2430
2430
|
featured_image_basename: { type: 'string', description: 'Filename of an attachment (e.g. "boating-accidents-v2.jpg") — resolves to the matching attachment ID. Use instead of featured_image_id when you have the source filename but not the ID.' },
|
|
2431
2431
|
elementor: { type: 'boolean', description: 'Set up for Elementor editing' },
|
|
2432
|
-
seo: { type: 'object', description: 'RankMath SEO: {title, description, focus_keyword, robots, ...}' }
|
|
2432
|
+
seo: { type: 'object', description: 'RankMath SEO: {title, description, focus_keyword, robots, ...}' },
|
|
2433
|
+
dedupe_by_title: { type: 'boolean', description: 'If true, check for an existing non-trashed post with the same (title, post_type) and return it instead of creating a duplicate. Response will have was_existing:true. Use for idempotent creates over flaky transports — protects against phantom duplicates when an MCP response times out but the server insert succeeded.' }
|
|
2433
2434
|
},
|
|
2434
2435
|
required: ['title']
|
|
2435
2436
|
}
|
|
@@ -2469,6 +2470,35 @@ function getToolDefinitions() {
|
|
|
2469
2470
|
required: ['post_id']
|
|
2470
2471
|
}
|
|
2471
2472
|
},
|
|
2473
|
+
{
|
|
2474
|
+
name: 'get_post_by_slug',
|
|
2475
|
+
description: 'Look up a single post by exact slug within a post type. Returns the post if found, or found:false if not. Use before create_post to check for slug collisions, or to resolve a slug into a post ID without scanning list_posts.',
|
|
2476
|
+
inputSchema: {
|
|
2477
|
+
type: 'object',
|
|
2478
|
+
properties: {
|
|
2479
|
+
slug: { type: 'string', description: 'Exact slug (post_name). Case-insensitive, sanitized server-side.' },
|
|
2480
|
+
post_type: { type: 'string', description: 'Post type slug. Default "post".' },
|
|
2481
|
+
status: { type: 'string', description: 'Comma-separated statuses to include. Default: publish,private,draft,pending (excludes trash).' }
|
|
2482
|
+
},
|
|
2483
|
+
required: ['slug']
|
|
2484
|
+
}
|
|
2485
|
+
},
|
|
2486
|
+
{
|
|
2487
|
+
name: 'change_post_type',
|
|
2488
|
+
description: 'Migrate a WordPress post to a different post type IN PLACE — preserves post ID, post_meta (SEO, featured image, custom fields), comments, attachments, post_date, and any taxonomy terms registered on both types. Atomic operation (single DB write to the post_type column, no save_post re-fire). Optionally rewrites internal links across all post_content and creates a RankMath 301 redirect from the old permalink. Use this instead of create_post + delete_post when moving a page to a CPT — it is faster, lossless, and keeps the URL history.',
|
|
2489
|
+
inputSchema: {
|
|
2490
|
+
type: 'object',
|
|
2491
|
+
properties: {
|
|
2492
|
+
post_id: { type: 'number', description: 'WordPress post/page ID to migrate' },
|
|
2493
|
+
new_post_type: { type: 'string', description: 'Target post type slug. Must be registered.' },
|
|
2494
|
+
slug_override: { type: 'string', description: 'Optional. Force a specific slug. If omitted and the existing slug collides on the new post type, a unique suffix is added automatically.' },
|
|
2495
|
+
update_internal_links: { type: 'boolean', description: 'Rewrite old permalink → new permalink across all post_content. Default: true.' },
|
|
2496
|
+
create_redirect: { type: 'boolean', description: 'Create a RankMath 301 from the old permalink to the new one. Default: true. Requires RankMath active.' },
|
|
2497
|
+
flush_rewrites: { type: 'boolean', description: 'Flush WP rewrite rules after the change. Default: true.' }
|
|
2498
|
+
},
|
|
2499
|
+
required: ['post_id', 'new_post_type']
|
|
2500
|
+
}
|
|
2501
|
+
},
|
|
2472
2502
|
// ── RankMath SEO ──
|
|
2473
2503
|
{
|
|
2474
2504
|
name: 'get_seo',
|
|
@@ -4794,11 +4824,37 @@ async function handleToolCall(name, args) {
|
|
|
4794
4824
|
const body = { title: args.title };
|
|
4795
4825
|
const passthrough = ['post_type', 'content', 'excerpt', 'status', 'slug',
|
|
4796
4826
|
'parent', 'parent_slug', 'taxonomies', 'featured_image_id',
|
|
4797
|
-
'featured_image_basename', 'elementor', 'seo'];
|
|
4827
|
+
'featured_image_basename', 'elementor', 'seo', 'dedupe_by_title'];
|
|
4798
4828
|
for (const k of passthrough) if (args[k] !== undefined) body[k] = args[k];
|
|
4799
4829
|
const r = await apiCall('/posts', 'POST', body);
|
|
4800
4830
|
if (!r.success) return ok(`Failed: ${r.message || 'Unknown error'}`);
|
|
4801
|
-
|
|
4831
|
+
const prefix = r.was_existing ? 'Post already existed (dedupe hit)' : 'Post created';
|
|
4832
|
+
return ok(`${prefix}!\nID: ${r.id} | Type: ${r.type} | Status: ${r.status}\nTitle: ${r.title}\nSlug: ${r.slug}\nURL: ${r.url}\nEdit: ${r.edit_url}`);
|
|
4833
|
+
}
|
|
4834
|
+
|
|
4835
|
+
case 'get_post_by_slug': {
|
|
4836
|
+
const params = new URLSearchParams();
|
|
4837
|
+
params.set('slug', args.slug);
|
|
4838
|
+
if (args.post_type) params.set('post_type', args.post_type);
|
|
4839
|
+
if (args.status) params.set('status', args.status);
|
|
4840
|
+
const r = await apiCall(`/posts/by-slug?${params}`);
|
|
4841
|
+
if (!r.success) return ok(`Failed: ${r.message || 'Unknown error'}`);
|
|
4842
|
+
if (!r.found) return ok(`No post with slug "${r.slug}" found in post type "${r.post_type}".`);
|
|
4843
|
+
return ok(`Found post!\nID: ${r.id} | Type: ${r.type} | Status: ${r.status}\nTitle: ${r.title}\nSlug: ${r.slug}\nURL: ${r.url}\nEdit: ${r.edit_url}`);
|
|
4844
|
+
}
|
|
4845
|
+
|
|
4846
|
+
case 'change_post_type': {
|
|
4847
|
+
const { post_id, ...body } = args;
|
|
4848
|
+
const r = await apiCall(`/posts/${post_id}/change-type`, 'POST', body);
|
|
4849
|
+
if (!r.success) return ok(`Failed: ${r.message || 'Unknown error'}`);
|
|
4850
|
+
let msg = `Post type changed!\nID: ${r.id}\n`;
|
|
4851
|
+
msg += `Type: ${r.old_post_type} → ${r.new_post_type}\n`;
|
|
4852
|
+
msg += `Permalink: ${r.old_permalink} → ${r.new_permalink}\n`;
|
|
4853
|
+
if (r.slug_changed) msg += `Slug: ${r.old_slug} → ${r.new_slug} (collision auto-resolved)\n`;
|
|
4854
|
+
msg += `Internal links rewritten: ${r.internal_links_updated}\n`;
|
|
4855
|
+
msg += `301 redirect created: ${r.redirect_created ? 'yes' : 'no'}\n`;
|
|
4856
|
+
msg += `Rewrite rules flushed: ${r.rewrites_flushed ? 'yes' : 'no'}`;
|
|
4857
|
+
return ok(msg);
|
|
4802
4858
|
}
|
|
4803
4859
|
|
|
4804
4860
|
case 'update_post': {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noleemits/vision-builder-control-mcp",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.47.0",
|
|
4
4
|
"description": "Vision Builder Control MCP server - design token-driven page builder tools for WordPress/Elementor websites",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|