@respira/wordpress-mcp-server 8.3.24 → 8.3.26
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/CHANGELOG.md +67 -0
- package/README.md +114 -20
- package/TOOL_CATALOG.md +445 -307
- package/dist/__tests__/087103bc-the-host-answers-well-known-first.test.d.ts +2 -0
- package/dist/__tests__/087103bc-the-host-answers-well-known-first.test.d.ts.map +1 -0
- package/dist/__tests__/087103bc-the-host-answers-well-known-first.test.js +73 -0
- package/dist/__tests__/087103bc-the-host-answers-well-known-first.test.js.map +1 -0
- package/dist/__tests__/0e6bd33c-redeem-preserves-per-site-settings.test.js +3 -2
- package/dist/__tests__/0e6bd33c-redeem-preserves-per-site-settings.test.js.map +1 -1
- package/dist/__tests__/685d8023-a-403-from-the-web-server-shows-its-evidence.test.d.ts +2 -0
- package/dist/__tests__/685d8023-a-403-from-the-web-server-shows-its-evidence.test.d.ts.map +1 -0
- package/dist/__tests__/685d8023-a-403-from-the-web-server-shows-its-evidence.test.js +106 -0
- package/dist/__tests__/685d8023-a-403-from-the-web-server-shows-its-evidence.test.js.map +1 -0
- package/dist/__tests__/81c478df-create-page-duplicate-id-aliases.test.d.ts +11 -0
- package/dist/__tests__/81c478df-create-page-duplicate-id-aliases.test.d.ts.map +1 -0
- package/dist/__tests__/81c478df-create-page-duplicate-id-aliases.test.js +80 -0
- package/dist/__tests__/81c478df-create-page-duplicate-id-aliases.test.js.map +1 -0
- package/dist/__tests__/81c478df-rest-no-route-blames-the-plugin.test.d.ts +16 -0
- package/dist/__tests__/81c478df-rest-no-route-blames-the-plugin.test.d.ts.map +1 -0
- package/dist/__tests__/81c478df-rest-no-route-blames-the-plugin.test.js +105 -0
- package/dist/__tests__/81c478df-rest-no-route-blames-the-plugin.test.js.map +1 -0
- package/dist/__tests__/dfc0e156-plugin-file-with-a-slash.test.d.ts +2 -0
- package/dist/__tests__/dfc0e156-plugin-file-with-a-slash.test.d.ts.map +1 -0
- package/dist/__tests__/dfc0e156-plugin-file-with-a-slash.test.js +69 -0
- package/dist/__tests__/dfc0e156-plugin-file-with-a-slash.test.js.map +1 -0
- package/dist/__tests__/fb4ec63e-update-advice-matches-the-install.test.d.ts +15 -0
- package/dist/__tests__/fb4ec63e-update-advice-matches-the-install.test.d.ts.map +1 -0
- package/dist/__tests__/fb4ec63e-update-advice-matches-the-install.test.js +61 -0
- package/dist/__tests__/fb4ec63e-update-advice-matches-the-install.test.js.map +1 -0
- package/dist/__tests__/plugin-slug-path-encoding.test.d.ts +2 -0
- package/dist/__tests__/plugin-slug-path-encoding.test.d.ts.map +1 -0
- package/dist/__tests__/plugin-slug-path-encoding.test.js +41 -0
- package/dist/__tests__/plugin-slug-path-encoding.test.js.map +1 -0
- package/dist/__tests__/release-9-surface.test.d.ts +2 -0
- package/dist/__tests__/release-9-surface.test.d.ts.map +1 -0
- package/dist/__tests__/release-9-surface.test.js +197 -0
- package/dist/__tests__/release-9-surface.test.js.map +1 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -1
- package/dist/install-skills.d.ts +4 -5
- package/dist/install-skills.d.ts.map +1 -1
- package/dist/install-skills.js +4 -5
- package/dist/install-skills.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +328 -89
- package/dist/server.js.map +1 -1
- package/dist/skill-prompts.d.ts +43 -0
- package/dist/skill-prompts.d.ts.map +1 -0
- package/dist/skill-prompts.js +135 -0
- package/dist/skill-prompts.js.map +1 -0
- package/dist/wordpress-client.d.ts +132 -11
- package/dist/wordpress-client.d.ts.map +1 -1
- package/dist/wordpress-client.js +380 -39
- package/dist/wordpress-client.js.map +1 -1
- package/package.json +2 -2
- package/skills/activity-report-composer/SKILL.md +17 -5
- package/skills/activity-report-composer/metadata.json +2 -2
- package/skills/art-direction/SKILL.md +9 -3
- package/skills/art-direction/metadata.json +7 -3
- package/skills/brand-voice-synthesizer/SKILL.md +36 -16
- package/skills/brand-voice-synthesizer/metadata.json +8 -4
- package/skills/build-oxygen6-page/SKILL.md +17 -2
- package/skills/conversion-audit/SKILL.md +12 -0
- package/skills/custom-post-type-architect/SKILL.md +12 -0
- package/skills/figma-to-bricks/SKILL.md +4 -2
- package/skills/figma-to-divi/SKILL.md +4 -2
- package/skills/figma-to-elementor/SKILL.md +8 -1
- package/skills/figma-to-gutenberg/SKILL.md +4 -2
- package/skills/html-to-breakdance/SKILL.md +7 -3
- package/skills/html-to-breakdance/metadata.json +7 -3
- package/skills/html-to-bricks/SKILL.md +7 -3
- package/skills/html-to-bricks/metadata.json +7 -3
- package/skills/internal-link-builder/SKILL.md +12 -0
- package/skills/migrate-beaver-builder-to-bricks/SKILL.md +19 -3
- package/skills/migrate-beaver-builder-to-gutenberg/SKILL.md +19 -3
- package/skills/migrate-brizy-to-gutenberg/SKILL.md +19 -3
- package/skills/migrate-divi-to-breakdance/SKILL.md +19 -3
- package/skills/migrate-divi-to-bricks/SKILL.md +19 -3
- package/skills/migrate-divi-to-gutenberg/SKILL.md +19 -3
- package/skills/migrate-elementor-to-breakdance/SKILL.md +20 -4
- package/skills/migrate-elementor-to-bricks/SKILL.md +20 -4
- package/skills/migrate-elementor-to-gutenberg/SKILL.md +20 -4
- package/skills/migrate-elementor-to-oxygen/SKILL.md +20 -4
- package/skills/migrate-oxygen-to-breakdance/SKILL.md +19 -3
- package/skills/migrate-oxygen-to-bricks/SKILL.md +19 -3
- package/skills/migrate-thrive-architect-to-gutenberg/SKILL.md +19 -3
- package/skills/migrate-visual-composer-to-gutenberg/SKILL.md +19 -3
- package/skills/migrate-wpbakery-to-bricks/SKILL.md +19 -3
- package/skills/migrate-wpbakery-to-gutenberg/SKILL.md +19 -3
- package/skills/mobile-experience-report/SKILL.md +12 -0
- package/skills/murmur-review-loop/SKILL.md +142 -0
- package/skills/page-template-library/SKILL.md +12 -0
- package/skills/respira-builder-edits/SKILL.md +1 -0
- package/skills/respira-setup-assistant/SKILL.md +12 -0
- package/skills/respira-site-audit/SKILL.md +18 -6
- package/skills/respira-woocommerce/SKILL.md +1 -0
- package/skills/seo-aeo-amplifier/SKILL.md +14 -2
- package/skills/seo-aeo-amplifier/metadata.json +2 -2
- package/skills/stale-content-detector/SKILL.md +12 -0
- package/skills/technical-debt-audit/SKILL.md +14 -2
- package/skills/woo-marketing-campaigns/SKILL.md +12 -9
- package/skills/woo-pricing-promotions/SKILL.md +9 -9
- package/skills/woocommerce-health-check/SKILL.md +22 -8
- package/skills/wordpress-ai-image-optimizer/SKILL.md +14 -2
- package/skills/wordpress-ai-image-optimizer/metadata.json +2 -2
- package/skills/wordpress-security-review/SKILL.md +154 -0
- package/skills/wordpress-site-dna/README.md +1 -1
- package/skills/wordpress-site-dna/SKILL.md +52 -19
- package/tool-capabilities.json +3171 -370
package/dist/server.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides tools for AI coding assistants to interact with WordPress sites
|
|
5
5
|
*/
|
|
6
|
-
import { Server } from '@modelcontextprotocol/server';
|
|
6
|
+
import { Server, ProtocolError, ProtocolErrorCode } from '@modelcontextprotocol/server';
|
|
7
7
|
import { setMcpClientInfo } from './agent-signature.js';
|
|
8
8
|
import { serveStdio } from '@modelcontextprotocol/server/stdio';
|
|
9
9
|
import { execSync } from 'child_process';
|
|
@@ -17,9 +17,10 @@ import { RespiraVersionChecker } from './version-checker.js';
|
|
|
17
17
|
import { getBricksTools, dispatchBricksTool } from './bricks-tools.js';
|
|
18
18
|
import { getElementorTools, dispatchElementorTool } from './elementor-tools.js';
|
|
19
19
|
import { getAcfTools, resolveAcfToolName } from './acf-tools.js';
|
|
20
|
+
import { listSkillPrompts, getSkillPrompt } from './skill-prompts.js';
|
|
20
21
|
import { getUsageEmitter, deriveToolKind } from './usage-emitter.js';
|
|
21
22
|
import { FSE_OPERATION_ITEM_SCHEMA } from './fse-operation-schema.js';
|
|
22
|
-
import { collapseLauncherProcesses, validateApiKeyShape, describeConfigOrigin, configOriginKey } from './config.js';
|
|
23
|
+
import { collapseLauncherProcesses, validateApiKeyShape, describeConfigOrigin, configOriginKey, describeUpdateRoute } from './config.js';
|
|
23
24
|
// Process-local secret keeps target hashes useful for same-session retry
|
|
24
25
|
// detection without making low-entropy WordPress ids reversible centrally.
|
|
25
26
|
const TELEMETRY_HASH_SECRET = randomUUID();
|
|
@@ -133,6 +134,19 @@ function saveRespiraMcpState(patch) {
|
|
|
133
134
|
console.error('[respira-mcp] could not write', STATE_FILE_PATH, '-', err?.message);
|
|
134
135
|
}
|
|
135
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Tools removed in a major release, keyed by the name a caller would still
|
|
139
|
+
* send. dispatchToolCall answers them with the replacement instead of a bare
|
|
140
|
+
* "Unknown tool". Not advertised and not dispatched, so the parity gate never
|
|
141
|
+
* sees them.
|
|
142
|
+
*/
|
|
143
|
+
const RETIRED_TOOLS = {
|
|
144
|
+
woocommerce_sales_report: {
|
|
145
|
+
replacement: 'woocommerce_revenue_summary',
|
|
146
|
+
removedIn: '9.0',
|
|
147
|
+
note: 'It takes date_start and date_end (ISO, in the store timezone) instead of period, date_min and date_max, and states exactly which order statuses and amounts it counts.',
|
|
148
|
+
},
|
|
149
|
+
};
|
|
136
150
|
const MCP_SERVER_VERSION = (() => {
|
|
137
151
|
try {
|
|
138
152
|
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
@@ -411,8 +425,8 @@ const TOOLS_WITH_PAGINATION_HINT = {
|
|
|
411
425
|
// node_id and no pagination, so the old hint sent the agent looking for an
|
|
412
426
|
// argument that does not exist and it silently did nothing. A customer hit
|
|
413
427
|
// the cap on a 158KB Breakdance page and was handed exactly that advice.
|
|
414
|
-
respira_extract_builder_content: 'This tool has no pagination and always returns the whole page.
|
|
415
|
-
wordpress_extract_builder_content: 'This tool has no pagination and always returns the whole page.
|
|
428
|
+
respira_extract_builder_content: 'This tool has no pagination and always returns the whole page. To read ONE element\'s stored content on a page of any size, call respira_find_element with include: "content". It returns the element body the builder saved, which is what update_element wants back. respira_find_builder_targets takes query, limit and offset and reports total_matches / has_more / next_offset, and respira_get_page_outline gives a row-level summary. Do not rebuild an element from the rendered front end: WordPress adds attributes at output time (target, rel) that the stored value never had. Raising RESPIRA_MAX_TOOL_RESULT_BYTES is a last resort, and it is a client-side setting an agent cannot change mid-task.',
|
|
429
|
+
wordpress_extract_builder_content: 'This tool has no pagination and always returns the whole page. To read ONE element\'s stored content on a page of any size, call wordpress_find_element with include: "content". It returns the element body the builder saved, which is what update_element wants back. wordpress_find_builder_targets takes query, limit and offset and reports total_matches / has_more / next_offset, and wordpress_get_page_outline gives a row-level summary. Do not rebuild an element from the rendered front end: WordPress adds attributes at output time (target, rel) that the stored value never had. Raising RESPIRA_MAX_TOOL_RESULT_BYTES is a last resort, and it is a client-side setting an agent cannot change mid-task.',
|
|
416
430
|
respira_list_plugins: 'No pagination arg today. The full plugin list is usually small; consider filing a feature request if your site hits the cap here.',
|
|
417
431
|
};
|
|
418
432
|
/**
|
|
@@ -566,6 +580,8 @@ export class RespiraWordPressServer {
|
|
|
566
580
|
}, {
|
|
567
581
|
capabilities: {
|
|
568
582
|
tools: {},
|
|
583
|
+
// The bundled skills catalog, one prompt per skill (skill-prompts.ts).
|
|
584
|
+
prompts: {},
|
|
569
585
|
},
|
|
570
586
|
instructions: `${SOUL_MD_CONTENT}
|
|
571
587
|
|
|
@@ -592,7 +608,7 @@ Follow these on every site. They are what separates a great result from a frustr
|
|
|
592
608
|
|
|
593
609
|
## Tool naming
|
|
594
610
|
|
|
595
|
-
Always use respira_* tool names (e.g. respira_update_page, respira_find_element). The wordpress_* names
|
|
611
|
+
Always use respira_* tool names (e.g. respira_update_page, respira_find_element). The older wordpress_* names still answer, so a saved call keeps working, but new calls should use respira_*.
|
|
596
612
|
|
|
597
613
|
## Step 1: Understand the site
|
|
598
614
|
|
|
@@ -1826,6 +1842,20 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
1826
1842
|
tools: await this.getTools(),
|
|
1827
1843
|
};
|
|
1828
1844
|
});
|
|
1845
|
+
// Skills as prompts. Served from the skills folder bundled into the
|
|
1846
|
+
// package, so listing them needs no site and no network: a client can
|
|
1847
|
+
// offer every Respira skill as a slash command before a site is set up.
|
|
1848
|
+
this.server.setRequestHandler('prompts/list', async () => {
|
|
1849
|
+
return { prompts: listSkillPrompts() };
|
|
1850
|
+
});
|
|
1851
|
+
this.server.setRequestHandler('prompts/get', async (request) => {
|
|
1852
|
+
const { name, arguments: promptArgs } = request.params;
|
|
1853
|
+
const prompt = getSkillPrompt(String(name || ''), promptArgs);
|
|
1854
|
+
if (!prompt) {
|
|
1855
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Unknown prompt: ${name}. Call prompts/list for the Respira skills this server offers.`);
|
|
1856
|
+
}
|
|
1857
|
+
return prompt;
|
|
1858
|
+
});
|
|
1829
1859
|
// Handle tool calls
|
|
1830
1860
|
this.server.setRequestHandler('tools/call', async (request) => {
|
|
1831
1861
|
const { name, arguments: args } = request.params;
|
|
@@ -2128,13 +2158,19 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2128
2158
|
if (!update) {
|
|
2129
2159
|
return result;
|
|
2130
2160
|
}
|
|
2161
|
+
// Ticket fb4ec63e: the advice has to describe the install that is
|
|
2162
|
+
// answering. On a .mcpb bundle the npm command completes, installs a copy
|
|
2163
|
+
// Claude Desktop never loads, and leaves the reporter certain they had
|
|
2164
|
+
// updated. describeUpdateRoute reads the same launch-path signal
|
|
2165
|
+
// respira_diagnose_connection already reports.
|
|
2166
|
+
const route = describeUpdateRoute();
|
|
2131
2167
|
// Lead with what this build is missing, not with the fact that a number
|
|
2132
2168
|
// changed. A customer on 7.1.2 received the old generic sentence on every
|
|
2133
2169
|
// call for weeks while fighting a bug that a newer build had already fixed,
|
|
2134
2170
|
// and neither she nor her AI had any reason to connect the two.
|
|
2135
2171
|
const message = update.missingFixes.length > 0
|
|
2136
|
-
? `This MCP build (${update.currentVersion}) is behind ${update.latestVersion} and is missing behaviour you may be working around right now: ${update.missingFixes.join(' ')}
|
|
2137
|
-
: `A newer MCP version is available (${update.currentVersion} -> ${update.latestVersion}).
|
|
2172
|
+
? `This MCP build (${update.currentVersion}) is behind ${update.latestVersion} and is missing behaviour you may be working around right now: ${update.missingFixes.join(' ')} ${route.how_to_update}`
|
|
2173
|
+
: `A newer MCP version is available (${update.currentVersion} -> ${update.latestVersion}). ${route.how_to_update}`;
|
|
2138
2174
|
const noticePayload = {
|
|
2139
2175
|
package: update.packageName,
|
|
2140
2176
|
current_version: update.currentVersion,
|
|
@@ -2142,8 +2178,12 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2142
2178
|
checked_at: update.checkedAt,
|
|
2143
2179
|
...(update.missingFixes.length > 0 ? { missing_fixes: update.missingFixes } : {}),
|
|
2144
2180
|
message,
|
|
2145
|
-
|
|
2146
|
-
|
|
2181
|
+
install_kind: route.install_kind,
|
|
2182
|
+
transport_mode: route.transport_mode,
|
|
2183
|
+
binary_path: route.binary_path,
|
|
2184
|
+
how_to_update: route.how_to_update,
|
|
2185
|
+
...(route.upgrade_command ? { upgrade_command: route.upgrade_command } : {}),
|
|
2186
|
+
...(route.rerun_setup_command ? { rerun_setup_command: route.rerun_setup_command } : {}),
|
|
2147
2187
|
};
|
|
2148
2188
|
if (result && typeof result === 'object' && !Array.isArray(result)) {
|
|
2149
2189
|
return {
|
|
@@ -2161,7 +2201,8 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2161
2201
|
if (!update) {
|
|
2162
2202
|
return errorMessage;
|
|
2163
2203
|
}
|
|
2164
|
-
|
|
2204
|
+
const route = describeUpdateRoute();
|
|
2205
|
+
return `${errorMessage}\n\nUpdate available: ${update.currentVersion} -> ${update.latestVersion}. ${route.how_to_update}`;
|
|
2165
2206
|
}
|
|
2166
2207
|
/**
|
|
2167
2208
|
* Append the plugin version compatibility warning to the first successful tool
|
|
@@ -2566,12 +2607,20 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2566
2607
|
type: 'number',
|
|
2567
2608
|
description: 'ID of the original page to duplicate',
|
|
2568
2609
|
},
|
|
2610
|
+
page_id: {
|
|
2611
|
+
type: 'number',
|
|
2612
|
+
description: 'Alias for original_id, matching the builder page tools',
|
|
2613
|
+
},
|
|
2614
|
+
post_id: {
|
|
2615
|
+
type: 'number',
|
|
2616
|
+
description: 'Alias for original_id, matching tools that operate on any post type',
|
|
2617
|
+
},
|
|
2569
2618
|
suffix: {
|
|
2570
2619
|
type: 'string',
|
|
2571
2620
|
description: 'Optional suffix for the duplicated page title',
|
|
2572
2621
|
},
|
|
2573
2622
|
},
|
|
2574
|
-
required: [
|
|
2623
|
+
required: [],
|
|
2575
2624
|
},
|
|
2576
2625
|
annotations: {
|
|
2577
2626
|
title: "Duplicate Page",
|
|
@@ -2649,7 +2698,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2649
2698
|
},
|
|
2650
2699
|
{
|
|
2651
2700
|
name: 'wordpress_delete_page',
|
|
2652
|
-
description: 'Delete a page. IMPORTANT: By default, this only works on Respira-created duplicates. To delete an original: pass `force=true` AND `confirm_live_edit=true`. The "Allow Direct Editing" setting in Respira must also be enabled (disabled by default for safety).\n\nApproval flow
|
|
2701
|
+
description: 'Delete a page. IMPORTANT: By default, this only works on Respira-created duplicates. To delete an original: pass `force=true` AND `confirm_live_edit=true`. The "Allow Direct Editing" setting in Respira must also be enabled (disabled by default for safety).\n\nApproval flow: the first call returns `code: respira_approval_required` with `data.approval_request.approval_token`. Pass that token back via the `approval_token` param on the next call to complete the delete.',
|
|
2653
2702
|
inputSchema: {
|
|
2654
2703
|
type: 'object',
|
|
2655
2704
|
properties: {
|
|
@@ -2663,7 +2712,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2663
2712
|
},
|
|
2664
2713
|
confirm_live_edit: {
|
|
2665
2714
|
type: 'boolean',
|
|
2666
|
-
description: '
|
|
2715
|
+
description: 'Operator confirmation that a force-delete on an original is intended. Required alongside force=true, and honoured only when "Allow Direct Editing" is enabled in Respira settings.',
|
|
2667
2716
|
},
|
|
2668
2717
|
approval_token: {
|
|
2669
2718
|
type: 'string',
|
|
@@ -2751,12 +2800,20 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
2751
2800
|
type: 'number',
|
|
2752
2801
|
description: 'Original post ID',
|
|
2753
2802
|
},
|
|
2803
|
+
post_id: {
|
|
2804
|
+
type: 'number',
|
|
2805
|
+
description: 'Alias for original_id, matching tools that operate on any post type',
|
|
2806
|
+
},
|
|
2807
|
+
page_id: {
|
|
2808
|
+
type: 'number',
|
|
2809
|
+
description: 'Alias for original_id, matching the builder page tools',
|
|
2810
|
+
},
|
|
2754
2811
|
suffix: {
|
|
2755
2812
|
type: 'string',
|
|
2756
2813
|
description: 'Optional suffix',
|
|
2757
2814
|
},
|
|
2758
2815
|
},
|
|
2759
|
-
required: [
|
|
2816
|
+
required: [],
|
|
2760
2817
|
},
|
|
2761
2818
|
annotations: {
|
|
2762
2819
|
title: "Duplicate Post",
|
|
@@ -3081,7 +3138,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
3081
3138
|
},
|
|
3082
3139
|
{
|
|
3083
3140
|
name: 'wordpress_delete_post',
|
|
3084
|
-
description: 'Delete a post. IMPORTANT: By default, this only works on Respira-created duplicates. To delete an original: pass `force=true` AND `confirm_live_edit=true`. The "Allow Direct Editing" setting in Respira must also be enabled (disabled by default for safety).\n\nApproval flow: destructive — the FIRST call returns `code: respira_approval_required` with `data.approval_request.approval_token`, and deletes nothing. Pass that exact token back via the `approval_token` param on the next call to complete the delete. Deleting a Respira-created duplicate still takes both calls; the approval gate runs before the duplicate check.\n\
|
|
3141
|
+
description: 'Delete a post. IMPORTANT: By default, this only works on Respira-created duplicates. To delete an original: pass `force=true` AND `confirm_live_edit=true`. The "Allow Direct Editing" setting in Respira must also be enabled (disabled by default for safety).\n\nApproval flow: destructive — the FIRST call returns `code: respira_approval_required` with `data.approval_request.approval_token`, and deletes nothing. Pass that exact token back via the `approval_token` param on the next call to complete the delete. Deleting a Respira-created duplicate still takes both calls; the approval gate runs before the duplicate check.\n\nThe response is always the site\'s answer: the approval token, the refusal reason, or the success flag.',
|
|
3085
3142
|
inputSchema: {
|
|
3086
3143
|
type: 'object',
|
|
3087
3144
|
properties: {
|
|
@@ -3324,7 +3381,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
3324
3381
|
},
|
|
3325
3382
|
mode: {
|
|
3326
3383
|
type: 'string',
|
|
3327
|
-
description: 'replace (default): OVERWRITES all existing page content. append: adds new content after existing elements, preserving the current layout.
|
|
3384
|
+
description: 'replace (default): OVERWRITES all existing page content. append: adds new content after existing elements, preserving the current layout. Replacing a page that already has content requires confirm_replace=true.',
|
|
3328
3385
|
enum: ['replace', 'append'],
|
|
3329
3386
|
},
|
|
3330
3387
|
confirm_replace: {
|
|
@@ -3660,6 +3717,57 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
3660
3717
|
openWorldHint: false,
|
|
3661
3718
|
},
|
|
3662
3719
|
},
|
|
3720
|
+
{
|
|
3721
|
+
// The client report. Before 9.0 it existed only as the ability
|
|
3722
|
+
// respira/generate-activity-report, which invoke_ability cannot reach
|
|
3723
|
+
// (the inhale gate refuses it), so every skill that asked for it
|
|
3724
|
+
// failed at step 1.
|
|
3725
|
+
name: 'wordpress_generate_activity_report',
|
|
3726
|
+
description: 'Generate the client report for a period from this site\'s Respira activity log: what changed, through which tools and builders, concrete before and after examples, notable moments, and time saved against per-tool manual baselines. Returns structured data for you to write up in the chosen framing, such as an agency client report or a personal recap. Reads the log and changes nothing. Defaults to the last 30 days. Needs an administrator key.',
|
|
3727
|
+
inputSchema: {
|
|
3728
|
+
type: 'object',
|
|
3729
|
+
properties: {
|
|
3730
|
+
window_days: { type: 'integer', minimum: 1, maximum: 365, description: 'Days back from now. Default 30. Ignored when start_date and end_date are given.' },
|
|
3731
|
+
start_date: { type: 'string', description: 'ISO 8601 start date. Use with end_date.' },
|
|
3732
|
+
end_date: { type: 'string', description: 'ISO 8601 end date. Use with start_date.' },
|
|
3733
|
+
content_types: {
|
|
3734
|
+
type: 'array',
|
|
3735
|
+
items: { type: 'string', enum: ['pages', 'posts', 'products', 'variables', 'snapshots', 'migrations', 'audits', 'skills'] },
|
|
3736
|
+
description: 'Limit the report to these content types. Default all.',
|
|
3737
|
+
},
|
|
3738
|
+
scope: {
|
|
3739
|
+
type: 'object',
|
|
3740
|
+
properties: {
|
|
3741
|
+
page_ids: { type: 'array', items: { type: 'integer' } },
|
|
3742
|
+
post_ids: { type: 'array', items: { type: 'integer' } },
|
|
3743
|
+
product_ids: { type: 'array', items: { type: 'integer' } },
|
|
3744
|
+
builder: { type: 'string' },
|
|
3745
|
+
},
|
|
3746
|
+
description: 'Focus on specific page, post or product IDs, or on one page builder by slug.',
|
|
3747
|
+
},
|
|
3748
|
+
framing: {
|
|
3749
|
+
type: 'string',
|
|
3750
|
+
enum: ['personal_recap', 'agency_client_report', 'agency_case_study', 'team_report', 'testimonial_draft', 'build_in_public'],
|
|
3751
|
+
description: 'Who the write-up is for. Default personal_recap; use agency_client_report for a client.',
|
|
3752
|
+
},
|
|
3753
|
+
output_mode: { type: 'string', enum: ['structured', 'client_report', 'ops_report'], description: 'structured returns the data; client_report and ops_report add ready-made sections.' },
|
|
3754
|
+
report_tone: { type: 'string', enum: ['client_update', 'retainer_proof', 'internal_ops'], description: 'Tone for the ready-made sections.' },
|
|
3755
|
+
client_name: { type: 'string', description: 'Who an agency report is addressed to.' },
|
|
3756
|
+
include_examples: { type: 'boolean', description: 'Up to 10 edits with 200-character before and after excerpts. Default true.' },
|
|
3757
|
+
include_time_estimates: { type: 'boolean', description: 'Estimate time saved from per-tool baselines. Default true.' },
|
|
3758
|
+
anonymize: { type: 'boolean', description: 'Redact page titles, URLs and excerpts, for a report that will be published. Default false.' },
|
|
3759
|
+
currency: { type: 'string', description: 'ISO 4217 code for the cost estimate. Default EUR.' },
|
|
3760
|
+
hourly_rate: { type: 'number', description: 'When set, time savings include a cost estimate at this hourly rate.' },
|
|
3761
|
+
},
|
|
3762
|
+
},
|
|
3763
|
+
annotations: {
|
|
3764
|
+
title: "Generate Activity Report",
|
|
3765
|
+
readOnlyHint: true,
|
|
3766
|
+
destructiveHint: false,
|
|
3767
|
+
idempotentHint: true,
|
|
3768
|
+
openWorldHint: false,
|
|
3769
|
+
},
|
|
3770
|
+
},
|
|
3663
3771
|
{
|
|
3664
3772
|
name: 'wordpress_get_site_template',
|
|
3665
3773
|
description: 'Read one FSE template or template part as normalized blocks. Returns its source, render route, supported targeted operations, and expected_fingerprint for safe updates.',
|
|
@@ -4640,7 +4748,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
4640
4748
|
},
|
|
4641
4749
|
{
|
|
4642
4750
|
name: 'wordpress_diagnose_connection',
|
|
4643
|
-
description: 'Run a connection-fingerprint diagnostic for the active site. Combines the plugin\'s server-side report (route registration, php/wp/plugin versions, edge plugin presence) with outside-in probes from the MCP server (REST root reachability, content-type sanity check on Respira routes, edge-layer headers). Use when a tool returns "html instead of json", an opaque 5xx, or when a connection that worked yesterday silently breaks. ALSO use it when the user suspects the wrong site, a stale connection, or a setup step that "did nothing": the response carries transport_mode (which install is answering: mcpb_bundle, npx_cache, global_npm_install, project_local_install, source_checkout), transport.duplicate_entries (whether a second Respira server is running, which usually means the client config lists Respira twice), and client_config (which config source won and how many sites came out of it). Returns a structured object including detected edge layers (Cloudflare, Wordfence, Sucuri) and concrete remediation recommendations.',
|
|
4751
|
+
description: 'Run a connection-fingerprint diagnostic for the active site. Combines the plugin\'s server-side report (route registration, php/wp/plugin versions, edge plugin presence) with outside-in probes from the MCP server (REST root reachability, content-type sanity check on Respira routes, edge-layer headers). Use when a tool returns "html instead of json", an opaque 5xx, or when a connection that worked yesterday silently breaks. ALSO use it when the user suspects the wrong site, a stale connection, or a setup step that "did nothing": the response carries transport_mode (which install is answering: mcpb_bundle, npx_cache, global_npm_install, project_local_install, source_checkout), transport.duplicate_entries (whether a second Respira server is running, which usually means the client config lists Respira twice), and client_config (which config source won and how many sites came out of it). Returns a structured object including detected edge layers (Cloudflare, Wordfence, Sucuri) and concrete remediation recommendations. It also reports well_known_discovery: whether the host answers /.well-known/oauth-protected-resource itself instead of letting WordPress answer it, which is what breaks a ChatGPT connection on a site whose plugin is working, since ChatGPT checks only that address.',
|
|
4644
4752
|
inputSchema: {
|
|
4645
4753
|
type: 'object',
|
|
4646
4754
|
properties: {
|
|
@@ -4650,7 +4758,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
4650
4758
|
},
|
|
4651
4759
|
probe_timeout_ms: {
|
|
4652
4760
|
type: 'number',
|
|
4653
|
-
description: 'Optional per-probe timeout in milliseconds. Default 30000
|
|
4761
|
+
description: 'Optional per-probe timeout in milliseconds. Default 30000. Clamped to [5000, 60000]. Bump this when probing sites behind slow edge layers (some Cloudflare custom rules add 8+ seconds before forwarding to origin).',
|
|
4654
4762
|
minimum: 5000,
|
|
4655
4763
|
maximum: 60000,
|
|
4656
4764
|
},
|
|
@@ -4786,31 +4894,35 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
4786
4894
|
},
|
|
4787
4895
|
},
|
|
4788
4896
|
{
|
|
4897
|
+
// Until 9.0 this returned a heuristic estimate from static page
|
|
4898
|
+
// analysis. AER's "what a visitor notices first" shortcut and three
|
|
4899
|
+
// skills call it by name expecting field data, so it now runs the real
|
|
4900
|
+
// PageSpeed Insights audit instead of being removed.
|
|
4789
4901
|
name: 'wordpress_get_core_web_vitals',
|
|
4790
|
-
description: '
|
|
4902
|
+
description: 'Core Web Vitals for a page, measured by Google PageSpeed Insights: LCP, CLS and INP from real Chrome users over the last 28 days when Google publishes field data for the URL, plus Lighthouse lab metrics. Runs the same audit as respira_run_pagespeed_audit with one strategy, so the page must be publicly reachable; drafts and local sites return an error that says so. Cached for 1 hour per URL and strategy.',
|
|
4791
4903
|
inputSchema: {
|
|
4792
4904
|
type: 'object',
|
|
4793
4905
|
properties: {
|
|
4794
|
-
page_id: {
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
},
|
|
4906
|
+
page_id: { type: 'number', description: 'Page ID to measure. Resolved to its public permalink.' },
|
|
4907
|
+
url: { type: 'string', description: 'Explicit public URL to measure instead of a page ID.' },
|
|
4908
|
+
strategy: { type: 'string', enum: ['mobile', 'desktop'], default: 'mobile', description: 'Device profile. Default mobile.' },
|
|
4798
4909
|
},
|
|
4799
|
-
|
|
4910
|
+
anyOf: [
|
|
4911
|
+
{ required: ['page_id'] },
|
|
4912
|
+
{ required: ['url'] },
|
|
4913
|
+
],
|
|
4800
4914
|
},
|
|
4801
4915
|
annotations: {
|
|
4802
4916
|
title: "Core Web Vitals",
|
|
4803
4917
|
readOnlyHint: true,
|
|
4804
4918
|
destructiveHint: false,
|
|
4805
4919
|
idempotentHint: true,
|
|
4806
|
-
openWorldHint:
|
|
4920
|
+
openWorldHint: true,
|
|
4807
4921
|
},
|
|
4808
4922
|
},
|
|
4809
4923
|
{
|
|
4810
|
-
//
|
|
4811
|
-
//
|
|
4812
|
-
// Lighthouse lab data + CrUX field data (when available) + the
|
|
4813
|
-
// opportunity list ranked by metric savings.
|
|
4924
|
+
// Real PageSpeed Insights v5 audit: Lighthouse lab data, CrUX field
|
|
4925
|
+
// data when available, and opportunities ranked by metric savings.
|
|
4814
4926
|
name: 'wordpress_run_pagespeed_audit',
|
|
4815
4927
|
description: 'Run a real PageSpeed Insights v5 audit against a public URL. Returns Lighthouse lab data (scores for performance/accessibility/best-practices/seo, lab metrics FCP/LCP/TBT/CLS/SI/TTI, opportunities ranked by savings_ms, diagnostics) plus CrUX field data (real-user p75 metrics over the trailing ~28 days, when Google has enough traffic to publish them for the URL). Cached for 1 hour per (url, strategy). Pass `fresh=true` to bypass the cache. `strategy="both"` runs mobile + desktop in series. Set the `respira_pagespeed_api_key` WordPress option to lift the 1 req/sec free-tier rate limit to 200 req/min.',
|
|
4816
4928
|
inputSchema: {
|
|
@@ -4836,9 +4948,8 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
4836
4948
|
},
|
|
4837
4949
|
},
|
|
4838
4950
|
{
|
|
4839
|
-
//
|
|
4840
|
-
//
|
|
4841
|
-
// `pagespeed` slot. Use for periodic site-wide health passes; use
|
|
4951
|
+
// Standard-analyzer-envelope wrapper around PSI. Feeds the Health tab
|
|
4952
|
+
// composite via Respira_Site_Health's `pagespeed` slot. Use for periodic site-wide health passes; use
|
|
4842
4953
|
// `respira_run_pagespeed_audit` for the raw lab+field data.
|
|
4843
4954
|
name: 'wordpress_analyze_pagespeed',
|
|
4844
4955
|
description: 'Analyzer-envelope wrapper around the PSI audit. Returns the standard `{success, score, grade, issues, recommendations, metrics, data_source, measured_at}` shape that the Reports → Health tab consumes. Score = Lighthouse performance score (0-100). Grade A≥90, B≥75, C≥60, D≥40, F<40. Issues derived from Lighthouse opportunities, ranked by savings_ms. CrUX p75 field-data surfaces as an info-priority recommendation when available.',
|
|
@@ -5016,7 +5127,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5016
5127
|
// Safety & Security center
|
|
5017
5128
|
{
|
|
5018
5129
|
name: 'wordpress_run_security_audit',
|
|
5019
|
-
description: 'Run a bounded
|
|
5130
|
+
description: 'Run a bounded WordPress security audit. Returns authoritative WordPress/WooCommerce versions, official core checksum mismatches, administrators and account hygiene, standard and must-use plugins, themes, WordPress cron hooks, advisory indicators, scan coverage and explicit host-level limitations. The audit reads and never changes the site, deep_scan included. One flag writes: probe_uploads_execution, off by default, puts one inert PHP file in uploads, requests it to learn whether PHP runs there, then deletes it. The result includes known_vulnerabilities: installed core, plugins and themes matched against the Respira vulnerability database for a licensed site, with status ok or unavailable. An unavailable status never means the site is clean. known_vulnerabilities=false skips that match. On plugins older than 9.0, deep_scan also runs the uploads probe.',
|
|
5020
5131
|
inputSchema: {
|
|
5021
5132
|
type: 'object',
|
|
5022
5133
|
properties: {
|
|
@@ -5028,7 +5139,17 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5028
5139
|
deep_scan: {
|
|
5029
5140
|
type: 'boolean',
|
|
5030
5141
|
default: false,
|
|
5031
|
-
description: 'Inspect uploads and must-use plugin paths with strict file, time, symlink and result limits.',
|
|
5142
|
+
description: 'Inspect uploads and must-use plugin paths for executable files, with strict file, time, symlink and result limits. Reads only on plugin 9.0 and newer.',
|
|
5143
|
+
},
|
|
5144
|
+
probe_uploads_execution: {
|
|
5145
|
+
type: 'boolean',
|
|
5146
|
+
default: false,
|
|
5147
|
+
description: 'Writes one inert PHP file into uploads, requests it to test whether PHP executes there, then deletes it. Off by default. File-change monitors such as Wordfence may report the file. Needs plugin 9.0 or newer; older plugins ignore it.',
|
|
5148
|
+
},
|
|
5149
|
+
known_vulnerabilities: {
|
|
5150
|
+
type: 'boolean',
|
|
5151
|
+
default: true,
|
|
5152
|
+
description: 'Match installed core, plugins and themes against the Respira vulnerability database. On by default; false skips that round trip. Needs plugin 9.0 or newer.',
|
|
5032
5153
|
},
|
|
5033
5154
|
},
|
|
5034
5155
|
},
|
|
@@ -5042,17 +5163,17 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5042
5163
|
},
|
|
5043
5164
|
{
|
|
5044
5165
|
name: 'wordpress_update_core_security',
|
|
5045
|
-
description: 'Update WordPress core to
|
|
5166
|
+
description: 'Update WordPress core to the security release WordPress.org offers on the site\'s current release branch. Requires a recent recoverable backup, then explicit two-step approval. The first call returns respira_approval_required and an approval_token; repeat the same arguments with that token. The result verifies the running version, REST/frontend boot and official checksums. WordPress core has no automatic rollback, and the receipt says so. Plugins older than 9.0 accept only the releases in their own catalog.',
|
|
5046
5167
|
inputSchema: {
|
|
5047
5168
|
type: 'object',
|
|
5048
5169
|
properties: {
|
|
5049
5170
|
advisory_id: {
|
|
5050
5171
|
type: 'string',
|
|
5051
|
-
description: '
|
|
5172
|
+
description: 'Security advisory ID from respira_run_security_audit, recorded on the receipt. Do not guess it: run the audit first and use the advisory it reports.',
|
|
5052
5173
|
},
|
|
5053
5174
|
target_version: {
|
|
5054
5175
|
type: 'string',
|
|
5055
|
-
description: '
|
|
5176
|
+
description: 'The exact version WordPress.org offers as the update on this site\'s own release branch, as reported by respira_run_security_audit. The plugin refuses any other version and never moves a site across branches.',
|
|
5056
5177
|
},
|
|
5057
5178
|
backup_confirmed: {
|
|
5058
5179
|
type: 'boolean',
|
|
@@ -5073,6 +5194,60 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5073
5194
|
openWorldHint: true,
|
|
5074
5195
|
},
|
|
5075
5196
|
},
|
|
5197
|
+
{
|
|
5198
|
+
name: 'wordpress_update_theme',
|
|
5199
|
+
description: 'Update a theme to the latest version offered to this site, then check that the site still answers (REST API, front page, fatal-error marker). Requires plugin management to be enabled in Respira settings. Approval-gated: the first call returns `respira_approval_required` with an `approval_token`; call again with the same `stylesheet` plus that token. If the result carries `stop_batch: true`, stop updating and check the site. There is no automatic rollback.',
|
|
5200
|
+
inputSchema: {
|
|
5201
|
+
type: 'object',
|
|
5202
|
+
properties: {
|
|
5203
|
+
stylesheet: {
|
|
5204
|
+
type: 'string',
|
|
5205
|
+
description: 'Theme directory name (its stylesheet), as respira_run_security_audit lists it under checks.themes.',
|
|
5206
|
+
},
|
|
5207
|
+
approval_token: {
|
|
5208
|
+
type: 'string',
|
|
5209
|
+
description: 'Second-step approval token returned by the first call. Echo it back unchanged with the same stylesheet.',
|
|
5210
|
+
},
|
|
5211
|
+
},
|
|
5212
|
+
required: ['stylesheet'],
|
|
5213
|
+
},
|
|
5214
|
+
annotations: {
|
|
5215
|
+
title: "Update Theme",
|
|
5216
|
+
readOnlyHint: false,
|
|
5217
|
+
destructiveHint: true,
|
|
5218
|
+
idempotentHint: true,
|
|
5219
|
+
openWorldHint: true,
|
|
5220
|
+
},
|
|
5221
|
+
},
|
|
5222
|
+
{
|
|
5223
|
+
name: 'wordpress_revoke_application_password',
|
|
5224
|
+
description: 'Revoke one WordPress application password, by user id and uuid as respira_run_security_audit reports them under checks.account_hygiene. Anything that signs in with it stops working and it cannot be restored. Approval-gated: the first call returns `respira_approval_required` with an `approval_token`; call again with the same arguments plus that token. The password this request itself signed in with is refused.',
|
|
5225
|
+
inputSchema: {
|
|
5226
|
+
type: 'object',
|
|
5227
|
+
properties: {
|
|
5228
|
+
user_id: {
|
|
5229
|
+
type: 'integer',
|
|
5230
|
+
description: 'The user the application password belongs to.',
|
|
5231
|
+
},
|
|
5232
|
+
uuid: {
|
|
5233
|
+
type: 'string',
|
|
5234
|
+
description: 'The application password uuid from the security audit. Never the password itself.',
|
|
5235
|
+
},
|
|
5236
|
+
approval_token: {
|
|
5237
|
+
type: 'string',
|
|
5238
|
+
description: 'Second-step approval token returned by the first call. Echo it back unchanged with the same user_id and uuid.',
|
|
5239
|
+
},
|
|
5240
|
+
},
|
|
5241
|
+
required: ['user_id', 'uuid'],
|
|
5242
|
+
},
|
|
5243
|
+
annotations: {
|
|
5244
|
+
title: "Revoke Application Password",
|
|
5245
|
+
readOnlyHint: false,
|
|
5246
|
+
destructiveHint: true,
|
|
5247
|
+
idempotentHint: true,
|
|
5248
|
+
openWorldHint: false,
|
|
5249
|
+
},
|
|
5250
|
+
},
|
|
5076
5251
|
// Accessibility tools
|
|
5077
5252
|
{
|
|
5078
5253
|
name: 'wordpress_list_accessibility_scans',
|
|
@@ -5155,10 +5330,12 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5155
5330
|
openWorldHint: false,
|
|
5156
5331
|
},
|
|
5157
5332
|
},
|
|
5158
|
-
// Plugin Management tools
|
|
5333
|
+
// Plugin Management tools. The EXPERIMENTAL label came off in 9.0: every
|
|
5334
|
+
// mutation is approval-gated, and activation has probed the site and
|
|
5335
|
+
// rolled itself back on failure since plugin 8.5.5.
|
|
5159
5336
|
{
|
|
5160
5337
|
name: 'wordpress_list_plugins',
|
|
5161
|
-
description: '
|
|
5338
|
+
description: 'List all installed plugins with their status, version, and update availability. Requires plugin management to be enabled in Respira settings.',
|
|
5162
5339
|
inputSchema: {
|
|
5163
5340
|
type: 'object',
|
|
5164
5341
|
properties: {},
|
|
@@ -5173,7 +5350,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5173
5350
|
},
|
|
5174
5351
|
{
|
|
5175
5352
|
name: 'wordpress_install_plugin',
|
|
5176
|
-
description: '
|
|
5353
|
+
description: 'Install a plugin from WordPress.org or a ZIP URL. Requires plugin management to be enabled in Respira settings. Approval-gated: first call returns `respira_approval_required` with an `approval_token`; call again with that token to complete the install. Install only what the site owner asked for.',
|
|
5177
5354
|
inputSchema: {
|
|
5178
5355
|
type: 'object',
|
|
5179
5356
|
properties: {
|
|
@@ -5203,13 +5380,13 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5203
5380
|
},
|
|
5204
5381
|
{
|
|
5205
5382
|
name: 'wordpress_activate_plugin',
|
|
5206
|
-
description: '
|
|
5383
|
+
description: 'Safely activate a plugin. Respira checks declared PHP, WordPress, dependency and companion-plugin compatibility, activates in a fresh loopback request, probes REST and frontend boot, and automatically deactivates the plugin if the site fails. Approval-gated. Use force_without_probe only after explicit operator approval on a host that blocks loopback requests.',
|
|
5207
5384
|
inputSchema: {
|
|
5208
5385
|
type: 'object',
|
|
5209
5386
|
properties: {
|
|
5210
5387
|
slug: {
|
|
5211
5388
|
type: 'string',
|
|
5212
|
-
description: 'Plugin
|
|
5389
|
+
description: 'Plugin folder name, or the exact plugin file wordpress_list_plugins reports. Both work, including names with spaces and capitals ("WP PROTECTION" or "WP PROTECTION/SECURITY.php"). Do not sanitize the name yourself: pass it exactly as WordPress spells it.',
|
|
5213
5390
|
},
|
|
5214
5391
|
approval_token: {
|
|
5215
5392
|
type: 'string',
|
|
@@ -5232,13 +5409,13 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5232
5409
|
},
|
|
5233
5410
|
{
|
|
5234
5411
|
name: 'wordpress_deactivate_plugin',
|
|
5235
|
-
description: '
|
|
5412
|
+
description: 'Deactivate a plugin. Requires plugin management to be enabled in Respira settings. Approval-gated: first call returns `respira_approval_required` with an `approval_token`; call again with the same `slug` plus that token to complete deactivation.',
|
|
5236
5413
|
inputSchema: {
|
|
5237
5414
|
type: 'object',
|
|
5238
5415
|
properties: {
|
|
5239
5416
|
slug: {
|
|
5240
5417
|
type: 'string',
|
|
5241
|
-
description: 'Plugin
|
|
5418
|
+
description: 'Plugin folder name, or the exact plugin file wordpress_list_plugins reports. Both work, including names with spaces and capitals ("WP PROTECTION" or "WP PROTECTION/SECURITY.php"). Do not sanitize the name yourself: pass it exactly as WordPress spells it.',
|
|
5242
5419
|
},
|
|
5243
5420
|
approval_token: {
|
|
5244
5421
|
type: 'string',
|
|
@@ -5257,13 +5434,13 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5257
5434
|
},
|
|
5258
5435
|
{
|
|
5259
5436
|
name: 'wordpress_update_plugin',
|
|
5260
|
-
description: '
|
|
5437
|
+
description: 'Update a plugin to the latest version. Requires plugin management to be enabled in Respira settings. Approval-gated: first call returns `respira_approval_required` with an `approval_token`; call again with the same `slug` plus that token to complete the update. Make sure a recent backup exists before updating, and load the front page afterwards to confirm the site still renders.',
|
|
5261
5438
|
inputSchema: {
|
|
5262
5439
|
type: 'object',
|
|
5263
5440
|
properties: {
|
|
5264
5441
|
slug: {
|
|
5265
5442
|
type: 'string',
|
|
5266
|
-
description: 'Plugin
|
|
5443
|
+
description: 'Plugin folder name, or the exact plugin file wordpress_list_plugins reports. Both work, including names with spaces and capitals ("WP PROTECTION" or "WP PROTECTION/SECURITY.php"). Do not sanitize the name yourself: pass it exactly as WordPress spells it.',
|
|
5267
5444
|
},
|
|
5268
5445
|
approval_token: {
|
|
5269
5446
|
type: 'string',
|
|
@@ -5282,13 +5459,13 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5282
5459
|
},
|
|
5283
5460
|
{
|
|
5284
5461
|
name: 'wordpress_delete_plugin',
|
|
5285
|
-
description: '
|
|
5462
|
+
description: 'Permanently delete a plugin. Requires plugin management to be enabled in Respira settings. The plugin must be deactivated first. Approval-gated: first call returns `respira_approval_required` with an `approval_token`; call again with the same `slug` plus that token to confirm deletion.',
|
|
5286
5463
|
inputSchema: {
|
|
5287
5464
|
type: 'object',
|
|
5288
5465
|
properties: {
|
|
5289
5466
|
slug: {
|
|
5290
5467
|
type: 'string',
|
|
5291
|
-
description: 'Plugin
|
|
5468
|
+
description: 'Plugin folder name, or the exact plugin file wordpress_list_plugins reports. Both work, including names with spaces and capitals ("WP PROTECTION" or "WP PROTECTION/SECURITY.php"). Do not sanitize the name yourself: pass it exactly as WordPress spells it.',
|
|
5292
5469
|
},
|
|
5293
5470
|
approval_token: {
|
|
5294
5471
|
type: 'string',
|
|
@@ -5357,7 +5534,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5357
5534
|
},
|
|
5358
5535
|
{
|
|
5359
5536
|
name: 'wordpress_create_user',
|
|
5360
|
-
description: 'Create a new user.\n\nApproval flow
|
|
5537
|
+
description: 'Create a new user.\n\nApproval flow: the first call returns `code: respira_approval_required` with `data.approval_request.approval_token`. Pass that token back via the `approval_token` param on the next call to complete the create.',
|
|
5361
5538
|
inputSchema: {
|
|
5362
5539
|
type: 'object',
|
|
5363
5540
|
properties: {
|
|
@@ -5394,7 +5571,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5394
5571
|
},
|
|
5395
5572
|
{
|
|
5396
5573
|
name: 'wordpress_update_user',
|
|
5397
|
-
description: 'Update user information.\n\nApproval flow
|
|
5574
|
+
description: 'Update user information.\n\nApproval flow: the first call returns `respira_approval_required` with `approval_token`; pass it back to complete the update.',
|
|
5398
5575
|
inputSchema: {
|
|
5399
5576
|
type: 'object',
|
|
5400
5577
|
properties: {
|
|
@@ -5435,7 +5612,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
5435
5612
|
},
|
|
5436
5613
|
{
|
|
5437
5614
|
name: 'wordpress_delete_user',
|
|
5438
|
-
description: 'Delete a user.\n\nApproval flow
|
|
5615
|
+
description: 'Delete a user.\n\nApproval flow: the first call returns `respira_approval_required` with `approval_token`; pass it back to complete the delete.',
|
|
5439
5616
|
inputSchema: {
|
|
5440
5617
|
type: 'object',
|
|
5441
5618
|
properties: {
|
|
@@ -6531,7 +6708,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
6531
6708
|
},
|
|
6532
6709
|
{
|
|
6533
6710
|
name: 'wordpress_delete_custom_post',
|
|
6534
|
-
description: 'Delete a custom post.\n\nSafety flow
|
|
6711
|
+
description: 'Delete a custom post.\n\nSafety flow: by default this only works on Respira-created duplicates. To delete an original: pass `force=true` AND `confirm_live_edit=true` (the latter requires "Allow Direct Editing" enabled in Respira settings). The approval gate may also fire: if the response is `respira_approval_required`, pass the returned `approval_token` back to complete the delete.',
|
|
6535
6712
|
inputSchema: {
|
|
6536
6713
|
type: 'object',
|
|
6537
6714
|
properties: {
|
|
@@ -6610,7 +6787,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
6610
6787
|
},
|
|
6611
6788
|
{
|
|
6612
6789
|
name: 'wordpress_update_option',
|
|
6613
|
-
description: 'Update an option value.',
|
|
6790
|
+
description: 'Update an option value. Send the value in the same type get_option returns. A string stays a string, even when it contains JSON, because many plugins store JSON as text and decode it themselves. Send an object or array only for options that already hold one, such as theme_mods. Writing an object or array over an option that holds text is refused unless allow_type_change is true.',
|
|
6614
6791
|
inputSchema: {
|
|
6615
6792
|
type: 'object',
|
|
6616
6793
|
properties: {
|
|
@@ -6619,7 +6796,15 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
6619
6796
|
description: 'Option name',
|
|
6620
6797
|
},
|
|
6621
6798
|
value: {
|
|
6622
|
-
description: 'Option value
|
|
6799
|
+
description: 'Option value, in the type get_option returns for this option. Text stays text (JSON-encode it if needed). Objects or arrays only for options that already hold them, such as theme_mods.',
|
|
6800
|
+
},
|
|
6801
|
+
allow_type_change: {
|
|
6802
|
+
type: 'boolean',
|
|
6803
|
+
description: 'Set true only to really replace an option that holds text with an object or array. Without it that write is refused, because a plugin that decodes its own text option can crash on every page load.',
|
|
6804
|
+
},
|
|
6805
|
+
allow_object_overwrite: {
|
|
6806
|
+
type: 'boolean',
|
|
6807
|
+
description: 'Set true only to replace an option that stores a PHP object, and only when the new value keeps the same shape. Without it that write is refused.',
|
|
6623
6808
|
},
|
|
6624
6809
|
},
|
|
6625
6810
|
required: ['option', 'value'],
|
|
@@ -6771,7 +6956,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
6771
6956
|
},
|
|
6772
6957
|
{
|
|
6773
6958
|
name: 'wordpress_delete_media',
|
|
6774
|
-
description: 'Delete a media file. Approval-gated
|
|
6959
|
+
description: 'Delete a media file. Approval-gated: the first call returns `code: respira_approval_required` with an `approval_token`; pass that token in the second call to confirm. Same flow as `delete_page` / `delete_user` / `delete_plugin`.',
|
|
6775
6960
|
inputSchema: {
|
|
6776
6961
|
type: 'object',
|
|
6777
6962
|
properties: {
|
|
@@ -6891,7 +7076,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
6891
7076
|
},
|
|
6892
7077
|
{
|
|
6893
7078
|
name: 'wordpress_delete_menu',
|
|
6894
|
-
description: 'Delete a navigation menu.\n\nApproval flow
|
|
7079
|
+
description: 'Delete a navigation menu.\n\nApproval flow: the first call returns `respira_approval_required` with `approval_token`; pass it back to complete the delete.',
|
|
6895
7080
|
inputSchema: {
|
|
6896
7081
|
type: 'object',
|
|
6897
7082
|
properties: {
|
|
@@ -7156,9 +7341,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
7156
7341
|
}
|
|
7157
7342
|
// Generate respira_* aliases for all wordpress_* tools.
|
|
7158
7343
|
const allTools = this.generateDualTools(tools);
|
|
7159
|
-
// Context-aware tool filtering:
|
|
7160
|
-
//
|
|
7161
|
-
//
|
|
7344
|
+
// Context-aware tool filtering: builder-specific tools appear only on the
|
|
7345
|
+
// builder they serve, and WooCommerce tools only where WooCommerce runs.
|
|
7346
|
+
// When the site context cannot be read, everything is shown (fail-open).
|
|
7347
|
+
// The README's "Tools on one site" table has the measured counts.
|
|
7162
7348
|
return this.filterToolsByContext(allTools);
|
|
7163
7349
|
}
|
|
7164
7350
|
/**
|
|
@@ -7719,25 +7905,6 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
7719
7905
|
openWorldHint: false,
|
|
7720
7906
|
},
|
|
7721
7907
|
},
|
|
7722
|
-
{
|
|
7723
|
-
name: 'woocommerce_sales_report',
|
|
7724
|
-
description: 'Deprecated compatibility alias for woocommerce_revenue_summary. Retained for two minor releases.',
|
|
7725
|
-
inputSchema: {
|
|
7726
|
-
type: 'object',
|
|
7727
|
-
properties: {
|
|
7728
|
-
period: { type: 'string', description: 'week, month, year, custom' },
|
|
7729
|
-
date_min: { type: 'string', description: 'Start date for custom period' },
|
|
7730
|
-
date_max: { type: 'string', description: 'End date for custom period' },
|
|
7731
|
-
},
|
|
7732
|
-
},
|
|
7733
|
-
annotations: {
|
|
7734
|
-
title: "Sales Report",
|
|
7735
|
-
readOnlyHint: true,
|
|
7736
|
-
destructiveHint: false,
|
|
7737
|
-
idempotentHint: true,
|
|
7738
|
-
openWorldHint: false,
|
|
7739
|
-
},
|
|
7740
|
-
},
|
|
7741
7908
|
{
|
|
7742
7909
|
name: 'woocommerce_revenue_summary',
|
|
7743
7910
|
description: 'Bounded HPOS-compatible revenue summary with currency, store timezone, exact date boundaries, included statuses, pagination coverage, and explicit gross/discount/refund/tax/shipping/net definitions.',
|
|
@@ -9675,12 +9842,33 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
9675
9842
|
const preview = serialized.slice(0, Math.min(2000, cap / 2));
|
|
9676
9843
|
const paginationHint = TOOLS_WITH_PAGINATION_HINT[toolName] ||
|
|
9677
9844
|
'Try re-calling this tool with pagination args (per_page, page, search filter) to limit the result size.';
|
|
9845
|
+
// Ticket 467cb71d: "_truncated: true" and two byte counts did not say
|
|
9846
|
+
// what was lost. On a 235 KB Divi page the preview stopped inside the
|
|
9847
|
+
// first section, far above the element being worked on, and nothing in
|
|
9848
|
+
// the envelope said so. Name the share that is missing and which
|
|
9849
|
+
// top-level keys did not survive the preview at all.
|
|
9850
|
+
const cutBytes = serialized.length - preview.length;
|
|
9851
|
+
const cutPercent = Math.max(1, Math.round((cutBytes / serialized.length) * 100));
|
|
9852
|
+
const topKeys = result && typeof result === 'object' && !Array.isArray(result) ? Object.keys(result) : [];
|
|
9853
|
+
const keysInPreview = topKeys.filter((key) => preview.includes(`${JSON.stringify(key)}:`));
|
|
9854
|
+
const keysCut = topKeys.filter((key) => !keysInPreview.includes(key));
|
|
9678
9855
|
const envelope = {
|
|
9679
9856
|
_truncated: true,
|
|
9680
9857
|
_original_size_bytes: serialized.length,
|
|
9681
9858
|
_cap_bytes: cap,
|
|
9682
9859
|
_tool_name: toolName,
|
|
9683
9860
|
_preview_json: preview,
|
|
9861
|
+
_returned_bytes: preview.length,
|
|
9862
|
+
_cut_bytes: cutBytes,
|
|
9863
|
+
_cut: `This response carries the first ${preview.length} bytes of ${serialized.length}. ` +
|
|
9864
|
+
`${cutBytes} bytes, about ${cutPercent}% of the answer, are not here, ` +
|
|
9865
|
+
'and the preview stops mid-structure wherever that byte count fell.' +
|
|
9866
|
+
(keysCut.length
|
|
9867
|
+
? ` Nothing was returned for: ${keysCut.join(', ')}.`
|
|
9868
|
+
: '') +
|
|
9869
|
+
(keysInPreview.length
|
|
9870
|
+
? ` Partly present: ${keysInPreview.join(', ')}.`
|
|
9871
|
+
: ''),
|
|
9684
9872
|
_hint: paginationHint,
|
|
9685
9873
|
_why: 'Response exceeded the MCP server response-size cap. ' +
|
|
9686
9874
|
'Most MCP hosts (Claude Desktop, Cursor) silently kill the subprocess ' +
|
|
@@ -9784,11 +9972,16 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
9784
9972
|
return await client.listPages(args);
|
|
9785
9973
|
case 'wordpress_read_page':
|
|
9786
9974
|
return await client.getPage(args.id, args.include);
|
|
9787
|
-
case 'wordpress_create_page_duplicate':
|
|
9975
|
+
case 'wordpress_create_page_duplicate': {
|
|
9976
|
+
const originalId = args.original_id ?? args.page_id ?? args.post_id;
|
|
9977
|
+
if (originalId === undefined || originalId === null) {
|
|
9978
|
+
throw new Error('create_page_duplicate needs original_id, page_id, or post_id.');
|
|
9979
|
+
}
|
|
9788
9980
|
return {
|
|
9789
|
-
...(await client.duplicatePage(
|
|
9981
|
+
...(await client.duplicatePage(originalId, args.suffix, args.include)),
|
|
9790
9982
|
respira_approvals_url: client.getApprovalsUrl(),
|
|
9791
9983
|
};
|
|
9984
|
+
}
|
|
9792
9985
|
case 'wordpress_update_page': {
|
|
9793
9986
|
const approvalsUrl = client.getApprovalsUrl();
|
|
9794
9987
|
const page = await client.updatePage(args.id, args);
|
|
@@ -9817,11 +10010,19 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
9817
10010
|
return await client.listPosts(args);
|
|
9818
10011
|
case 'wordpress_read_post':
|
|
9819
10012
|
return await client.getPost(args.id, args.include);
|
|
9820
|
-
case 'wordpress_create_post_duplicate':
|
|
10013
|
+
case 'wordpress_create_post_duplicate': {
|
|
10014
|
+
// Same shape as the page tool above (ticket 81c478df): a missing id
|
|
10015
|
+
// used to reach WordPress as the literal string "undefined" in the
|
|
10016
|
+
// path, and came back as a 404 that read like a plugin problem.
|
|
10017
|
+
const originalId = args.original_id ?? args.post_id ?? args.page_id;
|
|
10018
|
+
if (originalId === undefined || originalId === null) {
|
|
10019
|
+
throw new Error('create_post_duplicate needs original_id, post_id, or page_id.');
|
|
10020
|
+
}
|
|
9821
10021
|
return {
|
|
9822
|
-
...(await client.duplicatePost(
|
|
10022
|
+
...(await client.duplicatePost(originalId, args.suffix, args.include)),
|
|
9823
10023
|
respira_approvals_url: client.getApprovalsUrl(),
|
|
9824
10024
|
};
|
|
10025
|
+
}
|
|
9825
10026
|
case 'respira_duplicate_with_translations':
|
|
9826
10027
|
return await client.duplicateWithTranslations({
|
|
9827
10028
|
post_id: args.post_id,
|
|
@@ -10092,7 +10293,11 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10092
10293
|
case 'wordpress_analyze_performance':
|
|
10093
10294
|
return await client.analyzePerformance(args.page_id);
|
|
10094
10295
|
case 'wordpress_get_core_web_vitals':
|
|
10095
|
-
return await client.getCoreWebVitals(
|
|
10296
|
+
return await client.getCoreWebVitals({
|
|
10297
|
+
page_id: args.page_id,
|
|
10298
|
+
url: args.url,
|
|
10299
|
+
strategy: args.strategy,
|
|
10300
|
+
});
|
|
10096
10301
|
case 'wordpress_run_pagespeed_audit':
|
|
10097
10302
|
return await client.runPageSpeedAudit({
|
|
10098
10303
|
page_id: args.page_id,
|
|
@@ -10124,7 +10329,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10124
10329
|
case 'wordpress_check_structured_data':
|
|
10125
10330
|
return await client.checkStructuredData(args.page_id);
|
|
10126
10331
|
case 'wordpress_run_security_audit':
|
|
10127
|
-
return await client.runSecurityAudit(args.advisory_ids || [], args.deep_scan === true);
|
|
10332
|
+
return await client.runSecurityAudit(args.advisory_ids || [], args.deep_scan === true, args.probe_uploads_execution === true, args.known_vulnerabilities !== false);
|
|
10128
10333
|
case 'wordpress_update_core_security':
|
|
10129
10334
|
return await client.updateCoreSecurity({
|
|
10130
10335
|
advisoryId: args.advisory_id,
|
|
@@ -10132,6 +10337,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10132
10337
|
backupConfirmed: args.backup_confirmed === true,
|
|
10133
10338
|
approvalToken: args.approval_token,
|
|
10134
10339
|
});
|
|
10340
|
+
case 'wordpress_update_theme':
|
|
10341
|
+
return await client.updateTheme(args.stylesheet, args.approval_token);
|
|
10342
|
+
case 'wordpress_revoke_application_password':
|
|
10343
|
+
return await client.revokeApplicationPassword(Number(args.user_id), String(args.uuid), args.approval_token);
|
|
10135
10344
|
// Accessibility
|
|
10136
10345
|
case 'wordpress_list_accessibility_scans':
|
|
10137
10346
|
return await client.listAccessibilityScans({
|
|
@@ -10145,7 +10354,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10145
10354
|
return await client.scanPageAccessibility(args.page_id, args.standard, args.url);
|
|
10146
10355
|
case 'wordpress_apply_accessibility_fixes':
|
|
10147
10356
|
return await client.applyAccessibilityFixes(args.scan_id, args.rule_ids);
|
|
10148
|
-
// Plugin Management
|
|
10357
|
+
// Plugin Management
|
|
10149
10358
|
case 'wordpress_list_plugins':
|
|
10150
10359
|
return await client.listPlugins();
|
|
10151
10360
|
case 'wordpress_install_plugin':
|
|
@@ -10274,7 +10483,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10274
10483
|
case 'wordpress_get_option':
|
|
10275
10484
|
return await client.getOption(args.option);
|
|
10276
10485
|
case 'wordpress_update_option':
|
|
10277
|
-
return await client.updateOption(args.option, args.value
|
|
10486
|
+
return await client.updateOption(args.option, args.value, {
|
|
10487
|
+
allow_type_change: args.allow_type_change,
|
|
10488
|
+
allow_object_overwrite: args.allow_object_overwrite,
|
|
10489
|
+
});
|
|
10278
10490
|
case 'wordpress_delete_option':
|
|
10279
10491
|
return await client.deleteOption(args.option, args.approval_token);
|
|
10280
10492
|
case 'wordpress_purge_cache':
|
|
@@ -10341,6 +10553,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10341
10553
|
return await client.callRestV1('GET', '/activity', args);
|
|
10342
10554
|
case 'wordpress_get_activity':
|
|
10343
10555
|
return await client.callRestV1('GET', `/activity/${args.id}`);
|
|
10556
|
+
case 'wordpress_generate_activity_report': {
|
|
10557
|
+
const { site_id: _siteId, ...reportInput } = args || {};
|
|
10558
|
+
return await client.generateActivityReport(reportInput);
|
|
10559
|
+
}
|
|
10344
10560
|
case 'wordpress_get_site_template':
|
|
10345
10561
|
return await client.callRestV2('GET', '/fse/template', args);
|
|
10346
10562
|
case 'wordpress_create_site_template':
|
|
@@ -10478,8 +10694,6 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10478
10694
|
const { id, ...payload } = args;
|
|
10479
10695
|
return await client.woocommerceUpdateStock(id, payload);
|
|
10480
10696
|
}
|
|
10481
|
-
case 'woocommerce_sales_report':
|
|
10482
|
-
return await client.woocommerceSalesReport(args);
|
|
10483
10697
|
case 'woocommerce_revenue_summary':
|
|
10484
10698
|
return await client.callRestV1('GET', '/woocommerce/reports/revenue-summary', args);
|
|
10485
10699
|
case 'woocommerce_sales_timeseries':
|
|
@@ -10891,6 +11105,19 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10891
11105
|
}
|
|
10892
11106
|
// Return isError result instead of throwing — unknown tool is an execution
|
|
10893
11107
|
// error, not a protocol error. This lets LLMs self-correct gracefully.
|
|
11108
|
+
// A tool removed in a major release answers with its replacement, so a
|
|
11109
|
+
// saved workflow or an older skill learns the new name in one turn
|
|
11110
|
+
// instead of guessing from "Unknown tool".
|
|
11111
|
+
const retired = RETIRED_TOOLS[name];
|
|
11112
|
+
if (retired) {
|
|
11113
|
+
return {
|
|
11114
|
+
__respira_is_error: true,
|
|
11115
|
+
error: `Retired tool: ${name}`,
|
|
11116
|
+
code: 'respira_tool_retired',
|
|
11117
|
+
replacement: retired.replacement,
|
|
11118
|
+
hint: `${name} was removed in ${retired.removedIn}. Call ${retired.replacement} instead. ${retired.note}`,
|
|
11119
|
+
};
|
|
11120
|
+
}
|
|
10894
11121
|
return {
|
|
10895
11122
|
__respira_is_error: true,
|
|
10896
11123
|
error: `Unknown tool: ${name}`,
|
|
@@ -10922,6 +11149,18 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10922
11149
|
type: 'string',
|
|
10923
11150
|
description: 'Optional text to narrow the result set to elements whose own text or attribute values contain it. Works for every identifier_type. It separates siblings; it cannot separate an element from an ancestor that contains it, so use identifier_type "path" when you need certainty.',
|
|
10924
11151
|
},
|
|
11152
|
+
// Ticket 467cb71d: the plugin has honoured `include` since 7.1.0
|
|
11153
|
+
// and the compact answer told agents to pass it, but it was missing
|
|
11154
|
+
// from this schema, so hosts dropped it before the call left. On a
|
|
11155
|
+
// 235 KB Divi page that left no way at all to read one element:
|
|
11156
|
+
// extract_builder_content was over the response cap and this was
|
|
11157
|
+
// the documented alternative. The element could be written and
|
|
11158
|
+
// never read, so the value had to be reconstructed from the
|
|
11159
|
+
// rendered front end, which added attributes nobody asked for.
|
|
11160
|
+
include: {
|
|
11161
|
+
type: 'string',
|
|
11162
|
+
description: 'CSV of optional response sections. Pass "content" (or "full") for the element\'s stored body: settings, attributes and children, exactly as the builder saved them. Without it the answer is a compact summary with a one-line preview, which cannot be edited from. This is the way to read one element on a page too large for extract_builder_content.',
|
|
11163
|
+
},
|
|
10925
11164
|
},
|
|
10926
11165
|
required: ['post_id', 'identifier_type', 'identifier_value'],
|
|
10927
11166
|
},
|
|
@@ -10969,7 +11208,7 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
10969
11208
|
editTarget: {
|
|
10970
11209
|
type: 'string',
|
|
10971
11210
|
enum: ['live', 'duplicate'],
|
|
10972
|
-
description: 'Deprecated camelCase alias of edit_target. Prefer edit_target. Kept
|
|
11211
|
+
description: 'Deprecated camelCase alias of edit_target. Prefer edit_target. Kept so older callers keep working.',
|
|
10973
11212
|
},
|
|
10974
11213
|
confirm_live_edit: {
|
|
10975
11214
|
type: 'boolean',
|