myaidev-method 0.3.1 → 0.3.3
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 +52 -48
- package/CHANGELOG.md +5 -0
- package/DEV_WORKFLOW_GUIDE.md +6 -6
- package/MCP_INTEGRATION.md +4 -4
- package/README.md +140 -66
- package/TECHNICAL_ARCHITECTURE.md +112 -18
- package/USER_GUIDE.md +270 -39
- package/bin/cli.js +47 -13
- package/dist/mcp/gutenberg-converter.js +667 -413
- package/dist/mcp/wordpress-admin-mcp.js +0 -1
- package/dist/mcp/wordpress-integration.js +0 -1
- package/dist/mcp/wordpress-server.js +1558 -1182
- package/dist/server/.tsbuildinfo +1 -1
- package/extension.json +3 -3
- package/package.json +9 -2
- package/skills/content-writer/SKILL.md +130 -178
- package/skills/infographic/SKILL.md +191 -0
- package/skills/myaidev-analyze/SKILL.md +242 -0
- package/skills/myaidev-architect/SKILL.md +389 -0
- package/skills/myaidev-coder/SKILL.md +291 -0
- package/skills/myaidev-debug/SKILL.md +308 -0
- package/skills/myaidev-documenter/SKILL.md +194 -0
- package/skills/myaidev-migrate/SKILL.md +300 -0
- package/skills/myaidev-performance/SKILL.md +270 -0
- package/skills/myaidev-refactor/SKILL.md +296 -0
- package/skills/myaidev-reviewer/SKILL.md +385 -0
- package/skills/myaidev-tester/SKILL.md +331 -0
- package/skills/myaidev-workflow/SKILL.md +567 -0
- package/skills/security-auditor/SKILL.md +1 -1
- package/src/cli/commands/addon.js +60 -12
- package/src/cli/commands/auth.js +10 -2
- package/src/config/workflows.js +11 -6
- package/src/lib/ascii-banner.js +3 -3
- package/src/lib/coolify-utils.js +0 -1
- package/src/lib/payloadcms-utils.js +0 -1
- package/src/lib/visual-generation-utils.js +0 -1
- package/src/lib/wordpress-admin-utils.js +0 -1
- package/src/mcp/gutenberg-converter.js +667 -413
- package/src/mcp/wordpress-admin-mcp.js +0 -1
- package/src/mcp/wordpress-integration.js +0 -1
- package/src/mcp/wordpress-server.js +1558 -1182
- package/src/scripts/test-coolify-deploy.js +0 -1
- package/src/statusline/statusline.sh +279 -0
- package/skills/content-writer/agents/editor-agent.md +0 -138
- package/skills/content-writer/agents/planner-agent.md +0 -121
- package/skills/content-writer/agents/research-agent.md +0 -83
- package/skills/content-writer/agents/seo-agent.md +0 -139
- package/skills/content-writer/agents/visual-planner-agent.md +0 -110
- package/skills/content-writer/agents/writer-agent.md +0 -85
- package/skills/sparc-architect/SKILL.md +0 -127
- package/skills/sparc-coder/SKILL.md +0 -90
- package/skills/sparc-documenter/SKILL.md +0 -155
- package/skills/sparc-reviewer/SKILL.md +0 -138
- package/skills/sparc-tester/SKILL.md +0 -100
- package/skills/sparc-workflow/SKILL.md +0 -130
- /package/{marketplace.json → .claude-plugin/marketplace.json} +0 -0
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import fetch from "node-fetch";
|
|
7
6
|
import dotenv from "dotenv";
|
|
7
|
+
import fs from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
8
9
|
import { GutenbergConverter } from "./gutenberg-converter.js";
|
|
9
10
|
|
|
10
11
|
// Load environment variables
|
|
@@ -14,1260 +15,1635 @@ dotenv.config();
|
|
|
14
15
|
const WORDPRESS_URL = process.env.WORDPRESS_URL;
|
|
15
16
|
const WORDPRESS_USERNAME = process.env.WORDPRESS_USERNAME;
|
|
16
17
|
const WORDPRESS_APP_PASSWORD = process.env.WORDPRESS_APP_PASSWORD;
|
|
17
|
-
const WORDPRESS_USE_GUTENBERG = process.env.WORDPRESS_USE_GUTENBERG ===
|
|
18
|
+
const WORDPRESS_USE_GUTENBERG = process.env.WORDPRESS_USE_GUTENBERG === "true";
|
|
18
19
|
|
|
19
20
|
// Validate environment variables
|
|
20
21
|
if (!WORDPRESS_URL || !WORDPRESS_USERNAME || !WORDPRESS_APP_PASSWORD) {
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
console.error(
|
|
23
|
+
"Missing required environment variables: WORDPRESS_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD",
|
|
24
|
+
);
|
|
25
|
+
process.exit(1);
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
// Session management
|
|
26
29
|
class SessionManager {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
30
|
+
constructor() {
|
|
31
|
+
this.sessions = new Map();
|
|
32
|
+
this.activeSession = null;
|
|
33
|
+
this.sessionTimeout = 30 * 60 * 1000; // 30 minutes
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
createSession(id = null) {
|
|
37
|
+
const sessionId = id || `wp_session_${Date.now()}`;
|
|
38
|
+
const session = {
|
|
39
|
+
id: sessionId,
|
|
40
|
+
created: Date.now(),
|
|
41
|
+
lastActivity: Date.now(),
|
|
42
|
+
operations: [],
|
|
43
|
+
context: {},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
this.sessions.set(sessionId, session);
|
|
47
|
+
this.activeSession = sessionId;
|
|
48
|
+
return sessionId;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getSession(id) {
|
|
52
|
+
return this.sessions.get(id);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
updateActivity(id) {
|
|
56
|
+
const session = this.sessions.get(id);
|
|
57
|
+
if (session) {
|
|
58
|
+
session.lastActivity = Date.now();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
logOperation(sessionId, operation) {
|
|
63
|
+
const session = this.sessions.get(sessionId);
|
|
64
|
+
if (session) {
|
|
65
|
+
session.operations.push({
|
|
66
|
+
...operation,
|
|
67
|
+
timestamp: Date.now(),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
cleanup() {
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
for (const [id, session] of this.sessions) {
|
|
75
|
+
if (now - session.lastActivity > this.sessionTimeout) {
|
|
76
|
+
this.sessions.delete(id);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
const sessionManager = new SessionManager();
|
|
80
83
|
|
|
81
84
|
// Memory manager for persistence (simple implementation)
|
|
82
85
|
class MemoryManager {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
86
|
+
constructor() {
|
|
87
|
+
this.memory = new Map();
|
|
88
|
+
this.namespaces = new Map();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
store(key, value, namespace = "default", ttl = null) {
|
|
92
|
+
const nsMap = this.namespaces.get(namespace) || new Map();
|
|
93
|
+
const entry = {
|
|
94
|
+
value,
|
|
95
|
+
timestamp: Date.now(),
|
|
96
|
+
ttl: ttl ? Date.now() + ttl : null,
|
|
97
|
+
};
|
|
98
|
+
nsMap.set(key, entry);
|
|
99
|
+
this.namespaces.set(namespace, nsMap);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
retrieve(key, namespace = "default") {
|
|
104
|
+
const nsMap = this.namespaces.get(namespace);
|
|
105
|
+
if (!nsMap) return null;
|
|
106
|
+
|
|
107
|
+
const entry = nsMap.get(key);
|
|
108
|
+
if (!entry) return null;
|
|
109
|
+
|
|
110
|
+
if (entry.ttl && Date.now() > entry.ttl) {
|
|
111
|
+
nsMap.delete(key);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return entry.value;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
delete(key, namespace = "default") {
|
|
119
|
+
const nsMap = this.namespaces.get(namespace);
|
|
120
|
+
if (nsMap) {
|
|
121
|
+
return nsMap.delete(key);
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
list(namespace = "default") {
|
|
127
|
+
const nsMap = this.namespaces.get(namespace);
|
|
128
|
+
if (!nsMap) return [];
|
|
129
|
+
|
|
130
|
+
const now = Date.now();
|
|
131
|
+
const results = [];
|
|
132
|
+
|
|
133
|
+
for (const [key, entry] of nsMap) {
|
|
134
|
+
if (entry.ttl && now > entry.ttl) {
|
|
135
|
+
nsMap.delete(key);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
results.push({ key, value: entry.value, timestamp: entry.timestamp });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return results;
|
|
142
|
+
}
|
|
140
143
|
}
|
|
141
144
|
|
|
142
145
|
const memoryManager = new MemoryManager();
|
|
143
146
|
|
|
144
147
|
// Create MCP server with enhanced configuration
|
|
145
148
|
const server = new McpServer({
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
name: "wordpress-mcp-server",
|
|
150
|
+
version: "2.0.0",
|
|
151
|
+
description:
|
|
152
|
+
"Enhanced WordPress MCP Server with session management and memory persistence",
|
|
149
153
|
});
|
|
150
154
|
|
|
151
155
|
// Enhanced helper function for WordPress API requests with better error handling
|
|
152
|
-
async function wordpressRequest(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
156
|
+
async function wordpressRequest(
|
|
157
|
+
endpoint,
|
|
158
|
+
method = "GET",
|
|
159
|
+
data = null,
|
|
160
|
+
sessionId = null,
|
|
161
|
+
) {
|
|
162
|
+
const baseUrl = WORDPRESS_URL.replace(/\/$/, "");
|
|
163
|
+
const apiPath = "/wp-json/wp/v2";
|
|
164
|
+
const auth = Buffer.from(
|
|
165
|
+
`${WORDPRESS_USERNAME}:${WORDPRESS_APP_PASSWORD}`,
|
|
166
|
+
).toString("base64");
|
|
167
|
+
|
|
168
|
+
const options = {
|
|
169
|
+
method,
|
|
170
|
+
headers: {
|
|
171
|
+
Authorization: `Basic ${auth}`,
|
|
172
|
+
"Content-Type": "application/json",
|
|
173
|
+
"User-Agent": "WordPress-MCP-Server/2.0.0",
|
|
174
|
+
},
|
|
175
|
+
timeout: 30000, // 30 second timeout
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
if (data && method !== "GET") {
|
|
179
|
+
options.body = JSON.stringify(data);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const startTime = Date.now();
|
|
183
|
+
let response;
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
response = await fetch(`${baseUrl}${apiPath}${endpoint}`, options);
|
|
187
|
+
|
|
188
|
+
// Log operation if session provided
|
|
189
|
+
if (sessionId) {
|
|
190
|
+
sessionManager.logOperation(sessionId, {
|
|
191
|
+
type: "api_request",
|
|
192
|
+
method,
|
|
193
|
+
endpoint,
|
|
194
|
+
status: response.status,
|
|
195
|
+
duration: Date.now() - startTime,
|
|
196
|
+
});
|
|
197
|
+
sessionManager.updateActivity(sessionId);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!response.ok) {
|
|
201
|
+
let errorBody;
|
|
202
|
+
try {
|
|
203
|
+
errorBody = await response.json();
|
|
204
|
+
} catch {
|
|
205
|
+
errorBody = await response.text();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
throw new MCPError({
|
|
209
|
+
code: response.status,
|
|
210
|
+
message: `WordPress API Error: ${response.status} - ${response.statusText}`,
|
|
211
|
+
details: errorBody,
|
|
212
|
+
endpoint,
|
|
213
|
+
method,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return await response.json();
|
|
218
|
+
} catch (error) {
|
|
219
|
+
// Log error operation
|
|
220
|
+
if (sessionId) {
|
|
221
|
+
sessionManager.logOperation(sessionId, {
|
|
222
|
+
type: "api_error",
|
|
223
|
+
method,
|
|
224
|
+
endpoint,
|
|
225
|
+
error: error.message,
|
|
226
|
+
duration: Date.now() - startTime,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (error instanceof MCPError) {
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
throw new MCPError({
|
|
235
|
+
code: "NETWORK_ERROR",
|
|
236
|
+
message: `Network error: ${error.message}`,
|
|
237
|
+
details: error,
|
|
238
|
+
endpoint,
|
|
239
|
+
method,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Helper for uploading files to WordPress media library via multipart/form-data
|
|
245
|
+
async function wordpressUploadRequest(
|
|
246
|
+
filePath,
|
|
247
|
+
metadata = {},
|
|
248
|
+
sessionId = null,
|
|
249
|
+
) {
|
|
250
|
+
const baseUrl = WORDPRESS_URL.replace(/\/$/, "");
|
|
251
|
+
const apiPath = "/wp-json/wp/v2";
|
|
252
|
+
const auth = Buffer.from(
|
|
253
|
+
`${WORDPRESS_USERNAME}:${WORDPRESS_APP_PASSWORD}`,
|
|
254
|
+
).toString("base64");
|
|
255
|
+
|
|
256
|
+
const fileBuffer = fs.readFileSync(filePath);
|
|
257
|
+
const fileName = path.basename(filePath);
|
|
258
|
+
|
|
259
|
+
const formData = new FormData();
|
|
260
|
+
formData.append("file", new Blob([fileBuffer]), fileName);
|
|
261
|
+
if (metadata.title) formData.append("title", metadata.title);
|
|
262
|
+
if (metadata.alt_text) formData.append("alt_text", metadata.alt_text);
|
|
263
|
+
if (metadata.caption) formData.append("caption", metadata.caption);
|
|
264
|
+
if (metadata.description)
|
|
265
|
+
formData.append("description", metadata.description);
|
|
266
|
+
|
|
267
|
+
const startTime = Date.now();
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
const response = await fetch(`${baseUrl}${apiPath}/media`, {
|
|
271
|
+
method: "POST",
|
|
272
|
+
headers: {
|
|
273
|
+
Authorization: `Basic ${auth}`,
|
|
274
|
+
"User-Agent": "WordPress-MCP-Server/2.0.0",
|
|
275
|
+
},
|
|
276
|
+
body: formData,
|
|
277
|
+
timeout: 60000,
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
if (sessionId) {
|
|
281
|
+
sessionManager.logOperation(sessionId, {
|
|
282
|
+
type: "media_upload",
|
|
283
|
+
file: fileName,
|
|
284
|
+
status: response.status,
|
|
285
|
+
duration: Date.now() - startTime,
|
|
286
|
+
});
|
|
287
|
+
sessionManager.updateActivity(sessionId);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (!response.ok) {
|
|
291
|
+
let errorBody;
|
|
292
|
+
try {
|
|
293
|
+
errorBody = await response.json();
|
|
294
|
+
} catch {
|
|
295
|
+
errorBody = await response.text();
|
|
296
|
+
}
|
|
297
|
+
throw new MCPError({
|
|
298
|
+
code: response.status,
|
|
299
|
+
message: `Media upload failed: ${response.status} - ${response.statusText}`,
|
|
300
|
+
details: errorBody,
|
|
301
|
+
endpoint: "/media",
|
|
302
|
+
method: "POST",
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return await response.json();
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (sessionId) {
|
|
309
|
+
sessionManager.logOperation(sessionId, {
|
|
310
|
+
type: "media_upload_error",
|
|
311
|
+
file: fileName,
|
|
312
|
+
error: error.message,
|
|
313
|
+
duration: Date.now() - startTime,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
if (error instanceof MCPError) throw error;
|
|
317
|
+
throw new MCPError({
|
|
318
|
+
code: "UPLOAD_ERROR",
|
|
319
|
+
message: `Media upload error: ${error.message}`,
|
|
320
|
+
details: error,
|
|
321
|
+
endpoint: "/media",
|
|
322
|
+
method: "POST",
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Upload local assets referenced in content and replace paths with WordPress URLs
|
|
328
|
+
async function uploadAndReplaceAssets(content, basePath, sessionId = null) {
|
|
329
|
+
// Match both HTML <img> tags and markdown  image syntax
|
|
330
|
+
const patterns = [
|
|
331
|
+
/<img\s+[^>]*src=["'](assets\/[^"']+)["'][^>]*>/gi,
|
|
332
|
+
/!\[[^\]]*\]\((assets\/[^)]+)\)/gi,
|
|
333
|
+
];
|
|
334
|
+
const uploadedAssets = [];
|
|
335
|
+
let match;
|
|
336
|
+
const replacements = new Map();
|
|
337
|
+
|
|
338
|
+
for (const imgRegex of patterns) {
|
|
339
|
+
while ((match = imgRegex.exec(content)) !== null) {
|
|
340
|
+
const relativePath = match[1];
|
|
341
|
+
if (replacements.has(relativePath)) continue;
|
|
342
|
+
|
|
343
|
+
const absolutePath = path.resolve(basePath, relativePath);
|
|
344
|
+
if (!fs.existsSync(absolutePath)) {
|
|
345
|
+
uploadedAssets.push({
|
|
346
|
+
file: relativePath,
|
|
347
|
+
status: "skipped",
|
|
348
|
+
reason: "file not found",
|
|
349
|
+
});
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
const fileName = path.basename(
|
|
355
|
+
relativePath,
|
|
356
|
+
path.extname(relativePath),
|
|
357
|
+
);
|
|
358
|
+
const title = fileName.replace(/[-_]/g, " ");
|
|
359
|
+
const media = await wordpressUploadRequest(
|
|
360
|
+
absolutePath,
|
|
361
|
+
{ title },
|
|
362
|
+
sessionId,
|
|
363
|
+
);
|
|
364
|
+
replacements.set(relativePath, media.source_url);
|
|
365
|
+
uploadedAssets.push({
|
|
366
|
+
file: relativePath,
|
|
367
|
+
status: "uploaded",
|
|
368
|
+
media_id: media.id,
|
|
369
|
+
source_url: media.source_url,
|
|
370
|
+
});
|
|
371
|
+
} catch (error) {
|
|
372
|
+
uploadedAssets.push({
|
|
373
|
+
file: relativePath,
|
|
374
|
+
status: "error",
|
|
375
|
+
error: error.message,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
let updatedContent = content;
|
|
382
|
+
for (const [localPath, wpUrl] of replacements) {
|
|
383
|
+
updatedContent = updatedContent.replaceAll(localPath, wpUrl);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return { content: updatedContent, uploadedAssets };
|
|
232
387
|
}
|
|
233
388
|
|
|
234
389
|
// Custom error class for better error handling
|
|
235
390
|
class MCPError extends Error {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
391
|
+
constructor({ code, message, details, endpoint, method }) {
|
|
392
|
+
super(message);
|
|
393
|
+
this.name = "MCPError";
|
|
394
|
+
this.code = code;
|
|
395
|
+
this.details = details;
|
|
396
|
+
this.endpoint = endpoint;
|
|
397
|
+
this.method = method;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
toJSON() {
|
|
401
|
+
return {
|
|
402
|
+
success: false,
|
|
403
|
+
error: {
|
|
404
|
+
code: this.code,
|
|
405
|
+
message: this.message,
|
|
406
|
+
details: this.details,
|
|
407
|
+
endpoint: this.endpoint,
|
|
408
|
+
method: this.method,
|
|
409
|
+
timestamp: Date.now(),
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
}
|
|
258
413
|
}
|
|
259
414
|
|
|
260
415
|
// Enhanced response formatter
|
|
261
416
|
function formatMCPResponse(data, success = true) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
417
|
+
const response = {
|
|
418
|
+
success,
|
|
419
|
+
timestamp: Date.now(),
|
|
420
|
+
server_version: "2.0.0",
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
if (success) {
|
|
424
|
+
response.data = data;
|
|
425
|
+
} else {
|
|
426
|
+
response.error = data;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
content: [
|
|
431
|
+
{
|
|
432
|
+
type: "text",
|
|
433
|
+
text: JSON.stringify(response, null, 2),
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
};
|
|
280
437
|
}
|
|
281
438
|
|
|
282
439
|
// Tool execution wrapper with enhanced error handling
|
|
283
440
|
async function executeTool(toolName, params, handler) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
441
|
+
const sessionId =
|
|
442
|
+
sessionManager.activeSession || sessionManager.createSession();
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
sessionManager.updateActivity(sessionId);
|
|
446
|
+
|
|
447
|
+
const startTime = Date.now();
|
|
448
|
+
const result = await handler(params, sessionId);
|
|
449
|
+
const duration = Date.now() - startTime;
|
|
450
|
+
|
|
451
|
+
// Log successful operation
|
|
452
|
+
sessionManager.logOperation(sessionId, {
|
|
453
|
+
type: "tool_execution",
|
|
454
|
+
tool: toolName,
|
|
455
|
+
status: "success",
|
|
456
|
+
duration,
|
|
457
|
+
params: Object.keys(params || {}),
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
return result;
|
|
461
|
+
} catch (error) {
|
|
462
|
+
// Log failed operation
|
|
463
|
+
sessionManager.logOperation(sessionId, {
|
|
464
|
+
type: "tool_execution",
|
|
465
|
+
tool: toolName,
|
|
466
|
+
status: "error",
|
|
467
|
+
error: error.message,
|
|
468
|
+
params: Object.keys(params || {}),
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
if (error instanceof MCPError) {
|
|
472
|
+
return formatMCPResponse(error.toJSON().error, false);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return formatMCPResponse(
|
|
476
|
+
{
|
|
477
|
+
code: "TOOL_ERROR",
|
|
478
|
+
message: error.message,
|
|
479
|
+
tool: toolName,
|
|
480
|
+
timestamp: Date.now(),
|
|
481
|
+
},
|
|
482
|
+
false,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
325
485
|
}
|
|
326
486
|
|
|
327
487
|
// Register enhanced WordPress MCP Tools
|
|
328
488
|
|
|
329
489
|
// Session Management Tools
|
|
330
|
-
server.registerTool(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
});
|
|
490
|
+
server.registerTool(
|
|
491
|
+
"wp_session_create",
|
|
492
|
+
{
|
|
493
|
+
title: "Create WordPress Session",
|
|
494
|
+
description:
|
|
495
|
+
"Create a new session for tracking operations and maintaining context",
|
|
496
|
+
inputSchema: z.object({
|
|
497
|
+
session_id: z.string().optional().describe("Optional custom session ID"),
|
|
498
|
+
context: z
|
|
499
|
+
.object({})
|
|
500
|
+
.passthrough()
|
|
501
|
+
.optional()
|
|
502
|
+
.describe("Optional context data for the session"),
|
|
503
|
+
}),
|
|
504
|
+
},
|
|
505
|
+
async (params) => {
|
|
506
|
+
return executeTool("wp_session_create", params, async (params) => {
|
|
507
|
+
const sessionId = sessionManager.createSession(params.session_id);
|
|
508
|
+
if (params.context) {
|
|
509
|
+
const session = sessionManager.getSession(sessionId);
|
|
510
|
+
session.context = { ...session.context, ...params.context };
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return formatMCPResponse({
|
|
514
|
+
session_id: sessionId,
|
|
515
|
+
created: true,
|
|
516
|
+
message: "Session created successfully",
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
},
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
server.registerTool(
|
|
523
|
+
"wp_session_status",
|
|
524
|
+
{
|
|
525
|
+
title: "Get WordPress Session Status",
|
|
526
|
+
description: "Get current session information and operation history",
|
|
527
|
+
inputSchema: z.object({
|
|
528
|
+
session_id: z
|
|
529
|
+
.string()
|
|
530
|
+
.optional()
|
|
531
|
+
.describe("Session ID to check status for"),
|
|
532
|
+
}),
|
|
533
|
+
},
|
|
534
|
+
async (params) => {
|
|
535
|
+
return executeTool("wp_session_status", params, async (params) => {
|
|
536
|
+
const sessionId = params.session_id || sessionManager.activeSession;
|
|
537
|
+
if (!sessionId) {
|
|
538
|
+
throw new MCPError({
|
|
539
|
+
code: "NO_SESSION",
|
|
540
|
+
message: "No active session found",
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const session = sessionManager.getSession(sessionId);
|
|
545
|
+
if (!session) {
|
|
546
|
+
throw new MCPError({
|
|
547
|
+
code: "SESSION_NOT_FOUND",
|
|
548
|
+
message: `Session ${sessionId} not found`,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return formatMCPResponse({
|
|
553
|
+
session: {
|
|
554
|
+
id: session.id,
|
|
555
|
+
created: new Date(session.created).toISOString(),
|
|
556
|
+
last_activity: new Date(session.lastActivity).toISOString(),
|
|
557
|
+
operations_count: session.operations.length,
|
|
558
|
+
recent_operations: session.operations.slice(-5),
|
|
559
|
+
context: session.context,
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
});
|
|
563
|
+
},
|
|
564
|
+
);
|
|
406
565
|
|
|
407
566
|
// Memory Management Tools
|
|
408
|
-
server.registerTool(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
})
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
additionalProperties: false
|
|
498
|
-
}
|
|
499
|
-
}, async (params) => {
|
|
500
|
-
return executeTool('wp_memory_list', params, async (params) => {
|
|
501
|
-
const entries = memoryManager.list(params.namespace);
|
|
502
|
-
|
|
503
|
-
return formatMCPResponse({
|
|
504
|
-
namespace: params.namespace,
|
|
505
|
-
entries: entries,
|
|
506
|
-
count: entries.length
|
|
507
|
-
});
|
|
508
|
-
});
|
|
509
|
-
});
|
|
567
|
+
server.registerTool(
|
|
568
|
+
"wp_memory_store",
|
|
569
|
+
{
|
|
570
|
+
title: "Store WordPress Memory",
|
|
571
|
+
description: "Store data in memory for persistence across operations",
|
|
572
|
+
inputSchema: z.object({
|
|
573
|
+
key: z.string().describe("Memory key to store data under"),
|
|
574
|
+
value: z.any().describe("Value to store (any type)"),
|
|
575
|
+
namespace: z
|
|
576
|
+
.string()
|
|
577
|
+
.optional()
|
|
578
|
+
.default("wordpress")
|
|
579
|
+
.describe("Namespace to organize data"),
|
|
580
|
+
ttl: z.number().optional().describe("Time-to-live in milliseconds"),
|
|
581
|
+
}),
|
|
582
|
+
},
|
|
583
|
+
async (params) => {
|
|
584
|
+
return executeTool("wp_memory_store", params, async (params) => {
|
|
585
|
+
const stored = memoryManager.store(
|
|
586
|
+
params.key,
|
|
587
|
+
params.value,
|
|
588
|
+
params.namespace,
|
|
589
|
+
params.ttl,
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
return formatMCPResponse({
|
|
593
|
+
stored: stored,
|
|
594
|
+
key: params.key,
|
|
595
|
+
namespace: params.namespace,
|
|
596
|
+
ttl: params.ttl,
|
|
597
|
+
message: "Data stored successfully",
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
},
|
|
601
|
+
);
|
|
602
|
+
|
|
603
|
+
server.registerTool(
|
|
604
|
+
"wp_memory_retrieve",
|
|
605
|
+
{
|
|
606
|
+
title: "Retrieve WordPress Memory",
|
|
607
|
+
description: "Retrieve stored data from memory",
|
|
608
|
+
inputSchema: z.object({
|
|
609
|
+
key: z.string().describe("Memory key to retrieve"),
|
|
610
|
+
namespace: z
|
|
611
|
+
.string()
|
|
612
|
+
.optional()
|
|
613
|
+
.default("wordpress")
|
|
614
|
+
.describe("Namespace to search in"),
|
|
615
|
+
}),
|
|
616
|
+
},
|
|
617
|
+
async (params) => {
|
|
618
|
+
return executeTool("wp_memory_retrieve", params, async (params) => {
|
|
619
|
+
const value = memoryManager.retrieve(params.key, params.namespace);
|
|
620
|
+
|
|
621
|
+
return formatMCPResponse({
|
|
622
|
+
key: params.key,
|
|
623
|
+
namespace: params.namespace,
|
|
624
|
+
value: value,
|
|
625
|
+
found: value !== null,
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
},
|
|
629
|
+
);
|
|
630
|
+
|
|
631
|
+
server.registerTool(
|
|
632
|
+
"wp_memory_list",
|
|
633
|
+
{
|
|
634
|
+
title: "List WordPress Memory",
|
|
635
|
+
description: "List all stored data in a namespace",
|
|
636
|
+
inputSchema: z.object({
|
|
637
|
+
namespace: z
|
|
638
|
+
.string()
|
|
639
|
+
.optional()
|
|
640
|
+
.default("wordpress")
|
|
641
|
+
.describe("Namespace to list data from"),
|
|
642
|
+
}),
|
|
643
|
+
},
|
|
644
|
+
async (params) => {
|
|
645
|
+
return executeTool("wp_memory_list", params, async (params) => {
|
|
646
|
+
const entries = memoryManager.list(params.namespace);
|
|
647
|
+
|
|
648
|
+
return formatMCPResponse({
|
|
649
|
+
namespace: params.namespace,
|
|
650
|
+
entries: entries,
|
|
651
|
+
count: entries.length,
|
|
652
|
+
});
|
|
653
|
+
});
|
|
654
|
+
},
|
|
655
|
+
);
|
|
510
656
|
|
|
511
657
|
// Health and System Tools
|
|
512
|
-
server.registerTool(
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
658
|
+
server.registerTool(
|
|
659
|
+
"wp_health_check",
|
|
660
|
+
{
|
|
661
|
+
title: "WordPress Health Check",
|
|
662
|
+
description: "Comprehensive health check of WordPress site and MCP server",
|
|
663
|
+
inputSchema: z.object({
|
|
664
|
+
detailed: z
|
|
665
|
+
.boolean()
|
|
666
|
+
.optional()
|
|
667
|
+
.default(false)
|
|
668
|
+
.describe("Include detailed health metrics"),
|
|
669
|
+
}),
|
|
670
|
+
},
|
|
671
|
+
async (params) => {
|
|
672
|
+
return executeTool("wp_health_check", params, async (params, sessionId) => {
|
|
673
|
+
const checks = [];
|
|
674
|
+
|
|
675
|
+
try {
|
|
676
|
+
// Test WordPress API connectivity
|
|
677
|
+
const startTime = Date.now();
|
|
678
|
+
const response = await wordpressRequest("/", "GET", null, sessionId);
|
|
679
|
+
checks.push({
|
|
680
|
+
name: "WordPress API Connectivity",
|
|
681
|
+
status: "passed",
|
|
682
|
+
response_time: Date.now() - startTime,
|
|
683
|
+
message: "API is responding",
|
|
684
|
+
});
|
|
685
|
+
} catch (error) {
|
|
686
|
+
checks.push({
|
|
687
|
+
name: "WordPress API Connectivity",
|
|
688
|
+
status: "failed",
|
|
689
|
+
error: error.message,
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// Check authentication
|
|
694
|
+
try {
|
|
695
|
+
await wordpressRequest("/users/me", "GET", null, sessionId);
|
|
696
|
+
checks.push({
|
|
697
|
+
name: "Authentication",
|
|
698
|
+
status: "passed",
|
|
699
|
+
message: "Authentication working",
|
|
700
|
+
});
|
|
701
|
+
} catch (error) {
|
|
702
|
+
checks.push({
|
|
703
|
+
name: "Authentication",
|
|
704
|
+
status: "failed",
|
|
705
|
+
error: error.message,
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Session status
|
|
710
|
+
const activeSessionCount = sessionManager.sessions.size;
|
|
711
|
+
checks.push({
|
|
712
|
+
name: "Session Management",
|
|
713
|
+
status: "passed",
|
|
714
|
+
active_sessions: activeSessionCount,
|
|
715
|
+
current_session: sessionId,
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// Memory status
|
|
719
|
+
const memoryEntries = memoryManager.list("wordpress");
|
|
720
|
+
checks.push({
|
|
721
|
+
name: "Memory Management",
|
|
722
|
+
status: "passed",
|
|
723
|
+
stored_entries: memoryEntries.length,
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
const overall = checks.every((check) => check.status === "passed");
|
|
727
|
+
|
|
728
|
+
return formatMCPResponse({
|
|
729
|
+
overall_status: overall ? "healthy" : "unhealthy",
|
|
730
|
+
checks: checks,
|
|
731
|
+
timestamp: Date.now(),
|
|
732
|
+
server_version: "2.0.0",
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
},
|
|
736
|
+
);
|
|
591
737
|
|
|
592
738
|
// Get site information
|
|
593
|
-
server.registerTool(
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
739
|
+
server.registerTool(
|
|
740
|
+
"wp_get_site_info",
|
|
741
|
+
{
|
|
742
|
+
title: "Get WordPress Site Information",
|
|
743
|
+
description:
|
|
744
|
+
"Get WordPress site statistics, version, and health information",
|
|
745
|
+
inputSchema: z.object({
|
|
746
|
+
include_health: z
|
|
747
|
+
.boolean()
|
|
748
|
+
.optional()
|
|
749
|
+
.default(false)
|
|
750
|
+
.describe("Include health metrics in response"),
|
|
751
|
+
cache_duration: z
|
|
752
|
+
.number()
|
|
753
|
+
.optional()
|
|
754
|
+
.default(300)
|
|
755
|
+
.describe("Cache duration in seconds"),
|
|
756
|
+
}),
|
|
757
|
+
},
|
|
758
|
+
async (params) => {
|
|
759
|
+
return executeTool(
|
|
760
|
+
"wp_get_site_info",
|
|
761
|
+
params,
|
|
762
|
+
async (params, sessionId) => {
|
|
763
|
+
// Check cache first
|
|
764
|
+
const cacheKey = `site_info_${WORDPRESS_URL}`;
|
|
765
|
+
const cached = memoryManager.retrieve(cacheKey, "cache");
|
|
766
|
+
if (
|
|
767
|
+
cached &&
|
|
768
|
+
Date.now() - cached.timestamp < params.cache_duration * 1000
|
|
769
|
+
) {
|
|
770
|
+
return formatMCPResponse({
|
|
771
|
+
...cached.data,
|
|
772
|
+
cached: true,
|
|
773
|
+
cache_age: Math.floor((Date.now() - cached.timestamp) / 1000),
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// Get site info from multiple endpoints
|
|
778
|
+
const [users, posts, plugins] = await Promise.all([
|
|
779
|
+
wordpressRequest("/users", "GET", null, sessionId),
|
|
780
|
+
wordpressRequest("/posts?per_page=1", "GET", null, sessionId),
|
|
781
|
+
wordpressRequest("/plugins", "GET", null, sessionId).catch(() => []), // Plugins endpoint might not be available
|
|
782
|
+
]);
|
|
783
|
+
|
|
784
|
+
const siteInfo = {
|
|
785
|
+
site_url: WORDPRESS_URL,
|
|
786
|
+
total_users: users.length,
|
|
787
|
+
total_posts: posts.length,
|
|
788
|
+
total_plugins: plugins.length,
|
|
789
|
+
wordpress_version: "Available via REST API",
|
|
790
|
+
server_version: "2.0.0",
|
|
791
|
+
last_updated: new Date().toISOString(),
|
|
792
|
+
message: "Site information retrieved successfully",
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
// Store in cache
|
|
796
|
+
memoryManager.store(
|
|
797
|
+
cacheKey,
|
|
798
|
+
{
|
|
799
|
+
data: siteInfo,
|
|
800
|
+
timestamp: Date.now(),
|
|
801
|
+
},
|
|
802
|
+
"cache",
|
|
803
|
+
params.cache_duration * 1000,
|
|
804
|
+
);
|
|
805
|
+
|
|
806
|
+
if (params.include_health) {
|
|
807
|
+
// Include basic health metrics
|
|
808
|
+
siteInfo.health_metrics = {
|
|
809
|
+
api_responsive: true,
|
|
810
|
+
authenticated: true,
|
|
811
|
+
last_check: Date.now(),
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
return formatMCPResponse(siteInfo);
|
|
816
|
+
},
|
|
817
|
+
);
|
|
818
|
+
},
|
|
819
|
+
);
|
|
661
820
|
|
|
662
821
|
// List posts
|
|
663
|
-
server.registerTool(
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
822
|
+
server.registerTool(
|
|
823
|
+
"wp_list_posts",
|
|
824
|
+
{
|
|
825
|
+
title: "List WordPress Posts",
|
|
826
|
+
description: "Get posts with filtering options",
|
|
827
|
+
inputSchema: z.object({
|
|
828
|
+
per_page: z.number().optional().default(10),
|
|
829
|
+
page: z.number().optional().default(1),
|
|
830
|
+
status: z.string().optional().default("publish"),
|
|
831
|
+
search: z.string().optional(),
|
|
832
|
+
categories: z.array(z.number()).optional(),
|
|
833
|
+
tags: z.array(z.number()).optional(),
|
|
834
|
+
}),
|
|
835
|
+
},
|
|
836
|
+
async (params) => {
|
|
837
|
+
try {
|
|
838
|
+
const queryParams = new URLSearchParams();
|
|
839
|
+
|
|
840
|
+
queryParams.append("per_page", params.per_page.toString());
|
|
841
|
+
queryParams.append("page", params.page.toString());
|
|
842
|
+
queryParams.append("status", params.status);
|
|
843
|
+
|
|
844
|
+
if (params.search) queryParams.append("search", params.search);
|
|
845
|
+
if (params.categories)
|
|
846
|
+
queryParams.append("categories", params.categories.join(","));
|
|
847
|
+
if (params.tags) queryParams.append("tags", params.tags.join(","));
|
|
848
|
+
|
|
849
|
+
const posts = await wordpressRequest(`/posts?${queryParams.toString()}`);
|
|
850
|
+
|
|
851
|
+
return {
|
|
852
|
+
content: [
|
|
853
|
+
{
|
|
854
|
+
type: "text",
|
|
855
|
+
text: JSON.stringify(
|
|
856
|
+
{
|
|
857
|
+
success: true,
|
|
858
|
+
posts: posts.map((post) => ({
|
|
859
|
+
id: post.id,
|
|
860
|
+
title: post.title.rendered,
|
|
861
|
+
status: post.status,
|
|
862
|
+
date: post.date,
|
|
863
|
+
link: post.link,
|
|
864
|
+
excerpt: post.excerpt.rendered.replace(/<[^>]*>/g, "").trim(),
|
|
865
|
+
})),
|
|
866
|
+
total: posts.length,
|
|
867
|
+
},
|
|
868
|
+
null,
|
|
869
|
+
2,
|
|
870
|
+
),
|
|
871
|
+
},
|
|
872
|
+
],
|
|
873
|
+
};
|
|
874
|
+
} catch (error) {
|
|
875
|
+
return {
|
|
876
|
+
content: [
|
|
877
|
+
{
|
|
878
|
+
type: "text",
|
|
879
|
+
text: JSON.stringify(
|
|
880
|
+
{
|
|
881
|
+
success: false,
|
|
882
|
+
error: error.message,
|
|
883
|
+
},
|
|
884
|
+
null,
|
|
885
|
+
2,
|
|
886
|
+
),
|
|
887
|
+
},
|
|
888
|
+
],
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
);
|
|
717
893
|
|
|
718
894
|
// Create post
|
|
719
|
-
server.registerTool(
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
895
|
+
server.registerTool(
|
|
896
|
+
"wp_create_post",
|
|
897
|
+
{
|
|
898
|
+
title: "Create WordPress Post",
|
|
899
|
+
description:
|
|
900
|
+
"Create a new WordPress post or page with enhanced tracking and validation",
|
|
901
|
+
inputSchema: z.object({
|
|
902
|
+
title: z.string().min(1).describe("Post title (required)"),
|
|
903
|
+
content: z.string().min(1).describe("Post content (required)"),
|
|
904
|
+
status: z
|
|
905
|
+
.enum(["draft", "publish", "private", "pending"])
|
|
906
|
+
.optional()
|
|
907
|
+
.default("draft")
|
|
908
|
+
.describe("Post status"),
|
|
909
|
+
excerpt: z.string().optional().describe("Post excerpt"),
|
|
910
|
+
slug: z.string().optional().describe("Post slug/URL"),
|
|
911
|
+
categories: z
|
|
912
|
+
.array(z.number())
|
|
913
|
+
.optional()
|
|
914
|
+
.default([])
|
|
915
|
+
.describe("Category IDs"),
|
|
916
|
+
tags: z.array(z.number()).optional().default([]).describe("Tag IDs"),
|
|
917
|
+
use_gutenberg: z
|
|
918
|
+
.boolean()
|
|
919
|
+
.optional()
|
|
920
|
+
.default(false)
|
|
921
|
+
.describe("Use Gutenberg block format"),
|
|
922
|
+
store_in_memory: z
|
|
923
|
+
.boolean()
|
|
924
|
+
.optional()
|
|
925
|
+
.default(true)
|
|
926
|
+
.describe("Store post data in memory for tracking"),
|
|
927
|
+
content_base_path: z
|
|
928
|
+
.string()
|
|
929
|
+
.optional()
|
|
930
|
+
.describe(
|
|
931
|
+
"Base directory path to resolve relative asset references (e.g. assets/image.svg) in content. When provided, local assets are uploaded to the media library and URLs are replaced.",
|
|
932
|
+
),
|
|
933
|
+
}),
|
|
934
|
+
},
|
|
935
|
+
async (params) => {
|
|
936
|
+
return executeTool("wp_create_post", params, async (params, sessionId) => {
|
|
937
|
+
// Upload local assets if content_base_path is provided
|
|
938
|
+
let content = params.content;
|
|
939
|
+
let uploadedAssets = [];
|
|
940
|
+
if (params.content_base_path) {
|
|
941
|
+
const assetResult = await uploadAndReplaceAssets(
|
|
942
|
+
content,
|
|
943
|
+
params.content_base_path,
|
|
944
|
+
sessionId,
|
|
945
|
+
);
|
|
946
|
+
content = assetResult.content;
|
|
947
|
+
uploadedAssets = assetResult.uploadedAssets;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// Convert content to Gutenberg format if requested
|
|
951
|
+
const useGutenberg =
|
|
952
|
+
params.use_gutenberg || params.gutenberg || WORDPRESS_USE_GUTENBERG;
|
|
953
|
+
|
|
954
|
+
if (useGutenberg) {
|
|
955
|
+
try {
|
|
956
|
+
content = GutenbergConverter.toGutenberg(content);
|
|
957
|
+
} catch (gutenbergError) {
|
|
958
|
+
// If Gutenberg conversion fails, log warning but continue with original content
|
|
959
|
+
sessionManager.logOperation(sessionId, {
|
|
960
|
+
type: "warning",
|
|
961
|
+
message: "Gutenberg conversion failed, using original content",
|
|
962
|
+
error: gutenbergError.message,
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
const postData = {
|
|
968
|
+
title: params.title,
|
|
969
|
+
content: content,
|
|
970
|
+
status: params.status,
|
|
971
|
+
categories: params.categories,
|
|
972
|
+
tags: params.tags,
|
|
973
|
+
};
|
|
974
|
+
|
|
975
|
+
// Add optional fields
|
|
976
|
+
if (params.excerpt) postData.excerpt = params.excerpt;
|
|
977
|
+
if (params.slug) postData.slug = params.slug;
|
|
978
|
+
if (params.meta) postData.meta = params.meta;
|
|
979
|
+
if (params.featured_media)
|
|
980
|
+
postData.featured_media = params.featured_media;
|
|
981
|
+
if (params.author) postData.author = params.author;
|
|
982
|
+
if (params.comment_status)
|
|
983
|
+
postData.comment_status = params.comment_status;
|
|
984
|
+
if (params.ping_status) postData.ping_status = params.ping_status;
|
|
985
|
+
|
|
986
|
+
const post = await wordpressRequest(
|
|
987
|
+
"/posts",
|
|
988
|
+
"POST",
|
|
989
|
+
postData,
|
|
990
|
+
sessionId,
|
|
991
|
+
);
|
|
992
|
+
|
|
993
|
+
const result = {
|
|
994
|
+
post_id: post.id,
|
|
995
|
+
post_url: post.link,
|
|
996
|
+
edit_url: `${WORDPRESS_URL.replace(/\/$/, "")}/wp-admin/post.php?post=${post.id}&action=edit`,
|
|
997
|
+
title: post.title.rendered,
|
|
998
|
+
status: post.status,
|
|
999
|
+
date: post.date,
|
|
1000
|
+
modified: post.modified,
|
|
1001
|
+
gutenberg_used: useGutenberg,
|
|
1002
|
+
categories: post.categories,
|
|
1003
|
+
tags: post.tags,
|
|
1004
|
+
uploaded_assets: uploadedAssets.length > 0 ? uploadedAssets : undefined,
|
|
1005
|
+
message: `Post created successfully with ${useGutenberg ? "Gutenberg" : "Classic"} editor format`,
|
|
1006
|
+
};
|
|
1007
|
+
|
|
1008
|
+
// Store post reference in memory if requested
|
|
1009
|
+
if (params.store_in_memory) {
|
|
1010
|
+
memoryManager.store(
|
|
1011
|
+
`created_post_${post.id}`,
|
|
1012
|
+
{
|
|
1013
|
+
...result,
|
|
1014
|
+
original_params: params,
|
|
1015
|
+
created_at: Date.now(),
|
|
1016
|
+
},
|
|
1017
|
+
"posts",
|
|
1018
|
+
3600000,
|
|
1019
|
+
); // 1 hour TTL
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
return formatMCPResponse(result);
|
|
1023
|
+
});
|
|
1024
|
+
},
|
|
1025
|
+
);
|
|
839
1026
|
|
|
840
1027
|
// Update post
|
|
841
|
-
server.registerTool(
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1028
|
+
server.registerTool(
|
|
1029
|
+
"wp_update_post",
|
|
1030
|
+
{
|
|
1031
|
+
title: "Update WordPress Post",
|
|
1032
|
+
description: "Update an existing WordPress post",
|
|
1033
|
+
inputSchema: z.object({
|
|
1034
|
+
id: z.number(),
|
|
1035
|
+
title: z.string().optional(),
|
|
1036
|
+
content: z.string().optional(),
|
|
1037
|
+
status: z.string().optional(),
|
|
1038
|
+
excerpt: z.string().optional(),
|
|
1039
|
+
slug: z.string().optional(),
|
|
1040
|
+
categories: z.array(z.number()).optional(),
|
|
1041
|
+
tags: z.array(z.number()).optional(),
|
|
1042
|
+
}),
|
|
1043
|
+
},
|
|
1044
|
+
async (params) => {
|
|
1045
|
+
try {
|
|
1046
|
+
const { id, ...updateData } = params;
|
|
1047
|
+
const filteredData = Object.fromEntries(
|
|
1048
|
+
Object.entries(updateData).filter(([_, value]) => value !== undefined),
|
|
1049
|
+
);
|
|
1050
|
+
|
|
1051
|
+
const post = await wordpressRequest(`/posts/${id}`, "POST", filteredData);
|
|
1052
|
+
|
|
1053
|
+
return {
|
|
1054
|
+
content: [
|
|
1055
|
+
{
|
|
1056
|
+
type: "text",
|
|
1057
|
+
text: JSON.stringify(
|
|
1058
|
+
{
|
|
1059
|
+
success: true,
|
|
1060
|
+
post_id: post.id,
|
|
1061
|
+
post_url: post.link,
|
|
1062
|
+
message: "Post updated successfully",
|
|
1063
|
+
},
|
|
1064
|
+
null,
|
|
1065
|
+
2,
|
|
1066
|
+
),
|
|
1067
|
+
},
|
|
1068
|
+
],
|
|
1069
|
+
};
|
|
1070
|
+
} catch (error) {
|
|
1071
|
+
return {
|
|
1072
|
+
content: [
|
|
1073
|
+
{
|
|
1074
|
+
type: "text",
|
|
1075
|
+
text: JSON.stringify(
|
|
1076
|
+
{
|
|
1077
|
+
success: false,
|
|
1078
|
+
error: error.message,
|
|
1079
|
+
},
|
|
1080
|
+
null,
|
|
1081
|
+
2,
|
|
1082
|
+
),
|
|
1083
|
+
},
|
|
1084
|
+
],
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
},
|
|
1088
|
+
);
|
|
886
1089
|
|
|
887
1090
|
// Delete post
|
|
888
|
-
server.registerTool(
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
1091
|
+
server.registerTool(
|
|
1092
|
+
"wp_delete_post",
|
|
1093
|
+
{
|
|
1094
|
+
title: "Delete WordPress Post",
|
|
1095
|
+
description: "Delete a WordPress post (move to trash)",
|
|
1096
|
+
inputSchema: z.object({
|
|
1097
|
+
id: z.number(),
|
|
1098
|
+
}),
|
|
1099
|
+
},
|
|
1100
|
+
async (params) => {
|
|
1101
|
+
try {
|
|
1102
|
+
const post = await wordpressRequest(`/posts/${params.id}`, "DELETE");
|
|
1103
|
+
|
|
1104
|
+
return {
|
|
1105
|
+
content: [
|
|
1106
|
+
{
|
|
1107
|
+
type: "text",
|
|
1108
|
+
text: JSON.stringify(
|
|
1109
|
+
{
|
|
1110
|
+
success: true,
|
|
1111
|
+
post_id: post.id,
|
|
1112
|
+
message: "Post deleted successfully",
|
|
1113
|
+
},
|
|
1114
|
+
null,
|
|
1115
|
+
2,
|
|
1116
|
+
),
|
|
1117
|
+
},
|
|
1118
|
+
],
|
|
1119
|
+
};
|
|
1120
|
+
} catch (error) {
|
|
1121
|
+
return {
|
|
1122
|
+
content: [
|
|
1123
|
+
{
|
|
1124
|
+
type: "text",
|
|
1125
|
+
text: JSON.stringify(
|
|
1126
|
+
{
|
|
1127
|
+
success: false,
|
|
1128
|
+
error: error.message,
|
|
1129
|
+
},
|
|
1130
|
+
null,
|
|
1131
|
+
2,
|
|
1132
|
+
),
|
|
1133
|
+
},
|
|
1134
|
+
],
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
},
|
|
1138
|
+
);
|
|
920
1139
|
|
|
921
1140
|
// List users
|
|
922
|
-
server.registerTool(
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1141
|
+
server.registerTool(
|
|
1142
|
+
"wp_list_users",
|
|
1143
|
+
{
|
|
1144
|
+
title: "List WordPress Users",
|
|
1145
|
+
description: "Get WordPress user accounts and roles",
|
|
1146
|
+
inputSchema: z.object({
|
|
1147
|
+
per_page: z.number().optional().default(100),
|
|
1148
|
+
role: z.string().optional(),
|
|
1149
|
+
}),
|
|
1150
|
+
},
|
|
1151
|
+
async (params) => {
|
|
1152
|
+
try {
|
|
1153
|
+
const queryParams = new URLSearchParams();
|
|
1154
|
+
queryParams.append("per_page", params.per_page.toString());
|
|
1155
|
+
if (params.role) queryParams.append("role", params.role);
|
|
1156
|
+
|
|
1157
|
+
const users = await wordpressRequest(`/users?${queryParams.toString()}`);
|
|
1158
|
+
|
|
1159
|
+
return {
|
|
1160
|
+
content: [
|
|
1161
|
+
{
|
|
1162
|
+
type: "text",
|
|
1163
|
+
text: JSON.stringify(
|
|
1164
|
+
{
|
|
1165
|
+
success: true,
|
|
1166
|
+
users: users.map((user) => ({
|
|
1167
|
+
id: user.id,
|
|
1168
|
+
username: user.username,
|
|
1169
|
+
name: user.name,
|
|
1170
|
+
email: user.email,
|
|
1171
|
+
roles: user.roles,
|
|
1172
|
+
registered_date: user.registered_date,
|
|
1173
|
+
})),
|
|
1174
|
+
total: users.length,
|
|
1175
|
+
},
|
|
1176
|
+
null,
|
|
1177
|
+
2,
|
|
1178
|
+
),
|
|
1179
|
+
},
|
|
1180
|
+
],
|
|
1181
|
+
};
|
|
1182
|
+
} catch (error) {
|
|
1183
|
+
return {
|
|
1184
|
+
content: [
|
|
1185
|
+
{
|
|
1186
|
+
type: "text",
|
|
1187
|
+
text: JSON.stringify(
|
|
1188
|
+
{
|
|
1189
|
+
success: false,
|
|
1190
|
+
error: error.message,
|
|
1191
|
+
},
|
|
1192
|
+
null,
|
|
1193
|
+
2,
|
|
1194
|
+
),
|
|
1195
|
+
},
|
|
1196
|
+
],
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
},
|
|
1200
|
+
);
|
|
966
1201
|
|
|
967
1202
|
// Create user
|
|
968
|
-
server.registerTool(
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1203
|
+
server.registerTool(
|
|
1204
|
+
"wp_create_user",
|
|
1205
|
+
{
|
|
1206
|
+
title: "Create WordPress User",
|
|
1207
|
+
description: "Add a new WordPress user account",
|
|
1208
|
+
inputSchema: z.object({
|
|
1209
|
+
username: z.string(),
|
|
1210
|
+
email: z.string().email(),
|
|
1211
|
+
password: z.string(),
|
|
1212
|
+
roles: z.array(z.string()).optional().default(["subscriber"]),
|
|
1213
|
+
}),
|
|
1214
|
+
},
|
|
1215
|
+
async (params) => {
|
|
1216
|
+
try {
|
|
1217
|
+
const userData = {
|
|
1218
|
+
username: params.username,
|
|
1219
|
+
email: params.email,
|
|
1220
|
+
password: params.password,
|
|
1221
|
+
roles: params.roles,
|
|
1222
|
+
};
|
|
1223
|
+
|
|
1224
|
+
const user = await wordpressRequest("/users", "POST", userData);
|
|
1225
|
+
|
|
1226
|
+
return {
|
|
1227
|
+
content: [
|
|
1228
|
+
{
|
|
1229
|
+
type: "text",
|
|
1230
|
+
text: JSON.stringify(
|
|
1231
|
+
{
|
|
1232
|
+
success: true,
|
|
1233
|
+
user_id: user.id,
|
|
1234
|
+
username: user.username,
|
|
1235
|
+
email: user.email,
|
|
1236
|
+
roles: user.roles,
|
|
1237
|
+
message: "User created successfully",
|
|
1238
|
+
},
|
|
1239
|
+
null,
|
|
1240
|
+
2,
|
|
1241
|
+
),
|
|
1242
|
+
},
|
|
1243
|
+
],
|
|
1244
|
+
};
|
|
1245
|
+
} catch (error) {
|
|
1246
|
+
return {
|
|
1247
|
+
content: [
|
|
1248
|
+
{
|
|
1249
|
+
type: "text",
|
|
1250
|
+
text: JSON.stringify(
|
|
1251
|
+
{
|
|
1252
|
+
success: false,
|
|
1253
|
+
error: error.message,
|
|
1254
|
+
},
|
|
1255
|
+
null,
|
|
1256
|
+
2,
|
|
1257
|
+
),
|
|
1258
|
+
},
|
|
1259
|
+
],
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
},
|
|
1263
|
+
);
|
|
1013
1264
|
|
|
1014
1265
|
// Update user
|
|
1015
|
-
server.registerTool(
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1266
|
+
server.registerTool(
|
|
1267
|
+
"wp_update_user",
|
|
1268
|
+
{
|
|
1269
|
+
title: "Update WordPress User",
|
|
1270
|
+
description: "Modify WordPress user settings",
|
|
1271
|
+
inputSchema: z.object({
|
|
1272
|
+
id: z.number(),
|
|
1273
|
+
email: z.string().email().optional(),
|
|
1274
|
+
roles: z.array(z.string()).optional(),
|
|
1275
|
+
password: z.string().optional(),
|
|
1276
|
+
}),
|
|
1277
|
+
},
|
|
1278
|
+
async (params) => {
|
|
1279
|
+
try {
|
|
1280
|
+
const { id, ...updateData } = params;
|
|
1281
|
+
const filteredData = Object.fromEntries(
|
|
1282
|
+
Object.entries(updateData).filter(([_, value]) => value !== undefined),
|
|
1283
|
+
);
|
|
1284
|
+
|
|
1285
|
+
const user = await wordpressRequest(`/users/${id}`, "POST", filteredData);
|
|
1286
|
+
|
|
1287
|
+
return {
|
|
1288
|
+
content: [
|
|
1289
|
+
{
|
|
1290
|
+
type: "text",
|
|
1291
|
+
text: JSON.stringify(
|
|
1292
|
+
{
|
|
1293
|
+
success: true,
|
|
1294
|
+
user_id: user.id,
|
|
1295
|
+
username: user.username,
|
|
1296
|
+
email: user.email,
|
|
1297
|
+
roles: user.roles,
|
|
1298
|
+
message: "User updated successfully",
|
|
1299
|
+
},
|
|
1300
|
+
null,
|
|
1301
|
+
2,
|
|
1302
|
+
),
|
|
1303
|
+
},
|
|
1304
|
+
],
|
|
1305
|
+
};
|
|
1306
|
+
} catch (error) {
|
|
1307
|
+
return {
|
|
1308
|
+
content: [
|
|
1309
|
+
{
|
|
1310
|
+
type: "text",
|
|
1311
|
+
text: JSON.stringify(
|
|
1312
|
+
{
|
|
1313
|
+
success: false,
|
|
1314
|
+
error: error.message,
|
|
1315
|
+
},
|
|
1316
|
+
null,
|
|
1317
|
+
2,
|
|
1318
|
+
),
|
|
1319
|
+
},
|
|
1320
|
+
],
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
},
|
|
1324
|
+
);
|
|
1058
1325
|
|
|
1059
1326
|
// List plugins (if available)
|
|
1060
|
-
server.registerTool(
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1327
|
+
server.registerTool(
|
|
1328
|
+
"wp_list_plugins",
|
|
1329
|
+
{
|
|
1330
|
+
title: "List WordPress Plugins",
|
|
1331
|
+
description: "Get installed WordPress plugins",
|
|
1332
|
+
inputSchema: z.object({}),
|
|
1333
|
+
},
|
|
1334
|
+
async () => {
|
|
1335
|
+
try {
|
|
1336
|
+
const plugins = await wordpressRequest("/plugins");
|
|
1337
|
+
|
|
1338
|
+
return {
|
|
1339
|
+
content: [
|
|
1340
|
+
{
|
|
1341
|
+
type: "text",
|
|
1342
|
+
text: JSON.stringify(
|
|
1343
|
+
{
|
|
1344
|
+
success: true,
|
|
1345
|
+
plugins: plugins.map((plugin) => ({
|
|
1346
|
+
name: plugin.name,
|
|
1347
|
+
plugin: plugin.plugin,
|
|
1348
|
+
status: plugin.status,
|
|
1349
|
+
version: plugin.version,
|
|
1350
|
+
})),
|
|
1351
|
+
total: plugins.length,
|
|
1352
|
+
},
|
|
1353
|
+
null,
|
|
1354
|
+
2,
|
|
1355
|
+
),
|
|
1356
|
+
},
|
|
1357
|
+
],
|
|
1358
|
+
};
|
|
1359
|
+
} catch (error) {
|
|
1360
|
+
return {
|
|
1361
|
+
content: [
|
|
1362
|
+
{
|
|
1363
|
+
type: "text",
|
|
1364
|
+
text: JSON.stringify(
|
|
1365
|
+
{
|
|
1366
|
+
success: false,
|
|
1367
|
+
error: error.message,
|
|
1368
|
+
note: "Plugins endpoint may not be available on all WordPress installations",
|
|
1369
|
+
},
|
|
1370
|
+
null,
|
|
1371
|
+
2,
|
|
1372
|
+
),
|
|
1373
|
+
},
|
|
1374
|
+
],
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
},
|
|
1378
|
+
);
|
|
1096
1379
|
|
|
1097
1380
|
// Get media
|
|
1098
|
-
server.registerTool(
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1381
|
+
server.registerTool(
|
|
1382
|
+
"wp_get_media",
|
|
1383
|
+
{
|
|
1384
|
+
title: "Get WordPress Media",
|
|
1385
|
+
description: "Access WordPress media library",
|
|
1386
|
+
inputSchema: z.object({
|
|
1387
|
+
per_page: z.number().optional().default(10),
|
|
1388
|
+
media_type: z.string().optional(),
|
|
1389
|
+
}),
|
|
1390
|
+
},
|
|
1391
|
+
async (params) => {
|
|
1392
|
+
try {
|
|
1393
|
+
const queryParams = new URLSearchParams();
|
|
1394
|
+
queryParams.append("per_page", params.per_page.toString());
|
|
1395
|
+
if (params.media_type)
|
|
1396
|
+
queryParams.append("media_type", params.media_type);
|
|
1397
|
+
|
|
1398
|
+
const media = await wordpressRequest(`/media?${queryParams.toString()}`);
|
|
1399
|
+
|
|
1400
|
+
return {
|
|
1401
|
+
content: [
|
|
1402
|
+
{
|
|
1403
|
+
type: "text",
|
|
1404
|
+
text: JSON.stringify(
|
|
1405
|
+
{
|
|
1406
|
+
success: true,
|
|
1407
|
+
media: media.map((item) => ({
|
|
1408
|
+
id: item.id,
|
|
1409
|
+
title: item.title.rendered,
|
|
1410
|
+
source_url: item.source_url,
|
|
1411
|
+
media_type: item.media_type,
|
|
1412
|
+
mime_type: item.mime_type,
|
|
1413
|
+
date: item.date,
|
|
1414
|
+
})),
|
|
1415
|
+
total: media.length,
|
|
1416
|
+
},
|
|
1417
|
+
null,
|
|
1418
|
+
2,
|
|
1419
|
+
),
|
|
1420
|
+
},
|
|
1421
|
+
],
|
|
1422
|
+
};
|
|
1423
|
+
} catch (error) {
|
|
1424
|
+
return {
|
|
1425
|
+
content: [
|
|
1426
|
+
{
|
|
1427
|
+
type: "text",
|
|
1428
|
+
text: JSON.stringify(
|
|
1429
|
+
{
|
|
1430
|
+
success: false,
|
|
1431
|
+
error: error.message,
|
|
1432
|
+
},
|
|
1433
|
+
null,
|
|
1434
|
+
2,
|
|
1435
|
+
),
|
|
1436
|
+
},
|
|
1437
|
+
],
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
},
|
|
1441
|
+
);
|
|
1142
1442
|
|
|
1143
1443
|
// Batch operations tool
|
|
1144
|
-
server.registerTool(
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1444
|
+
server.registerTool(
|
|
1445
|
+
"wp_batch_publish",
|
|
1446
|
+
{
|
|
1447
|
+
title: "WordPress Batch Publish",
|
|
1448
|
+
description:
|
|
1449
|
+
"Publish multiple posts from markdown files with enhanced tracking",
|
|
1450
|
+
inputSchema: z.object({
|
|
1451
|
+
files: z.array(
|
|
1452
|
+
z.object({
|
|
1453
|
+
path: z.string(),
|
|
1454
|
+
title: z.string().optional(),
|
|
1455
|
+
status: z
|
|
1456
|
+
.enum(["draft", "publish", "private", "pending"])
|
|
1457
|
+
.optional()
|
|
1458
|
+
.default("draft"),
|
|
1459
|
+
categories: z.array(z.number()).optional().default([]),
|
|
1460
|
+
tags: z.array(z.number()).optional().default([]),
|
|
1461
|
+
}),
|
|
1462
|
+
),
|
|
1463
|
+
use_gutenberg: z.boolean().optional().default(WORDPRESS_USE_GUTENBERG),
|
|
1464
|
+
upload_assets: z
|
|
1465
|
+
.boolean()
|
|
1466
|
+
.optional()
|
|
1467
|
+
.default(true)
|
|
1468
|
+
.describe(
|
|
1469
|
+
"Upload local assets referenced in content (e.g. assets/image.svg) to the media library",
|
|
1470
|
+
),
|
|
1471
|
+
dry_run: z.boolean().optional().default(false),
|
|
1472
|
+
}),
|
|
1473
|
+
},
|
|
1474
|
+
async (params) => {
|
|
1475
|
+
return executeTool(
|
|
1476
|
+
"wp_batch_publish",
|
|
1477
|
+
params,
|
|
1478
|
+
async (params, sessionId) => {
|
|
1479
|
+
const results = [];
|
|
1480
|
+
const errors = [];
|
|
1481
|
+
|
|
1482
|
+
for (const file of params.files) {
|
|
1483
|
+
try {
|
|
1484
|
+
if (params.dry_run) {
|
|
1485
|
+
results.push({
|
|
1486
|
+
file: file.path,
|
|
1487
|
+
status: "dry_run",
|
|
1488
|
+
message: "Would process this file",
|
|
1489
|
+
});
|
|
1490
|
+
continue;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
// Read actual file content
|
|
1494
|
+
let fileContent;
|
|
1495
|
+
try {
|
|
1496
|
+
fileContent = fs.readFileSync(file.path, "utf-8");
|
|
1497
|
+
} catch {
|
|
1498
|
+
errors.push({
|
|
1499
|
+
file: file.path,
|
|
1500
|
+
error: `Could not read file: ${file.path}`,
|
|
1501
|
+
status: "error",
|
|
1502
|
+
});
|
|
1503
|
+
continue;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// Upload local assets if enabled
|
|
1507
|
+
let uploadedAssets = [];
|
|
1508
|
+
if (params.upload_assets) {
|
|
1509
|
+
const basePath = path.dirname(file.path);
|
|
1510
|
+
const assetResult = await uploadAndReplaceAssets(
|
|
1511
|
+
fileContent,
|
|
1512
|
+
basePath,
|
|
1513
|
+
sessionId,
|
|
1514
|
+
);
|
|
1515
|
+
fileContent = assetResult.content;
|
|
1516
|
+
uploadedAssets = assetResult.uploadedAssets;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
// Convert content to Gutenberg format if requested
|
|
1520
|
+
const useGutenberg =
|
|
1521
|
+
params.use_gutenberg || WORDPRESS_USE_GUTENBERG;
|
|
1522
|
+
if (useGutenberg) {
|
|
1523
|
+
try {
|
|
1524
|
+
fileContent = GutenbergConverter.toGutenberg(fileContent);
|
|
1525
|
+
} catch (gutenbergError) {
|
|
1526
|
+
sessionManager.logOperation(sessionId, {
|
|
1527
|
+
type: "warning",
|
|
1528
|
+
message: `Gutenberg conversion failed for ${file.path}, using original content`,
|
|
1529
|
+
error: gutenbergError.message,
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
const postData = {
|
|
1535
|
+
title: file.title || `Post from ${file.path}`,
|
|
1536
|
+
content: fileContent,
|
|
1537
|
+
status: file.status,
|
|
1538
|
+
categories: file.categories,
|
|
1539
|
+
tags: file.tags,
|
|
1540
|
+
store_in_memory: true,
|
|
1541
|
+
};
|
|
1542
|
+
|
|
1543
|
+
const post = await wordpressRequest(
|
|
1544
|
+
"/posts",
|
|
1545
|
+
"POST",
|
|
1546
|
+
postData,
|
|
1547
|
+
sessionId,
|
|
1548
|
+
);
|
|
1549
|
+
|
|
1550
|
+
results.push({
|
|
1551
|
+
file: file.path,
|
|
1552
|
+
post_id: post.id,
|
|
1553
|
+
post_url: post.link,
|
|
1554
|
+
status: "success",
|
|
1555
|
+
uploaded_assets:
|
|
1556
|
+
uploadedAssets.length > 0 ? uploadedAssets : undefined,
|
|
1557
|
+
message: "Published successfully",
|
|
1558
|
+
});
|
|
1559
|
+
} catch (error) {
|
|
1560
|
+
errors.push({
|
|
1561
|
+
file: file.path,
|
|
1562
|
+
error: error.message,
|
|
1563
|
+
status: "error",
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
// Store batch operation result in memory
|
|
1569
|
+
const batchId = `batch_${Date.now()}`;
|
|
1570
|
+
memoryManager.store(
|
|
1571
|
+
batchId,
|
|
1572
|
+
{
|
|
1573
|
+
operation: "batch_publish",
|
|
1574
|
+
results,
|
|
1575
|
+
errors,
|
|
1576
|
+
total_files: params.files.length,
|
|
1577
|
+
successful: results.filter((r) => r.status === "success").length,
|
|
1578
|
+
failed: errors.length,
|
|
1579
|
+
completed_at: Date.now(),
|
|
1580
|
+
},
|
|
1581
|
+
"batch_operations",
|
|
1582
|
+
3600000,
|
|
1583
|
+
); // 1 hour TTL
|
|
1584
|
+
|
|
1585
|
+
return formatMCPResponse({
|
|
1586
|
+
batch_id: batchId,
|
|
1587
|
+
summary: {
|
|
1588
|
+
total_files: params.files.length,
|
|
1589
|
+
successful: results.filter((r) => r.status === "success").length,
|
|
1590
|
+
failed: errors.length,
|
|
1591
|
+
dry_run: params.dry_run,
|
|
1592
|
+
},
|
|
1593
|
+
results,
|
|
1594
|
+
errors,
|
|
1595
|
+
});
|
|
1596
|
+
},
|
|
1597
|
+
);
|
|
1598
|
+
},
|
|
1599
|
+
);
|
|
1228
1600
|
|
|
1229
1601
|
// Resource cleanup and server lifecycle management
|
|
1230
1602
|
function setupCleanupHandlers() {
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1603
|
+
// Cleanup sessions every 10 minutes
|
|
1604
|
+
setInterval(
|
|
1605
|
+
() => {
|
|
1606
|
+
sessionManager.cleanup();
|
|
1607
|
+
},
|
|
1608
|
+
10 * 60 * 1000,
|
|
1609
|
+
);
|
|
1610
|
+
|
|
1611
|
+
// Handle graceful shutdown
|
|
1612
|
+
const cleanup = () => {
|
|
1613
|
+
console.error("WordPress MCP Server shutting down...");
|
|
1614
|
+
process.exit(0);
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1617
|
+
process.on("SIGINT", cleanup);
|
|
1618
|
+
process.on("SIGTERM", cleanup);
|
|
1619
|
+
process.on("SIGHUP", cleanup);
|
|
1245
1620
|
}
|
|
1246
1621
|
|
|
1247
1622
|
// Start the enhanced MCP server
|
|
1248
1623
|
async function main() {
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1624
|
+
try {
|
|
1625
|
+
// Initialize session manager
|
|
1626
|
+
sessionManager.createSession("default_session");
|
|
1627
|
+
|
|
1628
|
+
// Setup cleanup handlers
|
|
1629
|
+
setupCleanupHandlers();
|
|
1630
|
+
|
|
1631
|
+
const transport = new StdioServerTransport();
|
|
1632
|
+
await server.connect(transport);
|
|
1633
|
+
|
|
1634
|
+
console.error("Enhanced WordPress MCP Server v2.0.0 running...");
|
|
1635
|
+
console.error(`Connected to WordPress site: ${WORDPRESS_URL}`);
|
|
1636
|
+
console.error(`Active session: ${sessionManager.activeSession}`);
|
|
1637
|
+
console.error(
|
|
1638
|
+
"Available tools: session management, memory management, health checks, WordPress operations, batch publishing",
|
|
1639
|
+
);
|
|
1640
|
+
} catch (error) {
|
|
1641
|
+
console.error("Failed to start server:", error.message);
|
|
1642
|
+
process.exit(1);
|
|
1643
|
+
}
|
|
1268
1644
|
}
|
|
1269
1645
|
|
|
1270
1646
|
main().catch((error) => {
|
|
1271
|
-
|
|
1272
|
-
|
|
1647
|
+
console.error("Server startup error:", error);
|
|
1648
|
+
process.exit(1);
|
|
1273
1649
|
});
|