claude-plugin-wordpress-manager 2.3.1 → 2.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.
- package/.claude-plugin/plugin.json +15 -3
- package/CHANGELOG.md +62 -0
- package/agents/wp-content-strategist.md +104 -0
- package/agents/wp-distribution-manager.md +98 -0
- package/docs/GUIDE.md +183 -23
- package/docs/plans/2026-03-01-tier3-wcop-design.md +373 -0
- package/docs/plans/2026-03-01-tier3-wcop-implementation.md +915 -0
- package/hooks/hooks.json +18 -0
- package/package.json +18 -3
- package/servers/wp-rest-bridge/build/tools/buffer.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/buffer.js +205 -0
- package/servers/wp-rest-bridge/build/tools/comments.d.ts +6 -6
- package/servers/wp-rest-bridge/build/tools/gsc.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/gsc.js +354 -0
- package/servers/wp-rest-bridge/build/tools/index.d.ts +38 -38
- package/servers/wp-rest-bridge/build/tools/index.js +12 -0
- package/servers/wp-rest-bridge/build/tools/mailchimp.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/mailchimp.js +265 -0
- package/servers/wp-rest-bridge/build/tools/media.d.ts +2 -2
- package/servers/wp-rest-bridge/build/tools/multisite-sites.d.ts +2 -2
- package/servers/wp-rest-bridge/build/tools/plugin-repository.d.ts +1 -1
- package/servers/wp-rest-bridge/build/tools/search.d.ts +2 -2
- package/servers/wp-rest-bridge/build/tools/sendgrid.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/sendgrid.js +255 -0
- package/servers/wp-rest-bridge/build/tools/unified-content.d.ts +8 -8
- package/servers/wp-rest-bridge/build/tools/unified-taxonomies.d.ts +4 -4
- package/servers/wp-rest-bridge/build/tools/users.d.ts +6 -6
- package/servers/wp-rest-bridge/build/tools/wc-coupons.d.ts +1 -1
- package/servers/wp-rest-bridge/build/tools/wc-customers.d.ts +3 -3
- package/servers/wp-rest-bridge/build/tools/wc-orders.d.ts +4 -4
- package/servers/wp-rest-bridge/build/tools/wc-products.d.ts +8 -8
- package/servers/wp-rest-bridge/build/tools/wc-webhooks.d.ts +4 -4
- package/servers/wp-rest-bridge/build/types.d.ts +122 -0
- package/servers/wp-rest-bridge/build/wordpress.d.ts +14 -0
- package/servers/wp-rest-bridge/build/wordpress.js +151 -0
- package/servers/wp-rest-bridge/package.json +1 -0
- package/skills/wordpress-router/references/decision-tree.md +8 -2
- package/skills/wp-content/SKILL.md +2 -0
- package/skills/wp-content-attribution/SKILL.md +2 -0
- package/skills/wp-content-optimization/SKILL.md +172 -0
- package/skills/wp-content-optimization/references/content-freshness.md +234 -0
- package/skills/wp-content-optimization/references/headline-optimization.md +171 -0
- package/skills/wp-content-optimization/references/meta-optimization.md +243 -0
- package/skills/wp-content-optimization/references/readability-analysis.md +201 -0
- package/skills/wp-content-optimization/references/seo-content-scoring.md +245 -0
- package/skills/wp-content-optimization/scripts/content_optimization_inspect.mjs +237 -0
- package/skills/wp-content-repurposing/SKILL.md +1 -0
- package/skills/wp-monitoring/SKILL.md +1 -0
- package/skills/wp-programmatic-seo/SKILL.md +2 -0
- package/skills/wp-search-console/SKILL.md +121 -0
- package/skills/wp-search-console/references/competitor-gap-analysis.md +226 -0
- package/skills/wp-search-console/references/content-seo-feedback.md +181 -0
- package/skills/wp-search-console/references/gsc-setup.md +110 -0
- package/skills/wp-search-console/references/indexing-management.md +182 -0
- package/skills/wp-search-console/references/keyword-tracking.md +181 -0
- package/skills/wp-search-console/scripts/search_console_inspect.mjs +178 -0
- package/skills/wp-social-email/SKILL.md +152 -0
- package/skills/wp-social-email/references/audience-segmentation.md +173 -0
- package/skills/wp-social-email/references/buffer-social-publishing.md +124 -0
- package/skills/wp-social-email/references/content-to-distribution.md +156 -0
- package/skills/wp-social-email/references/distribution-analytics.md +208 -0
- package/skills/wp-social-email/references/mailchimp-integration.md +145 -0
- package/skills/wp-social-email/references/sendgrid-transactional.md +165 -0
- package/skills/wp-social-email/scripts/distribution_inspect.mjs +165 -0
- package/skills/wp-webhooks/SKILL.md +1 -0
package/hooks/hooks.json
CHANGED
|
@@ -60,6 +60,24 @@
|
|
|
60
60
|
"prompt": "The agent is about to DELETE a WooCommerce webhook. This will stop notifications to the configured delivery URL. Verify the user explicitly requested this deletion and understands that external integrations depending on this webhook will stop receiving events."
|
|
61
61
|
}
|
|
62
62
|
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"matcher": "mcp__wp-rest-bridge__mc_send_campaign",
|
|
66
|
+
"hooks": [
|
|
67
|
+
{
|
|
68
|
+
"type": "prompt",
|
|
69
|
+
"prompt": "The agent is about to SEND a Mailchimp email campaign. This will deliver emails to all subscribers in the target audience. Verify the user explicitly requested this send and has reviewed the campaign content. Respond 'approve' only if the send was clearly intentional."
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"matcher": "mcp__wp-rest-bridge__sg_send_email",
|
|
75
|
+
"hooks": [
|
|
76
|
+
{
|
|
77
|
+
"type": "prompt",
|
|
78
|
+
"prompt": "The agent is about to SEND an email via SendGrid. Verify the user explicitly requested this email send and the recipient list is correct. Respond 'approve' only if intentional."
|
|
79
|
+
}
|
|
80
|
+
]
|
|
63
81
|
}
|
|
64
82
|
]
|
|
65
83
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-plugin-wordpress-manager",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Unified WordPress management and development plugin for Claude Code. Orchestrates Hostinger MCP, WP REST API bridge (
|
|
3
|
+
"version": "2.6.0",
|
|
4
|
+
"description": "Unified WordPress management and development plugin for Claude Code. Orchestrates Hostinger MCP, WP REST API bridge (111 tools incl. 30 WooCommerce + 10 Multisite + 4 Webhooks + 7 Mailchimp + 5 Buffer + 6 SendGrid + 8 GSC), and WordPress.com MCP with 36 skills, 12 agents, and security hooks. v2.6.0 adds AI content optimization (headline scoring, readability, SEO scoring, content triage). Tier 3 WCOP complete.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "vinmor",
|
|
7
7
|
"email": "morreale.v@gmail.com"
|
|
@@ -41,7 +41,22 @@
|
|
|
41
41
|
"attribution",
|
|
42
42
|
"multilingual",
|
|
43
43
|
"hreflang",
|
|
44
|
-
"international-seo"
|
|
44
|
+
"international-seo",
|
|
45
|
+
"mailchimp",
|
|
46
|
+
"buffer",
|
|
47
|
+
"sendgrid",
|
|
48
|
+
"social-media",
|
|
49
|
+
"email-marketing",
|
|
50
|
+
"content-distribution",
|
|
51
|
+
"google-search-console",
|
|
52
|
+
"gsc",
|
|
53
|
+
"keyword-tracking",
|
|
54
|
+
"seo-feedback",
|
|
55
|
+
"search-analytics",
|
|
56
|
+
"content-optimization",
|
|
57
|
+
"readability",
|
|
58
|
+
"headline-scoring",
|
|
59
|
+
"content-triage"
|
|
45
60
|
],
|
|
46
61
|
"repository": {
|
|
47
62
|
"type": "git",
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { makeBufferRequest, hasBuffer } from '../wordpress.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
// ── Zod Schemas ─────────────────────────────────────────────────
|
|
4
|
+
const bufListProfilesSchema = z.object({}).strict();
|
|
5
|
+
const bufCreateUpdateSchema = z.object({
|
|
6
|
+
profile_ids: z.array(z.string())
|
|
7
|
+
.describe('Array of Buffer profile IDs to post to'),
|
|
8
|
+
text: z.string()
|
|
9
|
+
.describe('Text content of the social media post'),
|
|
10
|
+
media: z.object({
|
|
11
|
+
link: z.string().optional().describe('URL to attach'),
|
|
12
|
+
description: z.string().optional().describe('Description for the media'),
|
|
13
|
+
picture: z.string().optional().describe('URL of an image to attach'),
|
|
14
|
+
}).optional()
|
|
15
|
+
.describe('Optional media attachment (link, description, picture)'),
|
|
16
|
+
scheduled_at: z.string().optional()
|
|
17
|
+
.describe('Scheduled publish time in ISO 8601 format'),
|
|
18
|
+
shorten: z.boolean().optional()
|
|
19
|
+
.describe('Whether to shorten links in the post'),
|
|
20
|
+
}).strict();
|
|
21
|
+
const bufListPendingSchema = z.object({
|
|
22
|
+
profile_id: z.string().describe('Buffer profile ID'),
|
|
23
|
+
count: z.number().optional()
|
|
24
|
+
.describe('Number of updates to return'),
|
|
25
|
+
page: z.number().optional()
|
|
26
|
+
.describe('Page number for pagination'),
|
|
27
|
+
}).strict();
|
|
28
|
+
const bufListSentSchema = z.object({
|
|
29
|
+
profile_id: z.string().describe('Buffer profile ID'),
|
|
30
|
+
count: z.number().optional()
|
|
31
|
+
.describe('Number of updates to return'),
|
|
32
|
+
page: z.number().optional()
|
|
33
|
+
.describe('Page number for pagination'),
|
|
34
|
+
}).strict();
|
|
35
|
+
const bufGetAnalyticsSchema = z.object({
|
|
36
|
+
update_id: z.string().describe('Buffer update ID'),
|
|
37
|
+
}).strict();
|
|
38
|
+
// ── Tool Definitions ────────────────────────────────────────────
|
|
39
|
+
export const bufferTools = [
|
|
40
|
+
{
|
|
41
|
+
name: "buf_list_profiles",
|
|
42
|
+
description: "Lists all Buffer social media profiles connected to the account",
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: "object",
|
|
45
|
+
properties: {},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "buf_create_update",
|
|
50
|
+
description: "Creates a new social media post (update) via Buffer",
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: {
|
|
54
|
+
profile_ids: {
|
|
55
|
+
type: "array",
|
|
56
|
+
items: { type: "string" },
|
|
57
|
+
description: "Array of Buffer profile IDs to post to",
|
|
58
|
+
},
|
|
59
|
+
text: { type: "string", description: "Text content of the social media post" },
|
|
60
|
+
media: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: {
|
|
63
|
+
link: { type: "string", description: "URL to attach" },
|
|
64
|
+
description: { type: "string", description: "Description for the media" },
|
|
65
|
+
picture: { type: "string", description: "URL of an image to attach" },
|
|
66
|
+
},
|
|
67
|
+
description: "Optional media attachment (link, description, picture)",
|
|
68
|
+
},
|
|
69
|
+
scheduled_at: { type: "string", description: "Scheduled publish time in ISO 8601 format" },
|
|
70
|
+
shorten: { type: "boolean", description: "Whether to shorten links in the post" },
|
|
71
|
+
},
|
|
72
|
+
required: ["profile_ids", "text"],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "buf_list_pending",
|
|
77
|
+
description: "Lists pending (scheduled) updates for a Buffer profile",
|
|
78
|
+
inputSchema: {
|
|
79
|
+
type: "object",
|
|
80
|
+
properties: {
|
|
81
|
+
profile_id: { type: "string", description: "Buffer profile ID" },
|
|
82
|
+
count: { type: "number", description: "Number of updates to return" },
|
|
83
|
+
page: { type: "number", description: "Page number for pagination" },
|
|
84
|
+
},
|
|
85
|
+
required: ["profile_id"],
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "buf_list_sent",
|
|
90
|
+
description: "Lists sent updates for a Buffer profile with engagement stats",
|
|
91
|
+
inputSchema: {
|
|
92
|
+
type: "object",
|
|
93
|
+
properties: {
|
|
94
|
+
profile_id: { type: "string", description: "Buffer profile ID" },
|
|
95
|
+
count: { type: "number", description: "Number of updates to return" },
|
|
96
|
+
page: { type: "number", description: "Page number for pagination" },
|
|
97
|
+
},
|
|
98
|
+
required: ["profile_id"],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "buf_get_analytics",
|
|
103
|
+
description: "Gets interaction analytics for a specific Buffer update",
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: {
|
|
107
|
+
update_id: { type: "string", description: "Buffer update ID" },
|
|
108
|
+
},
|
|
109
|
+
required: ["update_id"],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
// ── Handlers ────────────────────────────────────────────────────
|
|
114
|
+
export const bufferHandlers = {
|
|
115
|
+
buf_list_profiles: async (_params) => {
|
|
116
|
+
if (!hasBuffer()) {
|
|
117
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "Buffer not configured. Add buffer_access_token to WP_SITES_CONFIG." }] } };
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const response = await makeBufferRequest("GET", "profiles.json");
|
|
121
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const errorMessage = error.response?.data?.message || error.message;
|
|
125
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error listing Buffer profiles: ${errorMessage}` }] } };
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
buf_create_update: async (params) => {
|
|
129
|
+
if (!hasBuffer()) {
|
|
130
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "Buffer not configured. Add buffer_access_token to WP_SITES_CONFIG." }] } };
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const { profile_ids, text, media, scheduled_at, shorten } = params;
|
|
134
|
+
const body = { profile_ids, text };
|
|
135
|
+
if (media)
|
|
136
|
+
body.media = media;
|
|
137
|
+
if (scheduled_at)
|
|
138
|
+
body.scheduled_at = scheduled_at;
|
|
139
|
+
if (shorten !== undefined)
|
|
140
|
+
body.shorten = shorten;
|
|
141
|
+
const response = await makeBufferRequest("POST", "updates/create.json", body);
|
|
142
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
const errorMessage = error.response?.data?.message || error.message;
|
|
146
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error creating Buffer update: ${errorMessage}` }] } };
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
buf_list_pending: async (params) => {
|
|
150
|
+
if (!hasBuffer()) {
|
|
151
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "Buffer not configured. Add buffer_access_token to WP_SITES_CONFIG." }] } };
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
const { profile_id, count, page } = params;
|
|
155
|
+
const query = {};
|
|
156
|
+
if (count !== undefined)
|
|
157
|
+
query.count = count;
|
|
158
|
+
if (page !== undefined)
|
|
159
|
+
query.page = page;
|
|
160
|
+
const qs = Object.entries(query).map(([k, v]) => `${k}=${v}`).join('&');
|
|
161
|
+
const endpoint = `profiles/${profile_id}/updates/pending.json${qs ? '?' + qs : ''}`;
|
|
162
|
+
const response = await makeBufferRequest("GET", endpoint);
|
|
163
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
const errorMessage = error.response?.data?.message || error.message;
|
|
167
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error listing pending updates: ${errorMessage}` }] } };
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
buf_list_sent: async (params) => {
|
|
171
|
+
if (!hasBuffer()) {
|
|
172
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "Buffer not configured. Add buffer_access_token to WP_SITES_CONFIG." }] } };
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
const { profile_id, count, page } = params;
|
|
176
|
+
const query = {};
|
|
177
|
+
if (count !== undefined)
|
|
178
|
+
query.count = count;
|
|
179
|
+
if (page !== undefined)
|
|
180
|
+
query.page = page;
|
|
181
|
+
const qs = Object.entries(query).map(([k, v]) => `${k}=${v}`).join('&');
|
|
182
|
+
const endpoint = `profiles/${profile_id}/updates/sent.json${qs ? '?' + qs : ''}`;
|
|
183
|
+
const response = await makeBufferRequest("GET", endpoint);
|
|
184
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
const errorMessage = error.response?.data?.message || error.message;
|
|
188
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error listing sent updates: ${errorMessage}` }] } };
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
buf_get_analytics: async (params) => {
|
|
192
|
+
if (!hasBuffer()) {
|
|
193
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "Buffer not configured. Add buffer_access_token to WP_SITES_CONFIG." }] } };
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
const { update_id } = params;
|
|
197
|
+
const response = await makeBufferRequest("GET", `updates/${update_id}/interactions.json`);
|
|
198
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
const errorMessage = error.response?.data?.message || error.message;
|
|
202
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting update analytics: ${errorMessage}` }] } };
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
};
|
|
@@ -18,13 +18,13 @@ declare const listCommentsSchema: z.ZodObject<{
|
|
|
18
18
|
include_pagination: z.ZodOptional<z.ZodBoolean>;
|
|
19
19
|
}, "strip", z.ZodTypeAny, {
|
|
20
20
|
post?: number | undefined;
|
|
21
|
+
search?: string | undefined;
|
|
22
|
+
type?: string | undefined;
|
|
21
23
|
page?: number | undefined;
|
|
22
24
|
per_page?: number | undefined;
|
|
23
|
-
search?: string | undefined;
|
|
24
25
|
status?: "approve" | "hold" | "spam" | "trash" | undefined;
|
|
25
|
-
type?: string | undefined;
|
|
26
26
|
author?: number | number[] | undefined;
|
|
27
|
-
orderby?: "post" | "
|
|
27
|
+
orderby?: "post" | "id" | "type" | "date" | "parent" | "include" | "date_gmt" | undefined;
|
|
28
28
|
order?: "asc" | "desc" | undefined;
|
|
29
29
|
after?: string | undefined;
|
|
30
30
|
_embed?: boolean | undefined;
|
|
@@ -34,13 +34,13 @@ declare const listCommentsSchema: z.ZodObject<{
|
|
|
34
34
|
author_exclude?: number[] | undefined;
|
|
35
35
|
}, {
|
|
36
36
|
post?: number | undefined;
|
|
37
|
+
search?: string | undefined;
|
|
38
|
+
type?: string | undefined;
|
|
37
39
|
page?: number | undefined;
|
|
38
40
|
per_page?: number | undefined;
|
|
39
|
-
search?: string | undefined;
|
|
40
41
|
status?: "approve" | "hold" | "spam" | "trash" | undefined;
|
|
41
|
-
type?: string | undefined;
|
|
42
42
|
author?: number | number[] | undefined;
|
|
43
|
-
orderby?: "post" | "
|
|
43
|
+
orderby?: "post" | "id" | "type" | "date" | "parent" | "include" | "date_gmt" | undefined;
|
|
44
44
|
order?: "asc" | "desc" | undefined;
|
|
45
45
|
after?: string | undefined;
|
|
46
46
|
_embed?: boolean | undefined;
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { hasGSC, getGSCAuth, getGSCSiteUrl } from '../wordpress.js';
|
|
2
|
+
import { google } from 'googleapis';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// ── Zod Schemas ─────────────────────────────────────────────────
|
|
5
|
+
const gscListSitesSchema = z.object({}).strict();
|
|
6
|
+
const gscSearchAnalyticsSchema = z.object({
|
|
7
|
+
start_date: z.string().describe('Start date in YYYY-MM-DD format'),
|
|
8
|
+
end_date: z.string().describe('End date in YYYY-MM-DD format'),
|
|
9
|
+
dimensions: z.array(z.enum(['query', 'page', 'country', 'device', 'date'])).optional()
|
|
10
|
+
.describe('Dimensions to group results by'),
|
|
11
|
+
row_limit: z.number().optional().default(100)
|
|
12
|
+
.describe('Maximum number of rows to return (default 100)'),
|
|
13
|
+
dimension_filter_groups: z.array(z.object({
|
|
14
|
+
groupType: z.enum(['and']).optional(),
|
|
15
|
+
filters: z.array(z.object({
|
|
16
|
+
dimension: z.enum(['query', 'page', 'country', 'device']),
|
|
17
|
+
operator: z.enum(['contains', 'equals', 'notContains', 'notEquals', 'includingRegex', 'excludingRegex']),
|
|
18
|
+
expression: z.string(),
|
|
19
|
+
})),
|
|
20
|
+
})).optional()
|
|
21
|
+
.describe('Filter groups for narrowing results'),
|
|
22
|
+
}).strict();
|
|
23
|
+
const gscInspectUrlSchema = z.object({
|
|
24
|
+
inspection_url: z.string().describe('The fully-qualified URL to inspect'),
|
|
25
|
+
site_url: z.string().optional()
|
|
26
|
+
.describe('Site URL (defaults to configured gsc_site_url)'),
|
|
27
|
+
}).strict();
|
|
28
|
+
const gscListSitemapsSchema = z.object({}).strict();
|
|
29
|
+
const gscSubmitSitemapSchema = z.object({
|
|
30
|
+
feedpath: z.string().describe('Full URL to the sitemap (e.g. https://example.com/sitemap.xml)'),
|
|
31
|
+
}).strict();
|
|
32
|
+
const gscDeleteSitemapSchema = z.object({
|
|
33
|
+
feedpath: z.string().describe('Full URL of the sitemap to delete'),
|
|
34
|
+
}).strict();
|
|
35
|
+
const gscTopQueriesSchema = z.object({
|
|
36
|
+
start_date: z.string().describe('Start date in YYYY-MM-DD format'),
|
|
37
|
+
end_date: z.string().describe('End date in YYYY-MM-DD format'),
|
|
38
|
+
limit: z.number().optional().default(25)
|
|
39
|
+
.describe('Number of top queries to return (default 25)'),
|
|
40
|
+
}).strict();
|
|
41
|
+
const gscPagePerformanceSchema = z.object({
|
|
42
|
+
start_date: z.string().describe('Start date in YYYY-MM-DD format'),
|
|
43
|
+
end_date: z.string().describe('End date in YYYY-MM-DD format'),
|
|
44
|
+
page_filter: z.string().optional()
|
|
45
|
+
.describe('Filter pages by URL containing this string'),
|
|
46
|
+
limit: z.number().optional().default(50)
|
|
47
|
+
.describe('Number of pages to return (default 50)'),
|
|
48
|
+
}).strict();
|
|
49
|
+
// ── Tool Definitions ────────────────────────────────────────────
|
|
50
|
+
export const gscTools = [
|
|
51
|
+
{
|
|
52
|
+
name: "gsc_list_sites",
|
|
53
|
+
description: "Lists all sites verified in Google Search Console",
|
|
54
|
+
inputSchema: {
|
|
55
|
+
type: "object",
|
|
56
|
+
properties: {},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "gsc_search_analytics",
|
|
61
|
+
description: "Queries search analytics data (impressions, clicks, CTR, position) for a site",
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {
|
|
65
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
66
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
67
|
+
dimensions: {
|
|
68
|
+
type: "array",
|
|
69
|
+
items: {
|
|
70
|
+
type: "string",
|
|
71
|
+
enum: ["query", "page", "country", "device", "date"],
|
|
72
|
+
},
|
|
73
|
+
description: "Dimensions to group results by",
|
|
74
|
+
},
|
|
75
|
+
row_limit: { type: "number", description: "Maximum number of rows to return (default 100)" },
|
|
76
|
+
dimension_filter_groups: {
|
|
77
|
+
type: "array",
|
|
78
|
+
items: {
|
|
79
|
+
type: "object",
|
|
80
|
+
properties: {
|
|
81
|
+
groupType: { type: "string", enum: ["and"] },
|
|
82
|
+
filters: {
|
|
83
|
+
type: "array",
|
|
84
|
+
items: {
|
|
85
|
+
type: "object",
|
|
86
|
+
properties: {
|
|
87
|
+
dimension: { type: "string", enum: ["query", "page", "country", "device"] },
|
|
88
|
+
operator: {
|
|
89
|
+
type: "string",
|
|
90
|
+
enum: ["contains", "equals", "notContains", "notEquals", "includingRegex", "excludingRegex"],
|
|
91
|
+
},
|
|
92
|
+
expression: { type: "string" },
|
|
93
|
+
},
|
|
94
|
+
required: ["dimension", "operator", "expression"],
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
description: "Filter groups for narrowing results",
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
required: ["start_date", "end_date"],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "gsc_inspect_url",
|
|
107
|
+
description: "Inspects a URL's indexing status in Google Search Console",
|
|
108
|
+
inputSchema: {
|
|
109
|
+
type: "object",
|
|
110
|
+
properties: {
|
|
111
|
+
inspection_url: { type: "string", description: "The fully-qualified URL to inspect" },
|
|
112
|
+
site_url: { type: "string", description: "Site URL (defaults to configured gsc_site_url)" },
|
|
113
|
+
},
|
|
114
|
+
required: ["inspection_url"],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "gsc_list_sitemaps",
|
|
119
|
+
description: "Lists all sitemaps submitted to Google Search Console",
|
|
120
|
+
inputSchema: {
|
|
121
|
+
type: "object",
|
|
122
|
+
properties: {},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "gsc_submit_sitemap",
|
|
127
|
+
description: "Submits a sitemap to Google Search Console",
|
|
128
|
+
inputSchema: {
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: {
|
|
131
|
+
feedpath: { type: "string", description: "Full URL to the sitemap (e.g. https://example.com/sitemap.xml)" },
|
|
132
|
+
},
|
|
133
|
+
required: ["feedpath"],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "gsc_delete_sitemap",
|
|
138
|
+
description: "Deletes a sitemap from Google Search Console",
|
|
139
|
+
inputSchema: {
|
|
140
|
+
type: "object",
|
|
141
|
+
properties: {
|
|
142
|
+
feedpath: { type: "string", description: "Full URL of the sitemap to delete" },
|
|
143
|
+
},
|
|
144
|
+
required: ["feedpath"],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: "gsc_top_queries",
|
|
149
|
+
description: "Gets top search queries for a site ordered by clicks (convenience wrapper around gsc_search_analytics)",
|
|
150
|
+
inputSchema: {
|
|
151
|
+
type: "object",
|
|
152
|
+
properties: {
|
|
153
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
154
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
155
|
+
limit: { type: "number", description: "Number of top queries to return (default 25)" },
|
|
156
|
+
},
|
|
157
|
+
required: ["start_date", "end_date"],
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "gsc_page_performance",
|
|
162
|
+
description: "Gets performance metrics for specific pages with optional URL filter (convenience wrapper)",
|
|
163
|
+
inputSchema: {
|
|
164
|
+
type: "object",
|
|
165
|
+
properties: {
|
|
166
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
167
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
168
|
+
page_filter: { type: "string", description: "Filter pages by URL containing this string" },
|
|
169
|
+
limit: { type: "number", description: "Number of pages to return (default 50)" },
|
|
170
|
+
},
|
|
171
|
+
required: ["start_date", "end_date"],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
// ── Handlers ────────────────────────────────────────────────────
|
|
176
|
+
export const gscHandlers = {
|
|
177
|
+
gsc_list_sites: async (_params) => {
|
|
178
|
+
if (!hasGSC()) {
|
|
179
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "GSC not configured. Add gsc_service_account_key and gsc_site_url to WP_SITES_CONFIG." }] } };
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const auth = await getGSCAuth();
|
|
183
|
+
const searchconsole = google.searchconsole({ version: 'v1', auth });
|
|
184
|
+
const response = await searchconsole.sites.list();
|
|
185
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
const errorMessage = error.response?.data?.error?.message || error.message;
|
|
189
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error listing sites: ${errorMessage}` }] } };
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
gsc_search_analytics: async (params) => {
|
|
193
|
+
if (!hasGSC()) {
|
|
194
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "GSC not configured. Add gsc_service_account_key and gsc_site_url to WP_SITES_CONFIG." }] } };
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
const auth = await getGSCAuth();
|
|
198
|
+
const siteUrl = getGSCSiteUrl();
|
|
199
|
+
const { start_date, end_date, dimensions, row_limit, dimension_filter_groups } = params;
|
|
200
|
+
const searchconsole = google.searchconsole({ version: 'v1', auth });
|
|
201
|
+
const requestBody = {
|
|
202
|
+
startDate: start_date,
|
|
203
|
+
endDate: end_date,
|
|
204
|
+
rowLimit: row_limit || 100,
|
|
205
|
+
};
|
|
206
|
+
if (dimensions)
|
|
207
|
+
requestBody.dimensions = dimensions;
|
|
208
|
+
if (dimension_filter_groups)
|
|
209
|
+
requestBody.dimensionFilterGroups = dimension_filter_groups;
|
|
210
|
+
const response = await searchconsole.searchanalytics.query({
|
|
211
|
+
siteUrl,
|
|
212
|
+
requestBody,
|
|
213
|
+
});
|
|
214
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
const errorMessage = error.response?.data?.error?.message || error.message;
|
|
218
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error querying search analytics: ${errorMessage}` }] } };
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
gsc_inspect_url: async (params) => {
|
|
222
|
+
if (!hasGSC()) {
|
|
223
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "GSC not configured. Add gsc_service_account_key and gsc_site_url to WP_SITES_CONFIG." }] } };
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
const auth = await getGSCAuth();
|
|
227
|
+
const { inspection_url, site_url } = params;
|
|
228
|
+
const siteUrl = site_url || getGSCSiteUrl();
|
|
229
|
+
const searchconsole = google.searchconsole({ version: 'v1', auth });
|
|
230
|
+
const response = await searchconsole.urlInspection.index.inspect({
|
|
231
|
+
requestBody: {
|
|
232
|
+
inspectionUrl: inspection_url,
|
|
233
|
+
siteUrl,
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
const errorMessage = error.response?.data?.error?.message || error.message;
|
|
240
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error inspecting URL: ${errorMessage}` }] } };
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
gsc_list_sitemaps: async (_params) => {
|
|
244
|
+
if (!hasGSC()) {
|
|
245
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "GSC not configured. Add gsc_service_account_key and gsc_site_url to WP_SITES_CONFIG." }] } };
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
const auth = await getGSCAuth();
|
|
249
|
+
const siteUrl = getGSCSiteUrl();
|
|
250
|
+
const webmasters = google.webmasters({ version: 'v3', auth });
|
|
251
|
+
const response = await webmasters.sitemaps.list({ siteUrl });
|
|
252
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
const errorMessage = error.response?.data?.error?.message || error.message;
|
|
256
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error listing sitemaps: ${errorMessage}` }] } };
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
gsc_submit_sitemap: async (params) => {
|
|
260
|
+
if (!hasGSC()) {
|
|
261
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "GSC not configured. Add gsc_service_account_key and gsc_site_url to WP_SITES_CONFIG." }] } };
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
const auth = await getGSCAuth();
|
|
265
|
+
const siteUrl = getGSCSiteUrl();
|
|
266
|
+
const { feedpath } = params;
|
|
267
|
+
const webmasters = google.webmasters({ version: 'v3', auth });
|
|
268
|
+
await webmasters.sitemaps.submit({ siteUrl, feedpath });
|
|
269
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Sitemap submitted: ${feedpath}` }, null, 2) }] } };
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
const errorMessage = error.response?.data?.error?.message || error.message;
|
|
273
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error submitting sitemap: ${errorMessage}` }] } };
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
gsc_delete_sitemap: async (params) => {
|
|
277
|
+
if (!hasGSC()) {
|
|
278
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "GSC not configured. Add gsc_service_account_key and gsc_site_url to WP_SITES_CONFIG." }] } };
|
|
279
|
+
}
|
|
280
|
+
try {
|
|
281
|
+
const auth = await getGSCAuth();
|
|
282
|
+
const siteUrl = getGSCSiteUrl();
|
|
283
|
+
const { feedpath } = params;
|
|
284
|
+
const webmasters = google.webmasters({ version: 'v3', auth });
|
|
285
|
+
await webmasters.sitemaps.delete({ siteUrl, feedpath });
|
|
286
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Sitemap deleted: ${feedpath}` }, null, 2) }] } };
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
const errorMessage = error.response?.data?.error?.message || error.message;
|
|
290
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error deleting sitemap: ${errorMessage}` }] } };
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
gsc_top_queries: async (params) => {
|
|
294
|
+
if (!hasGSC()) {
|
|
295
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "GSC not configured. Add gsc_service_account_key and gsc_site_url to WP_SITES_CONFIG." }] } };
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
const auth = await getGSCAuth();
|
|
299
|
+
const siteUrl = getGSCSiteUrl();
|
|
300
|
+
const { start_date, end_date, limit } = params;
|
|
301
|
+
const searchconsole = google.searchconsole({ version: 'v1', auth });
|
|
302
|
+
const response = await searchconsole.searchanalytics.query({
|
|
303
|
+
siteUrl,
|
|
304
|
+
requestBody: {
|
|
305
|
+
startDate: start_date,
|
|
306
|
+
endDate: end_date,
|
|
307
|
+
dimensions: ['query'],
|
|
308
|
+
rowLimit: limit || 25,
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
const errorMessage = error.response?.data?.error?.message || error.message;
|
|
315
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting top queries: ${errorMessage}` }] } };
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
gsc_page_performance: async (params) => {
|
|
319
|
+
if (!hasGSC()) {
|
|
320
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: "GSC not configured. Add gsc_service_account_key and gsc_site_url to WP_SITES_CONFIG." }] } };
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
const auth = await getGSCAuth();
|
|
324
|
+
const siteUrl = getGSCSiteUrl();
|
|
325
|
+
const { start_date, end_date, page_filter, limit } = params;
|
|
326
|
+
const searchconsole = google.searchconsole({ version: 'v1', auth });
|
|
327
|
+
const requestBody = {
|
|
328
|
+
startDate: start_date,
|
|
329
|
+
endDate: end_date,
|
|
330
|
+
dimensions: ['page'],
|
|
331
|
+
rowLimit: limit || 50,
|
|
332
|
+
};
|
|
333
|
+
if (page_filter) {
|
|
334
|
+
requestBody.dimensionFilterGroups = [{
|
|
335
|
+
groupType: 'and',
|
|
336
|
+
filters: [{
|
|
337
|
+
dimension: 'page',
|
|
338
|
+
operator: 'contains',
|
|
339
|
+
expression: page_filter,
|
|
340
|
+
}],
|
|
341
|
+
}];
|
|
342
|
+
}
|
|
343
|
+
const response = await searchconsole.searchanalytics.query({
|
|
344
|
+
siteUrl,
|
|
345
|
+
requestBody,
|
|
346
|
+
});
|
|
347
|
+
return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
const errorMessage = error.response?.data?.error?.message || error.message;
|
|
351
|
+
return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting page performance: ${errorMessage}` }] } };
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
};
|