claude-plugin-wordpress-manager 2.3.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/.claude-plugin/plugin.json +8 -3
  2. package/CHANGELOG.md +20 -0
  3. package/agents/wp-distribution-manager.md +98 -0
  4. package/docs/plans/2026-03-01-tier3-wcop-design.md +373 -0
  5. package/docs/plans/2026-03-01-tier3-wcop-implementation.md +915 -0
  6. package/hooks/hooks.json +18 -0
  7. package/package.json +9 -3
  8. package/servers/wp-rest-bridge/build/tools/buffer.d.ts +3 -0
  9. package/servers/wp-rest-bridge/build/tools/buffer.js +205 -0
  10. package/servers/wp-rest-bridge/build/tools/index.js +9 -0
  11. package/servers/wp-rest-bridge/build/tools/mailchimp.d.ts +3 -0
  12. package/servers/wp-rest-bridge/build/tools/mailchimp.js +265 -0
  13. package/servers/wp-rest-bridge/build/tools/sendgrid.d.ts +3 -0
  14. package/servers/wp-rest-bridge/build/tools/sendgrid.js +255 -0
  15. package/servers/wp-rest-bridge/build/types.d.ts +122 -0
  16. package/servers/wp-rest-bridge/build/wordpress.d.ts +9 -0
  17. package/servers/wp-rest-bridge/build/wordpress.js +112 -0
  18. package/skills/wordpress-router/references/decision-tree.md +4 -2
  19. package/skills/wp-content/SKILL.md +1 -0
  20. package/skills/wp-content-repurposing/SKILL.md +1 -0
  21. package/skills/wp-social-email/SKILL.md +152 -0
  22. package/skills/wp-social-email/references/audience-segmentation.md +173 -0
  23. package/skills/wp-social-email/references/buffer-social-publishing.md +124 -0
  24. package/skills/wp-social-email/references/content-to-distribution.md +156 -0
  25. package/skills/wp-social-email/references/distribution-analytics.md +208 -0
  26. package/skills/wp-social-email/references/mailchimp-integration.md +145 -0
  27. package/skills/wp-social-email/references/sendgrid-transactional.md +165 -0
  28. package/skills/wp-social-email/scripts/distribution_inspect.mjs +165 -0
  29. 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.3.1",
4
- "description": "Unified WordPress management and development plugin for Claude Code. Orchestrates Hostinger MCP, WP REST API bridge (85 tools incl. 30 WooCommerce + 10 Multisite + 4 Webhooks), and WordPress.com MCP with 33 skills, 11 agents, and security hooks. v2.3.0 adds programmatic SEO, content-commerce attribution, and multi-language network skills.",
3
+ "version": "2.4.0",
4
+ "description": "Unified WordPress management and development plugin for Claude Code. Orchestrates Hostinger MCP, WP REST API bridge (103 tools incl. 30 WooCommerce + 10 Multisite + 4 Webhooks + 7 Mailchimp + 5 Buffer + 6 SendGrid), and WordPress.com MCP with 34 skills, 12 agents, and security hooks. v2.4.0 adds social/email distribution connectors (Mailchimp, Buffer, SendGrid).",
5
5
  "author": {
6
6
  "name": "vinmor",
7
7
  "email": "morreale.v@gmail.com"
@@ -41,7 +41,13 @@
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"
45
51
  ],
46
52
  "repository": {
47
53
  "type": "git",
@@ -0,0 +1,3 @@
1
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare const bufferTools: Tool[];
3
+ export declare const bufferHandlers: Record<string, Function>;
@@ -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
+ };
@@ -15,6 +15,9 @@ import { wcSettingTools, wcSettingHandlers } from './wc-settings.js';
15
15
  import { multisiteSiteTools, multisiteSiteHandlers } from './multisite-sites.js';
16
16
  import { multisiteNetworkTools, multisiteNetworkHandlers } from './multisite-network.js';
17
17
  import { wcWebhookTools, wcWebhookHandlers } from './wc-webhooks.js';
18
+ import { mailchimpTools, mailchimpHandlers } from './mailchimp.js';
19
+ import { bufferTools, bufferHandlers } from './buffer.js';
20
+ import { sendgridTools, sendgridHandlers } from './sendgrid.js';
18
21
  // Combine all tools
19
22
  export const allTools = [
20
23
  ...unifiedContentTools, // 8 tools
@@ -34,6 +37,9 @@ export const allTools = [
34
37
  ...multisiteSiteTools, // 5 tools
35
38
  ...multisiteNetworkTools, // 5 tools
36
39
  ...wcWebhookTools, // 4 tools
40
+ ...mailchimpTools, // 7 tools
41
+ ...bufferTools, // 5 tools
42
+ ...sendgridTools, // 6 tools
37
43
  ];
38
44
  // Combine all handlers
39
45
  export const toolHandlers = {
@@ -54,4 +60,7 @@ export const toolHandlers = {
54
60
  ...multisiteSiteHandlers,
55
61
  ...multisiteNetworkHandlers,
56
62
  ...wcWebhookHandlers,
63
+ ...mailchimpHandlers,
64
+ ...bufferHandlers,
65
+ ...sendgridHandlers,
57
66
  };
@@ -0,0 +1,3 @@
1
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare const mailchimpTools: Tool[];
3
+ export declare const mailchimpHandlers: Record<string, Function>;
@@ -0,0 +1,265 @@
1
+ import { makeMailchimpRequest, hasMailchimp } from '../wordpress.js';
2
+ import { z } from 'zod';
3
+ // ── Zod Schemas ─────────────────────────────────────────────────
4
+ const mcListAudiencesSchema = z.object({}).strict();
5
+ const mcGetAudienceMembersSchema = z.object({
6
+ list_id: z.string().describe('Audience (list) ID'),
7
+ status: z.enum(['subscribed', 'unsubscribed', 'cleaned', 'pending']).optional()
8
+ .describe('Filter members by subscription status'),
9
+ count: z.number().optional().default(100)
10
+ .describe('Number of members to return (default 100)'),
11
+ offset: z.number().optional()
12
+ .describe('Number of members to skip (for pagination)'),
13
+ }).strict();
14
+ const mcCreateCampaignSchema = z.object({
15
+ type: z.enum(['regular', 'plaintext', 'absplit'])
16
+ .describe('Campaign type'),
17
+ list_id: z.string().describe('Audience (list) ID to send to'),
18
+ subject_line: z.string().describe('Email subject line'),
19
+ from_name: z.string().describe('Sender name shown to recipients'),
20
+ reply_to: z.string().describe('Reply-to email address'),
21
+ }).strict();
22
+ const mcUpdateCampaignContentSchema = z.object({
23
+ campaign_id: z.string().describe('Campaign ID'),
24
+ html: z.string().describe('HTML content for the campaign email'),
25
+ }).strict();
26
+ const mcSendCampaignSchema = z.object({
27
+ campaign_id: z.string().describe('Campaign ID to send'),
28
+ }).strict();
29
+ const mcGetCampaignReportSchema = z.object({
30
+ campaign_id: z.string().describe('Campaign ID to get report for'),
31
+ }).strict();
32
+ const mcAddSubscriberSchema = z.object({
33
+ list_id: z.string().describe('Audience (list) ID'),
34
+ email_address: z.string().describe('Subscriber email address'),
35
+ status: z.enum(['subscribed', 'unsubscribed', 'cleaned', 'pending'])
36
+ .describe('Subscription status'),
37
+ merge_fields: z.record(z.any()).optional()
38
+ .describe('Merge fields (e.g. FNAME, LNAME)'),
39
+ tags: z.array(z.string()).optional()
40
+ .describe('Tags to assign to the subscriber'),
41
+ }).strict();
42
+ // ── Tool Definitions ────────────────────────────────────────────
43
+ export const mailchimpTools = [
44
+ {
45
+ name: "mc_list_audiences",
46
+ description: "Lists all Mailchimp audiences (lists) with member counts and stats",
47
+ inputSchema: {
48
+ type: "object",
49
+ properties: {},
50
+ },
51
+ },
52
+ {
53
+ name: "mc_get_audience_members",
54
+ description: "Gets members of a Mailchimp audience with optional status filter",
55
+ inputSchema: {
56
+ type: "object",
57
+ properties: {
58
+ list_id: { type: "string", description: "Audience (list) ID" },
59
+ status: {
60
+ type: "string",
61
+ enum: ["subscribed", "unsubscribed", "cleaned", "pending"],
62
+ description: "Filter members by subscription status",
63
+ },
64
+ count: { type: "number", description: "Number of members to return (default 100)" },
65
+ offset: { type: "number", description: "Number of members to skip (for pagination)" },
66
+ },
67
+ required: ["list_id"],
68
+ },
69
+ },
70
+ {
71
+ name: "mc_create_campaign",
72
+ description: "Creates a new Mailchimp email campaign",
73
+ inputSchema: {
74
+ type: "object",
75
+ properties: {
76
+ type: {
77
+ type: "string",
78
+ enum: ["regular", "plaintext", "absplit"],
79
+ description: "Campaign type",
80
+ },
81
+ list_id: { type: "string", description: "Audience (list) ID to send to" },
82
+ subject_line: { type: "string", description: "Email subject line" },
83
+ from_name: { type: "string", description: "Sender name shown to recipients" },
84
+ reply_to: { type: "string", description: "Reply-to email address" },
85
+ },
86
+ required: ["type", "list_id", "subject_line", "from_name", "reply_to"],
87
+ },
88
+ },
89
+ {
90
+ name: "mc_update_campaign_content",
91
+ description: "Sets the HTML content of a Mailchimp campaign",
92
+ inputSchema: {
93
+ type: "object",
94
+ properties: {
95
+ campaign_id: { type: "string", description: "Campaign ID" },
96
+ html: { type: "string", description: "HTML content for the campaign email" },
97
+ },
98
+ required: ["campaign_id", "html"],
99
+ },
100
+ },
101
+ {
102
+ name: "mc_send_campaign",
103
+ description: "Sends a Mailchimp campaign to its audience (DESTRUCTIVE — triggers real emails)",
104
+ inputSchema: {
105
+ type: "object",
106
+ properties: {
107
+ campaign_id: { type: "string", description: "Campaign ID to send" },
108
+ },
109
+ required: ["campaign_id"],
110
+ },
111
+ },
112
+ {
113
+ name: "mc_get_campaign_report",
114
+ description: "Gets performance report for a sent Mailchimp campaign (opens, clicks, bounces)",
115
+ inputSchema: {
116
+ type: "object",
117
+ properties: {
118
+ campaign_id: { type: "string", description: "Campaign ID to get report for" },
119
+ },
120
+ required: ["campaign_id"],
121
+ },
122
+ },
123
+ {
124
+ name: "mc_add_subscriber",
125
+ description: "Adds or updates a subscriber in a Mailchimp audience",
126
+ inputSchema: {
127
+ type: "object",
128
+ properties: {
129
+ list_id: { type: "string", description: "Audience (list) ID" },
130
+ email_address: { type: "string", description: "Subscriber email address" },
131
+ status: {
132
+ type: "string",
133
+ enum: ["subscribed", "unsubscribed", "cleaned", "pending"],
134
+ description: "Subscription status",
135
+ },
136
+ merge_fields: { type: "object", description: "Merge fields (e.g. FNAME, LNAME)" },
137
+ tags: {
138
+ type: "array",
139
+ items: { type: "string" },
140
+ description: "Tags to assign to the subscriber",
141
+ },
142
+ },
143
+ required: ["list_id", "email_address", "status"],
144
+ },
145
+ },
146
+ ];
147
+ // ── Handlers ────────────────────────────────────────────────────
148
+ export const mailchimpHandlers = {
149
+ mc_list_audiences: async (_params) => {
150
+ if (!hasMailchimp()) {
151
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Mailchimp not configured. Add mailchimp_api_key to WP_SITES_CONFIG." }] } };
152
+ }
153
+ try {
154
+ const response = await makeMailchimpRequest("GET", "/lists");
155
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
156
+ }
157
+ catch (error) {
158
+ const errorMessage = error.response?.data?.detail || error.message;
159
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error listing audiences: ${errorMessage}` }] } };
160
+ }
161
+ },
162
+ mc_get_audience_members: async (params) => {
163
+ if (!hasMailchimp()) {
164
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Mailchimp not configured. Add mailchimp_api_key to WP_SITES_CONFIG." }] } };
165
+ }
166
+ try {
167
+ const { list_id, status, count, offset } = params;
168
+ const query = {};
169
+ if (status)
170
+ query.status = status;
171
+ if (count !== undefined)
172
+ query.count = count;
173
+ if (offset !== undefined)
174
+ query.offset = offset;
175
+ const qs = Object.entries(query).map(([k, v]) => `${k}=${v}`).join('&');
176
+ const endpoint = `/lists/${list_id}/members${qs ? '?' + qs : ''}`;
177
+ const response = await makeMailchimpRequest("GET", endpoint);
178
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
179
+ }
180
+ catch (error) {
181
+ const errorMessage = error.response?.data?.detail || error.message;
182
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting audience members: ${errorMessage}` }] } };
183
+ }
184
+ },
185
+ mc_create_campaign: async (params) => {
186
+ if (!hasMailchimp()) {
187
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Mailchimp not configured. Add mailchimp_api_key to WP_SITES_CONFIG." }] } };
188
+ }
189
+ try {
190
+ const { type, list_id, subject_line, from_name, reply_to } = params;
191
+ const body = {
192
+ type,
193
+ recipients: { list_id },
194
+ settings: { subject_line, from_name, reply_to },
195
+ };
196
+ const response = await makeMailchimpRequest("POST", "/campaigns", body);
197
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
198
+ }
199
+ catch (error) {
200
+ const errorMessage = error.response?.data?.detail || error.message;
201
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error creating campaign: ${errorMessage}` }] } };
202
+ }
203
+ },
204
+ mc_update_campaign_content: async (params) => {
205
+ if (!hasMailchimp()) {
206
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Mailchimp not configured. Add mailchimp_api_key to WP_SITES_CONFIG." }] } };
207
+ }
208
+ try {
209
+ const { campaign_id, html } = params;
210
+ const response = await makeMailchimpRequest("PUT", `/campaigns/${campaign_id}/content`, { html });
211
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
212
+ }
213
+ catch (error) {
214
+ const errorMessage = error.response?.data?.detail || error.message;
215
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error updating campaign content: ${errorMessage}` }] } };
216
+ }
217
+ },
218
+ mc_send_campaign: async (params) => {
219
+ if (!hasMailchimp()) {
220
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Mailchimp not configured. Add mailchimp_api_key to WP_SITES_CONFIG." }] } };
221
+ }
222
+ try {
223
+ const { campaign_id } = params;
224
+ const response = await makeMailchimpRequest("POST", `/campaigns/${campaign_id}/actions/send`);
225
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response ?? { success: true, message: "Campaign sent successfully" }, null, 2) }] } };
226
+ }
227
+ catch (error) {
228
+ const errorMessage = error.response?.data?.detail || error.message;
229
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error sending campaign: ${errorMessage}` }] } };
230
+ }
231
+ },
232
+ mc_get_campaign_report: async (params) => {
233
+ if (!hasMailchimp()) {
234
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Mailchimp not configured. Add mailchimp_api_key to WP_SITES_CONFIG." }] } };
235
+ }
236
+ try {
237
+ const { campaign_id } = params;
238
+ const response = await makeMailchimpRequest("GET", `/reports/${campaign_id}`);
239
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
240
+ }
241
+ catch (error) {
242
+ const errorMessage = error.response?.data?.detail || error.message;
243
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting campaign report: ${errorMessage}` }] } };
244
+ }
245
+ },
246
+ mc_add_subscriber: async (params) => {
247
+ if (!hasMailchimp()) {
248
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Mailchimp not configured. Add mailchimp_api_key to WP_SITES_CONFIG." }] } };
249
+ }
250
+ try {
251
+ const { list_id, email_address, status, merge_fields, tags } = params;
252
+ const body = { email_address, status };
253
+ if (merge_fields)
254
+ body.merge_fields = merge_fields;
255
+ if (tags)
256
+ body.tags = tags;
257
+ const response = await makeMailchimpRequest("POST", `/lists/${list_id}/members`, body);
258
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
259
+ }
260
+ catch (error) {
261
+ const errorMessage = error.response?.data?.detail || error.message;
262
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error adding subscriber: ${errorMessage}` }] } };
263
+ }
264
+ },
265
+ };
@@ -0,0 +1,3 @@
1
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare const sendgridTools: Tool[];
3
+ export declare const sendgridHandlers: Record<string, Function>;