myaidev-method 0.0.7 → 0.0.8
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/CLAUDE.md +52 -0
- package/.claude/agents/content-writer.md +155 -0
- package/.claude/commands/myai-configure.md +44 -0
- package/.claude/commands/myai-content-writer.md +78 -0
- package/.claude/commands/myai-wordpress-publish.md +120 -0
- package/.claude/mcp/gutenberg-converter.js +447 -0
- package/.claude/mcp/mcp-config.json +101 -0
- package/.claude/mcp/wordpress-server-simple.js +182 -0
- package/.claude/mcp/wordpress-server.js +1277 -0
- package/.claude/settings.local.json +12 -0
- package/README.md +4 -4
- package/bin/cli.js +17 -22
- package/dist/mcp/gutenberg-converter.js +447 -0
- package/dist/mcp/mcp-config.json +101 -0
- package/dist/mcp/wordpress-server-simple.js +182 -0
- package/dist/mcp/wordpress-server.js +1277 -0
- package/package.json +16 -3
- package/src/mcp/health-check.js +190 -0
- package/src/mcp/mcp-launcher.js +237 -0
- package/src/templates/claude/agents/wordpress-admin.md +228 -271
- package/src/templates/claude/commands/myai-configure.md +10 -74
- package/src/templates/claude/commands/myai-wordpress-publish.md +16 -8
|
@@ -0,0 +1,1277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import fetch from "node-fetch";
|
|
7
|
+
import dotenv from "dotenv";
|
|
8
|
+
import { GutenbergConverter } from "./gutenberg-converter.js";
|
|
9
|
+
|
|
10
|
+
// Load environment variables
|
|
11
|
+
dotenv.config();
|
|
12
|
+
|
|
13
|
+
// WordPress API configuration from environment
|
|
14
|
+
const WORDPRESS_URL = process.env.WORDPRESS_URL;
|
|
15
|
+
const WORDPRESS_USERNAME = process.env.WORDPRESS_USERNAME;
|
|
16
|
+
const WORDPRESS_APP_PASSWORD = process.env.WORDPRESS_APP_PASSWORD;
|
|
17
|
+
const WORDPRESS_USE_GUTENBERG = process.env.WORDPRESS_USE_GUTENBERG === 'true';
|
|
18
|
+
|
|
19
|
+
// Validate environment variables
|
|
20
|
+
if (!WORDPRESS_URL || !WORDPRESS_USERNAME || !WORDPRESS_APP_PASSWORD) {
|
|
21
|
+
console.error("Missing required environment variables: WORDPRESS_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Session management
|
|
26
|
+
class SessionManager {
|
|
27
|
+
constructor() {
|
|
28
|
+
this.sessions = new Map();
|
|
29
|
+
this.activeSession = null;
|
|
30
|
+
this.sessionTimeout = 30 * 60 * 1000; // 30 minutes
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
createSession(id = null) {
|
|
34
|
+
const sessionId = id || `wp_session_${Date.now()}`;
|
|
35
|
+
const session = {
|
|
36
|
+
id: sessionId,
|
|
37
|
+
created: Date.now(),
|
|
38
|
+
lastActivity: Date.now(),
|
|
39
|
+
operations: [],
|
|
40
|
+
context: {}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
this.sessions.set(sessionId, session);
|
|
44
|
+
this.activeSession = sessionId;
|
|
45
|
+
return sessionId;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getSession(id) {
|
|
49
|
+
return this.sessions.get(id);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
updateActivity(id) {
|
|
53
|
+
const session = this.sessions.get(id);
|
|
54
|
+
if (session) {
|
|
55
|
+
session.lastActivity = Date.now();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
logOperation(sessionId, operation) {
|
|
60
|
+
const session = this.sessions.get(sessionId);
|
|
61
|
+
if (session) {
|
|
62
|
+
session.operations.push({
|
|
63
|
+
...operation,
|
|
64
|
+
timestamp: Date.now()
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
cleanup() {
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
for (const [id, session] of this.sessions) {
|
|
72
|
+
if (now - session.lastActivity > this.sessionTimeout) {
|
|
73
|
+
this.sessions.delete(id);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const sessionManager = new SessionManager();
|
|
80
|
+
|
|
81
|
+
// Memory manager for persistence (simple implementation)
|
|
82
|
+
class MemoryManager {
|
|
83
|
+
constructor() {
|
|
84
|
+
this.memory = new Map();
|
|
85
|
+
this.namespaces = new Map();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
store(key, value, namespace = 'default', ttl = null) {
|
|
89
|
+
const nsMap = this.namespaces.get(namespace) || new Map();
|
|
90
|
+
const entry = {
|
|
91
|
+
value,
|
|
92
|
+
timestamp: Date.now(),
|
|
93
|
+
ttl: ttl ? Date.now() + ttl : null
|
|
94
|
+
};
|
|
95
|
+
nsMap.set(key, entry);
|
|
96
|
+
this.namespaces.set(namespace, nsMap);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
retrieve(key, namespace = 'default') {
|
|
101
|
+
const nsMap = this.namespaces.get(namespace);
|
|
102
|
+
if (!nsMap) return null;
|
|
103
|
+
|
|
104
|
+
const entry = nsMap.get(key);
|
|
105
|
+
if (!entry) return null;
|
|
106
|
+
|
|
107
|
+
if (entry.ttl && Date.now() > entry.ttl) {
|
|
108
|
+
nsMap.delete(key);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return entry.value;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
delete(key, namespace = 'default') {
|
|
116
|
+
const nsMap = this.namespaces.get(namespace);
|
|
117
|
+
if (nsMap) {
|
|
118
|
+
return nsMap.delete(key);
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
list(namespace = 'default') {
|
|
124
|
+
const nsMap = this.namespaces.get(namespace);
|
|
125
|
+
if (!nsMap) return [];
|
|
126
|
+
|
|
127
|
+
const now = Date.now();
|
|
128
|
+
const results = [];
|
|
129
|
+
|
|
130
|
+
for (const [key, entry] of nsMap) {
|
|
131
|
+
if (entry.ttl && now > entry.ttl) {
|
|
132
|
+
nsMap.delete(key);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
results.push({ key, value: entry.value, timestamp: entry.timestamp });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return results;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const memoryManager = new MemoryManager();
|
|
143
|
+
|
|
144
|
+
// Create MCP server with enhanced configuration
|
|
145
|
+
const server = new McpServer({
|
|
146
|
+
name: "wordpress-mcp-server",
|
|
147
|
+
version: "2.0.0",
|
|
148
|
+
description: "Enhanced WordPress MCP Server with session management and memory persistence"
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Enhanced helper function for WordPress API requests with better error handling
|
|
152
|
+
async function wordpressRequest(endpoint, method = 'GET', data = null, sessionId = null) {
|
|
153
|
+
const baseUrl = WORDPRESS_URL.replace(/\/$/, '');
|
|
154
|
+
const apiPath = '/wp-json/wp/v2';
|
|
155
|
+
const auth = Buffer.from(`${WORDPRESS_USERNAME}:${WORDPRESS_APP_PASSWORD}`).toString('base64');
|
|
156
|
+
|
|
157
|
+
const options = {
|
|
158
|
+
method,
|
|
159
|
+
headers: {
|
|
160
|
+
'Authorization': `Basic ${auth}`,
|
|
161
|
+
'Content-Type': 'application/json',
|
|
162
|
+
'User-Agent': 'WordPress-MCP-Server/2.0.0'
|
|
163
|
+
},
|
|
164
|
+
timeout: 30000 // 30 second timeout
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
if (data && method !== 'GET') {
|
|
168
|
+
options.body = JSON.stringify(data);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const startTime = Date.now();
|
|
172
|
+
let response;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
response = await fetch(`${baseUrl}${apiPath}${endpoint}`, options);
|
|
176
|
+
|
|
177
|
+
// Log operation if session provided
|
|
178
|
+
if (sessionId) {
|
|
179
|
+
sessionManager.logOperation(sessionId, {
|
|
180
|
+
type: 'api_request',
|
|
181
|
+
method,
|
|
182
|
+
endpoint,
|
|
183
|
+
status: response.status,
|
|
184
|
+
duration: Date.now() - startTime
|
|
185
|
+
});
|
|
186
|
+
sessionManager.updateActivity(sessionId);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!response.ok) {
|
|
190
|
+
let errorBody;
|
|
191
|
+
try {
|
|
192
|
+
errorBody = await response.json();
|
|
193
|
+
} catch {
|
|
194
|
+
errorBody = await response.text();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
throw new MCPError({
|
|
198
|
+
code: response.status,
|
|
199
|
+
message: `WordPress API Error: ${response.status} - ${response.statusText}`,
|
|
200
|
+
details: errorBody,
|
|
201
|
+
endpoint,
|
|
202
|
+
method
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return await response.json();
|
|
207
|
+
|
|
208
|
+
} catch (error) {
|
|
209
|
+
// Log error operation
|
|
210
|
+
if (sessionId) {
|
|
211
|
+
sessionManager.logOperation(sessionId, {
|
|
212
|
+
type: 'api_error',
|
|
213
|
+
method,
|
|
214
|
+
endpoint,
|
|
215
|
+
error: error.message,
|
|
216
|
+
duration: Date.now() - startTime
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (error instanceof MCPError) {
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
throw new MCPError({
|
|
225
|
+
code: 'NETWORK_ERROR',
|
|
226
|
+
message: `Network error: ${error.message}`,
|
|
227
|
+
details: error,
|
|
228
|
+
endpoint,
|
|
229
|
+
method
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Custom error class for better error handling
|
|
235
|
+
class MCPError extends Error {
|
|
236
|
+
constructor({ code, message, details, endpoint, method }) {
|
|
237
|
+
super(message);
|
|
238
|
+
this.name = 'MCPError';
|
|
239
|
+
this.code = code;
|
|
240
|
+
this.details = details;
|
|
241
|
+
this.endpoint = endpoint;
|
|
242
|
+
this.method = method;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
toJSON() {
|
|
246
|
+
return {
|
|
247
|
+
success: false,
|
|
248
|
+
error: {
|
|
249
|
+
code: this.code,
|
|
250
|
+
message: this.message,
|
|
251
|
+
details: this.details,
|
|
252
|
+
endpoint: this.endpoint,
|
|
253
|
+
method: this.method,
|
|
254
|
+
timestamp: Date.now()
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Enhanced response formatter
|
|
261
|
+
function formatMCPResponse(data, success = true) {
|
|
262
|
+
const response = {
|
|
263
|
+
success,
|
|
264
|
+
timestamp: Date.now(),
|
|
265
|
+
server_version: "2.0.0"
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
if (success) {
|
|
269
|
+
response.data = data;
|
|
270
|
+
} else {
|
|
271
|
+
response.error = data;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
content: [{
|
|
276
|
+
type: "text",
|
|
277
|
+
text: JSON.stringify(response, null, 2)
|
|
278
|
+
}]
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Tool execution wrapper with enhanced error handling
|
|
283
|
+
async function executeTool(toolName, params, handler) {
|
|
284
|
+
const sessionId = sessionManager.activeSession || sessionManager.createSession();
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
sessionManager.updateActivity(sessionId);
|
|
288
|
+
|
|
289
|
+
const startTime = Date.now();
|
|
290
|
+
const result = await handler(params, sessionId);
|
|
291
|
+
const duration = Date.now() - startTime;
|
|
292
|
+
|
|
293
|
+
// Log successful operation
|
|
294
|
+
sessionManager.logOperation(sessionId, {
|
|
295
|
+
type: 'tool_execution',
|
|
296
|
+
tool: toolName,
|
|
297
|
+
status: 'success',
|
|
298
|
+
duration,
|
|
299
|
+
params: Object.keys(params || {})
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
return result;
|
|
303
|
+
|
|
304
|
+
} catch (error) {
|
|
305
|
+
// Log failed operation
|
|
306
|
+
sessionManager.logOperation(sessionId, {
|
|
307
|
+
type: 'tool_execution',
|
|
308
|
+
tool: toolName,
|
|
309
|
+
status: 'error',
|
|
310
|
+
error: error.message,
|
|
311
|
+
params: Object.keys(params || {})
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
if (error instanceof MCPError) {
|
|
315
|
+
return formatMCPResponse(error.toJSON().error, false);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return formatMCPResponse({
|
|
319
|
+
code: 'TOOL_ERROR',
|
|
320
|
+
message: error.message,
|
|
321
|
+
tool: toolName,
|
|
322
|
+
timestamp: Date.now()
|
|
323
|
+
}, false);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Register enhanced WordPress MCP Tools
|
|
328
|
+
|
|
329
|
+
// Session Management Tools
|
|
330
|
+
server.registerTool("wp_session_create", {
|
|
331
|
+
title: "Create WordPress Session",
|
|
332
|
+
description: "Create a new session for tracking operations and maintaining context",
|
|
333
|
+
inputSchema: {
|
|
334
|
+
type: "object",
|
|
335
|
+
properties: {
|
|
336
|
+
session_id: {
|
|
337
|
+
type: "string",
|
|
338
|
+
description: "Optional custom session ID"
|
|
339
|
+
},
|
|
340
|
+
context: {
|
|
341
|
+
type: "object",
|
|
342
|
+
description: "Optional context data for the session"
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
additionalProperties: false
|
|
346
|
+
}
|
|
347
|
+
}, async (params) => {
|
|
348
|
+
return executeTool('wp_session_create', params, async (params) => {
|
|
349
|
+
const sessionId = sessionManager.createSession(params.session_id);
|
|
350
|
+
if (params.context) {
|
|
351
|
+
const session = sessionManager.getSession(sessionId);
|
|
352
|
+
session.context = { ...session.context, ...params.context };
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return formatMCPResponse({
|
|
356
|
+
session_id: sessionId,
|
|
357
|
+
created: true,
|
|
358
|
+
message: "Session created successfully"
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
server.registerTool("wp_session_status", {
|
|
364
|
+
title: "Get WordPress Session Status",
|
|
365
|
+
description: "Get current session information and operation history",
|
|
366
|
+
inputSchema: {
|
|
367
|
+
type: "object",
|
|
368
|
+
properties: {
|
|
369
|
+
session_id: {
|
|
370
|
+
type: "string",
|
|
371
|
+
description: "Session ID to check status for"
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
additionalProperties: false
|
|
375
|
+
}
|
|
376
|
+
}, async (params) => {
|
|
377
|
+
return executeTool('wp_session_status', params, async (params) => {
|
|
378
|
+
const sessionId = params.session_id || sessionManager.activeSession;
|
|
379
|
+
if (!sessionId) {
|
|
380
|
+
throw new MCPError({
|
|
381
|
+
code: 'NO_SESSION',
|
|
382
|
+
message: 'No active session found'
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const session = sessionManager.getSession(sessionId);
|
|
387
|
+
if (!session) {
|
|
388
|
+
throw new MCPError({
|
|
389
|
+
code: 'SESSION_NOT_FOUND',
|
|
390
|
+
message: `Session ${sessionId} not found`
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return formatMCPResponse({
|
|
395
|
+
session: {
|
|
396
|
+
id: session.id,
|
|
397
|
+
created: new Date(session.created).toISOString(),
|
|
398
|
+
last_activity: new Date(session.lastActivity).toISOString(),
|
|
399
|
+
operations_count: session.operations.length,
|
|
400
|
+
recent_operations: session.operations.slice(-5),
|
|
401
|
+
context: session.context
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Memory Management Tools
|
|
408
|
+
server.registerTool("wp_memory_store", {
|
|
409
|
+
title: "Store WordPress Memory",
|
|
410
|
+
description: "Store data in memory for persistence across operations",
|
|
411
|
+
inputSchema: {
|
|
412
|
+
type: "object",
|
|
413
|
+
properties: {
|
|
414
|
+
key: {
|
|
415
|
+
type: "string",
|
|
416
|
+
description: "Memory key to store data under"
|
|
417
|
+
},
|
|
418
|
+
value: {
|
|
419
|
+
description: "Value to store (any type)"
|
|
420
|
+
},
|
|
421
|
+
namespace: {
|
|
422
|
+
type: "string",
|
|
423
|
+
description: "Namespace to organize data",
|
|
424
|
+
default: "wordpress"
|
|
425
|
+
},
|
|
426
|
+
ttl: {
|
|
427
|
+
type: "number",
|
|
428
|
+
description: "Time-to-live in milliseconds"
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
required: ["key", "value"],
|
|
432
|
+
additionalProperties: false
|
|
433
|
+
}
|
|
434
|
+
}, async (params) => {
|
|
435
|
+
return executeTool('wp_memory_store', params, async (params) => {
|
|
436
|
+
const stored = memoryManager.store(
|
|
437
|
+
params.key,
|
|
438
|
+
params.value,
|
|
439
|
+
params.namespace,
|
|
440
|
+
params.ttl
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
return formatMCPResponse({
|
|
444
|
+
stored: stored,
|
|
445
|
+
key: params.key,
|
|
446
|
+
namespace: params.namespace,
|
|
447
|
+
ttl: params.ttl,
|
|
448
|
+
message: "Data stored successfully"
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
server.registerTool("wp_memory_retrieve", {
|
|
454
|
+
title: "Retrieve WordPress Memory",
|
|
455
|
+
description: "Retrieve stored data from memory",
|
|
456
|
+
inputSchema: {
|
|
457
|
+
type: "object",
|
|
458
|
+
properties: {
|
|
459
|
+
key: {
|
|
460
|
+
type: "string",
|
|
461
|
+
description: "Memory key to retrieve"
|
|
462
|
+
},
|
|
463
|
+
namespace: {
|
|
464
|
+
type: "string",
|
|
465
|
+
description: "Namespace to search in",
|
|
466
|
+
default: "wordpress"
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
required: ["key"],
|
|
470
|
+
additionalProperties: false
|
|
471
|
+
}
|
|
472
|
+
}, async (params) => {
|
|
473
|
+
return executeTool('wp_memory_retrieve', params, async (params) => {
|
|
474
|
+
const value = memoryManager.retrieve(params.key, params.namespace);
|
|
475
|
+
|
|
476
|
+
return formatMCPResponse({
|
|
477
|
+
key: params.key,
|
|
478
|
+
namespace: params.namespace,
|
|
479
|
+
value: value,
|
|
480
|
+
found: value !== null
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
server.registerTool("wp_memory_list", {
|
|
486
|
+
title: "List WordPress Memory",
|
|
487
|
+
description: "List all stored data in a namespace",
|
|
488
|
+
inputSchema: {
|
|
489
|
+
type: "object",
|
|
490
|
+
properties: {
|
|
491
|
+
namespace: {
|
|
492
|
+
type: "string",
|
|
493
|
+
description: "Namespace to list data from",
|
|
494
|
+
default: "wordpress"
|
|
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
|
+
});
|
|
510
|
+
|
|
511
|
+
// Health and System Tools
|
|
512
|
+
server.registerTool("wp_health_check", {
|
|
513
|
+
title: "WordPress Health Check",
|
|
514
|
+
description: "Comprehensive health check of WordPress site and MCP server",
|
|
515
|
+
inputSchema: {
|
|
516
|
+
type: "object",
|
|
517
|
+
properties: {
|
|
518
|
+
detailed: {
|
|
519
|
+
type: "boolean",
|
|
520
|
+
description: "Include detailed health metrics",
|
|
521
|
+
default: false
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
additionalProperties: false
|
|
525
|
+
}
|
|
526
|
+
}, async (params) => {
|
|
527
|
+
return executeTool('wp_health_check', params, async (params, sessionId) => {
|
|
528
|
+
const checks = [];
|
|
529
|
+
|
|
530
|
+
try {
|
|
531
|
+
// Test WordPress API connectivity
|
|
532
|
+
const startTime = Date.now();
|
|
533
|
+
const response = await wordpressRequest('/', 'GET', null, sessionId);
|
|
534
|
+
checks.push({
|
|
535
|
+
name: 'WordPress API Connectivity',
|
|
536
|
+
status: 'passed',
|
|
537
|
+
response_time: Date.now() - startTime,
|
|
538
|
+
message: 'API is responding'
|
|
539
|
+
});
|
|
540
|
+
} catch (error) {
|
|
541
|
+
checks.push({
|
|
542
|
+
name: 'WordPress API Connectivity',
|
|
543
|
+
status: 'failed',
|
|
544
|
+
error: error.message
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Check authentication
|
|
549
|
+
try {
|
|
550
|
+
await wordpressRequest('/users/me', 'GET', null, sessionId);
|
|
551
|
+
checks.push({
|
|
552
|
+
name: 'Authentication',
|
|
553
|
+
status: 'passed',
|
|
554
|
+
message: 'Authentication working'
|
|
555
|
+
});
|
|
556
|
+
} catch (error) {
|
|
557
|
+
checks.push({
|
|
558
|
+
name: 'Authentication',
|
|
559
|
+
status: 'failed',
|
|
560
|
+
error: error.message
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Session status
|
|
565
|
+
const activeSessionCount = sessionManager.sessions.size;
|
|
566
|
+
checks.push({
|
|
567
|
+
name: 'Session Management',
|
|
568
|
+
status: 'passed',
|
|
569
|
+
active_sessions: activeSessionCount,
|
|
570
|
+
current_session: sessionId
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// Memory status
|
|
574
|
+
const memoryEntries = memoryManager.list('wordpress');
|
|
575
|
+
checks.push({
|
|
576
|
+
name: 'Memory Management',
|
|
577
|
+
status: 'passed',
|
|
578
|
+
stored_entries: memoryEntries.length
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
const overall = checks.every(check => check.status === 'passed');
|
|
582
|
+
|
|
583
|
+
return formatMCPResponse({
|
|
584
|
+
overall_status: overall ? 'healthy' : 'unhealthy',
|
|
585
|
+
checks: checks,
|
|
586
|
+
timestamp: Date.now(),
|
|
587
|
+
server_version: '2.0.0'
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
// Get site information
|
|
593
|
+
server.registerTool("wp_get_site_info", {
|
|
594
|
+
title: "Get WordPress Site Information",
|
|
595
|
+
description: "Get WordPress site statistics, version, and health information",
|
|
596
|
+
inputSchema: {
|
|
597
|
+
type: "object",
|
|
598
|
+
properties: {
|
|
599
|
+
include_health: {
|
|
600
|
+
type: "boolean",
|
|
601
|
+
description: "Include health metrics in response",
|
|
602
|
+
default: false
|
|
603
|
+
},
|
|
604
|
+
cache_duration: {
|
|
605
|
+
type: "number",
|
|
606
|
+
description: "Cache duration in seconds",
|
|
607
|
+
default: 300
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
additionalProperties: false
|
|
611
|
+
}
|
|
612
|
+
}, async (params) => {
|
|
613
|
+
return executeTool('wp_get_site_info', params, async (params, sessionId) => {
|
|
614
|
+
// Check cache first
|
|
615
|
+
const cacheKey = `site_info_${WORDPRESS_URL}`;
|
|
616
|
+
const cached = memoryManager.retrieve(cacheKey, 'cache');
|
|
617
|
+
if (cached && Date.now() - cached.timestamp < params.cache_duration * 1000) {
|
|
618
|
+
return formatMCPResponse({
|
|
619
|
+
...cached.data,
|
|
620
|
+
cached: true,
|
|
621
|
+
cache_age: Math.floor((Date.now() - cached.timestamp) / 1000)
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Get site info from multiple endpoints
|
|
626
|
+
const [users, posts, plugins] = await Promise.all([
|
|
627
|
+
wordpressRequest('/users', 'GET', null, sessionId),
|
|
628
|
+
wordpressRequest('/posts?per_page=1', 'GET', null, sessionId),
|
|
629
|
+
wordpressRequest('/plugins', 'GET', null, sessionId).catch(() => []) // Plugins endpoint might not be available
|
|
630
|
+
]);
|
|
631
|
+
|
|
632
|
+
const siteInfo = {
|
|
633
|
+
site_url: WORDPRESS_URL,
|
|
634
|
+
total_users: users.length,
|
|
635
|
+
total_posts: posts.length,
|
|
636
|
+
total_plugins: plugins.length,
|
|
637
|
+
wordpress_version: "Available via REST API",
|
|
638
|
+
server_version: "2.0.0",
|
|
639
|
+
last_updated: new Date().toISOString(),
|
|
640
|
+
message: "Site information retrieved successfully"
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
// Store in cache
|
|
644
|
+
memoryManager.store(cacheKey, {
|
|
645
|
+
data: siteInfo,
|
|
646
|
+
timestamp: Date.now()
|
|
647
|
+
}, 'cache', params.cache_duration * 1000);
|
|
648
|
+
|
|
649
|
+
if (params.include_health) {
|
|
650
|
+
// Include basic health metrics
|
|
651
|
+
siteInfo.health_metrics = {
|
|
652
|
+
api_responsive: true,
|
|
653
|
+
authenticated: true,
|
|
654
|
+
last_check: Date.now()
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return formatMCPResponse(siteInfo);
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
// List posts
|
|
663
|
+
server.registerTool("wp_list_posts", {
|
|
664
|
+
title: "List WordPress Posts",
|
|
665
|
+
description: "Get posts with filtering options",
|
|
666
|
+
inputSchema: z.object({
|
|
667
|
+
per_page: z.number().optional().default(10),
|
|
668
|
+
page: z.number().optional().default(1),
|
|
669
|
+
status: z.string().optional().default("publish"),
|
|
670
|
+
search: z.string().optional(),
|
|
671
|
+
categories: z.array(z.number()).optional(),
|
|
672
|
+
tags: z.array(z.number()).optional()
|
|
673
|
+
})
|
|
674
|
+
}, async (params) => {
|
|
675
|
+
try {
|
|
676
|
+
const queryParams = new URLSearchParams();
|
|
677
|
+
|
|
678
|
+
queryParams.append('per_page', params.per_page.toString());
|
|
679
|
+
queryParams.append('page', params.page.toString());
|
|
680
|
+
queryParams.append('status', params.status);
|
|
681
|
+
|
|
682
|
+
if (params.search) queryParams.append('search', params.search);
|
|
683
|
+
if (params.categories) queryParams.append('categories', params.categories.join(','));
|
|
684
|
+
if (params.tags) queryParams.append('tags', params.tags.join(','));
|
|
685
|
+
|
|
686
|
+
const posts = await wordpressRequest(`/posts?${queryParams.toString()}`);
|
|
687
|
+
|
|
688
|
+
return {
|
|
689
|
+
content: [{
|
|
690
|
+
type: "text",
|
|
691
|
+
text: JSON.stringify({
|
|
692
|
+
success: true,
|
|
693
|
+
posts: posts.map(post => ({
|
|
694
|
+
id: post.id,
|
|
695
|
+
title: post.title.rendered,
|
|
696
|
+
status: post.status,
|
|
697
|
+
date: post.date,
|
|
698
|
+
link: post.link,
|
|
699
|
+
excerpt: post.excerpt.rendered.replace(/<[^>]*>/g, '').trim()
|
|
700
|
+
})),
|
|
701
|
+
total: posts.length
|
|
702
|
+
}, null, 2)
|
|
703
|
+
}]
|
|
704
|
+
};
|
|
705
|
+
} catch (error) {
|
|
706
|
+
return {
|
|
707
|
+
content: [{
|
|
708
|
+
type: "text",
|
|
709
|
+
text: JSON.stringify({
|
|
710
|
+
success: false,
|
|
711
|
+
error: error.message
|
|
712
|
+
}, null, 2)
|
|
713
|
+
}]
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// Create post
|
|
719
|
+
server.registerTool("wp_create_post", {
|
|
720
|
+
title: "Create WordPress Post",
|
|
721
|
+
description: "Create a new WordPress post or page with enhanced tracking and validation",
|
|
722
|
+
inputSchema: {
|
|
723
|
+
type: "object",
|
|
724
|
+
properties: {
|
|
725
|
+
title: {
|
|
726
|
+
type: "string",
|
|
727
|
+
description: "Post title (required)",
|
|
728
|
+
minLength: 1
|
|
729
|
+
},
|
|
730
|
+
content: {
|
|
731
|
+
type: "string",
|
|
732
|
+
description: "Post content (required)",
|
|
733
|
+
minLength: 1
|
|
734
|
+
},
|
|
735
|
+
status: {
|
|
736
|
+
type: "string",
|
|
737
|
+
enum: ["draft", "publish", "private", "pending"],
|
|
738
|
+
description: "Post status",
|
|
739
|
+
default: "draft"
|
|
740
|
+
},
|
|
741
|
+
excerpt: {
|
|
742
|
+
type: "string",
|
|
743
|
+
description: "Post excerpt"
|
|
744
|
+
},
|
|
745
|
+
slug: {
|
|
746
|
+
type: "string",
|
|
747
|
+
description: "Post slug/URL"
|
|
748
|
+
},
|
|
749
|
+
categories: {
|
|
750
|
+
type: "array",
|
|
751
|
+
items: { type: "number" },
|
|
752
|
+
description: "Category IDs",
|
|
753
|
+
default: []
|
|
754
|
+
},
|
|
755
|
+
tags: {
|
|
756
|
+
type: "array",
|
|
757
|
+
items: { type: "number" },
|
|
758
|
+
description: "Tag IDs",
|
|
759
|
+
default: []
|
|
760
|
+
},
|
|
761
|
+
use_gutenberg: {
|
|
762
|
+
type: "boolean",
|
|
763
|
+
description: "Use Gutenberg block format",
|
|
764
|
+
default: WORDPRESS_USE_GUTENBERG
|
|
765
|
+
},
|
|
766
|
+
store_in_memory: {
|
|
767
|
+
type: "boolean",
|
|
768
|
+
description: "Store post data in memory for tracking",
|
|
769
|
+
default: true
|
|
770
|
+
}
|
|
771
|
+
},
|
|
772
|
+
required: ["title", "content"],
|
|
773
|
+
additionalProperties: false
|
|
774
|
+
}
|
|
775
|
+
}, async (params) => {
|
|
776
|
+
return executeTool('wp_create_post', params, async (params, sessionId) => {
|
|
777
|
+
// Convert content to Gutenberg format if requested
|
|
778
|
+
let content = params.content;
|
|
779
|
+
const useGutenberg = params.use_gutenberg || params.gutenberg || WORDPRESS_USE_GUTENBERG;
|
|
780
|
+
|
|
781
|
+
if (useGutenberg) {
|
|
782
|
+
try {
|
|
783
|
+
content = GutenbergConverter.htmlToGutenberg(params.content);
|
|
784
|
+
} catch (gutenbergError) {
|
|
785
|
+
// If Gutenberg conversion fails, log warning but continue with original content
|
|
786
|
+
sessionManager.logOperation(sessionId, {
|
|
787
|
+
type: 'warning',
|
|
788
|
+
message: 'Gutenberg conversion failed, using original content',
|
|
789
|
+
error: gutenbergError.message
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const postData = {
|
|
795
|
+
title: params.title,
|
|
796
|
+
content: content,
|
|
797
|
+
status: params.status,
|
|
798
|
+
categories: params.categories,
|
|
799
|
+
tags: params.tags
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
// Add optional fields
|
|
803
|
+
if (params.excerpt) postData.excerpt = params.excerpt;
|
|
804
|
+
if (params.slug) postData.slug = params.slug;
|
|
805
|
+
if (params.meta) postData.meta = params.meta;
|
|
806
|
+
if (params.featured_media) postData.featured_media = params.featured_media;
|
|
807
|
+
if (params.author) postData.author = params.author;
|
|
808
|
+
if (params.comment_status) postData.comment_status = params.comment_status;
|
|
809
|
+
if (params.ping_status) postData.ping_status = params.ping_status;
|
|
810
|
+
|
|
811
|
+
const post = await wordpressRequest('/posts', 'POST', postData, sessionId);
|
|
812
|
+
|
|
813
|
+
const result = {
|
|
814
|
+
post_id: post.id,
|
|
815
|
+
post_url: post.link,
|
|
816
|
+
edit_url: `${WORDPRESS_URL.replace(/\/$/, '')}/wp-admin/post.php?post=${post.id}&action=edit`,
|
|
817
|
+
title: post.title.rendered,
|
|
818
|
+
status: post.status,
|
|
819
|
+
date: post.date,
|
|
820
|
+
modified: post.modified,
|
|
821
|
+
gutenberg_used: useGutenberg,
|
|
822
|
+
categories: post.categories,
|
|
823
|
+
tags: post.tags,
|
|
824
|
+
message: `Post created successfully with ${useGutenberg ? 'Gutenberg' : 'Classic'} editor format`
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
// Store post reference in memory if requested
|
|
828
|
+
if (params.store_in_memory) {
|
|
829
|
+
memoryManager.store(`created_post_${post.id}`, {
|
|
830
|
+
...result,
|
|
831
|
+
original_params: params,
|
|
832
|
+
created_at: Date.now()
|
|
833
|
+
}, 'posts', 3600000); // 1 hour TTL
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
return formatMCPResponse(result);
|
|
837
|
+
});
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
// Update post
|
|
841
|
+
server.registerTool("wp_update_post", {
|
|
842
|
+
title: "Update WordPress Post",
|
|
843
|
+
description: "Update an existing WordPress post",
|
|
844
|
+
inputSchema: z.object({
|
|
845
|
+
id: z.number(),
|
|
846
|
+
title: z.string().optional(),
|
|
847
|
+
content: z.string().optional(),
|
|
848
|
+
status: z.string().optional(),
|
|
849
|
+
excerpt: z.string().optional(),
|
|
850
|
+
slug: z.string().optional(),
|
|
851
|
+
categories: z.array(z.number()).optional(),
|
|
852
|
+
tags: z.array(z.number()).optional()
|
|
853
|
+
})
|
|
854
|
+
}, async (params) => {
|
|
855
|
+
try {
|
|
856
|
+
const { id, ...updateData } = params;
|
|
857
|
+
const filteredData = Object.fromEntries(
|
|
858
|
+
Object.entries(updateData).filter(([_, value]) => value !== undefined)
|
|
859
|
+
);
|
|
860
|
+
|
|
861
|
+
const post = await wordpressRequest(`/posts/${id}`, 'POST', filteredData);
|
|
862
|
+
|
|
863
|
+
return {
|
|
864
|
+
content: [{
|
|
865
|
+
type: "text",
|
|
866
|
+
text: JSON.stringify({
|
|
867
|
+
success: true,
|
|
868
|
+
post_id: post.id,
|
|
869
|
+
post_url: post.link,
|
|
870
|
+
message: "Post updated successfully"
|
|
871
|
+
}, null, 2)
|
|
872
|
+
}]
|
|
873
|
+
};
|
|
874
|
+
} catch (error) {
|
|
875
|
+
return {
|
|
876
|
+
content: [{
|
|
877
|
+
type: "text",
|
|
878
|
+
text: JSON.stringify({
|
|
879
|
+
success: false,
|
|
880
|
+
error: error.message
|
|
881
|
+
}, null, 2)
|
|
882
|
+
}]
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
// Delete post
|
|
888
|
+
server.registerTool("wp_delete_post", {
|
|
889
|
+
title: "Delete WordPress Post",
|
|
890
|
+
description: "Delete a WordPress post (move to trash)",
|
|
891
|
+
inputSchema: z.object({
|
|
892
|
+
id: z.number()
|
|
893
|
+
})
|
|
894
|
+
}, async (params) => {
|
|
895
|
+
try {
|
|
896
|
+
const post = await wordpressRequest(`/posts/${params.id}`, 'DELETE');
|
|
897
|
+
|
|
898
|
+
return {
|
|
899
|
+
content: [{
|
|
900
|
+
type: "text",
|
|
901
|
+
text: JSON.stringify({
|
|
902
|
+
success: true,
|
|
903
|
+
post_id: post.id,
|
|
904
|
+
message: "Post deleted successfully"
|
|
905
|
+
}, null, 2)
|
|
906
|
+
}]
|
|
907
|
+
};
|
|
908
|
+
} catch (error) {
|
|
909
|
+
return {
|
|
910
|
+
content: [{
|
|
911
|
+
type: "text",
|
|
912
|
+
text: JSON.stringify({
|
|
913
|
+
success: false,
|
|
914
|
+
error: error.message
|
|
915
|
+
}, null, 2)
|
|
916
|
+
}]
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
// List users
|
|
922
|
+
server.registerTool("wp_list_users", {
|
|
923
|
+
title: "List WordPress Users",
|
|
924
|
+
description: "Get WordPress user accounts and roles",
|
|
925
|
+
inputSchema: z.object({
|
|
926
|
+
per_page: z.number().optional().default(100),
|
|
927
|
+
role: z.string().optional()
|
|
928
|
+
})
|
|
929
|
+
}, async (params) => {
|
|
930
|
+
try {
|
|
931
|
+
const queryParams = new URLSearchParams();
|
|
932
|
+
queryParams.append('per_page', params.per_page.toString());
|
|
933
|
+
if (params.role) queryParams.append('role', params.role);
|
|
934
|
+
|
|
935
|
+
const users = await wordpressRequest(`/users?${queryParams.toString()}`);
|
|
936
|
+
|
|
937
|
+
return {
|
|
938
|
+
content: [{
|
|
939
|
+
type: "text",
|
|
940
|
+
text: JSON.stringify({
|
|
941
|
+
success: true,
|
|
942
|
+
users: users.map(user => ({
|
|
943
|
+
id: user.id,
|
|
944
|
+
username: user.username,
|
|
945
|
+
name: user.name,
|
|
946
|
+
email: user.email,
|
|
947
|
+
roles: user.roles,
|
|
948
|
+
registered_date: user.registered_date
|
|
949
|
+
})),
|
|
950
|
+
total: users.length
|
|
951
|
+
}, null, 2)
|
|
952
|
+
}]
|
|
953
|
+
};
|
|
954
|
+
} catch (error) {
|
|
955
|
+
return {
|
|
956
|
+
content: [{
|
|
957
|
+
type: "text",
|
|
958
|
+
text: JSON.stringify({
|
|
959
|
+
success: false,
|
|
960
|
+
error: error.message
|
|
961
|
+
}, null, 2)
|
|
962
|
+
}]
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
// Create user
|
|
968
|
+
server.registerTool("wp_create_user", {
|
|
969
|
+
title: "Create WordPress User",
|
|
970
|
+
description: "Add a new WordPress user account",
|
|
971
|
+
inputSchema: z.object({
|
|
972
|
+
username: z.string(),
|
|
973
|
+
email: z.string().email(),
|
|
974
|
+
password: z.string(),
|
|
975
|
+
roles: z.array(z.string()).optional().default(["subscriber"])
|
|
976
|
+
})
|
|
977
|
+
}, async (params) => {
|
|
978
|
+
try {
|
|
979
|
+
const userData = {
|
|
980
|
+
username: params.username,
|
|
981
|
+
email: params.email,
|
|
982
|
+
password: params.password,
|
|
983
|
+
roles: params.roles
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
const user = await wordpressRequest('/users', 'POST', userData);
|
|
987
|
+
|
|
988
|
+
return {
|
|
989
|
+
content: [{
|
|
990
|
+
type: "text",
|
|
991
|
+
text: JSON.stringify({
|
|
992
|
+
success: true,
|
|
993
|
+
user_id: user.id,
|
|
994
|
+
username: user.username,
|
|
995
|
+
email: user.email,
|
|
996
|
+
roles: user.roles,
|
|
997
|
+
message: "User created successfully"
|
|
998
|
+
}, null, 2)
|
|
999
|
+
}]
|
|
1000
|
+
};
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
return {
|
|
1003
|
+
content: [{
|
|
1004
|
+
type: "text",
|
|
1005
|
+
text: JSON.stringify({
|
|
1006
|
+
success: false,
|
|
1007
|
+
error: error.message
|
|
1008
|
+
}, null, 2)
|
|
1009
|
+
}]
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
// Update user
|
|
1015
|
+
server.registerTool("wp_update_user", {
|
|
1016
|
+
title: "Update WordPress User",
|
|
1017
|
+
description: "Modify WordPress user settings",
|
|
1018
|
+
inputSchema: z.object({
|
|
1019
|
+
id: z.number(),
|
|
1020
|
+
email: z.string().email().optional(),
|
|
1021
|
+
roles: z.array(z.string()).optional(),
|
|
1022
|
+
password: z.string().optional()
|
|
1023
|
+
})
|
|
1024
|
+
}, async (params) => {
|
|
1025
|
+
try {
|
|
1026
|
+
const { id, ...updateData } = params;
|
|
1027
|
+
const filteredData = Object.fromEntries(
|
|
1028
|
+
Object.entries(updateData).filter(([_, value]) => value !== undefined)
|
|
1029
|
+
);
|
|
1030
|
+
|
|
1031
|
+
const user = await wordpressRequest(`/users/${id}`, 'POST', filteredData);
|
|
1032
|
+
|
|
1033
|
+
return {
|
|
1034
|
+
content: [{
|
|
1035
|
+
type: "text",
|
|
1036
|
+
text: JSON.stringify({
|
|
1037
|
+
success: true,
|
|
1038
|
+
user_id: user.id,
|
|
1039
|
+
username: user.username,
|
|
1040
|
+
email: user.email,
|
|
1041
|
+
roles: user.roles,
|
|
1042
|
+
message: "User updated successfully"
|
|
1043
|
+
}, null, 2)
|
|
1044
|
+
}]
|
|
1045
|
+
};
|
|
1046
|
+
} catch (error) {
|
|
1047
|
+
return {
|
|
1048
|
+
content: [{
|
|
1049
|
+
type: "text",
|
|
1050
|
+
text: JSON.stringify({
|
|
1051
|
+
success: false,
|
|
1052
|
+
error: error.message
|
|
1053
|
+
}, null, 2)
|
|
1054
|
+
}]
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
// List plugins (if available)
|
|
1060
|
+
server.registerTool("wp_list_plugins", {
|
|
1061
|
+
title: "List WordPress Plugins",
|
|
1062
|
+
description: "Get installed WordPress plugins",
|
|
1063
|
+
inputSchema: z.object({})
|
|
1064
|
+
}, async () => {
|
|
1065
|
+
try {
|
|
1066
|
+
const plugins = await wordpressRequest('/plugins');
|
|
1067
|
+
|
|
1068
|
+
return {
|
|
1069
|
+
content: [{
|
|
1070
|
+
type: "text",
|
|
1071
|
+
text: JSON.stringify({
|
|
1072
|
+
success: true,
|
|
1073
|
+
plugins: plugins.map(plugin => ({
|
|
1074
|
+
name: plugin.name,
|
|
1075
|
+
plugin: plugin.plugin,
|
|
1076
|
+
status: plugin.status,
|
|
1077
|
+
version: plugin.version
|
|
1078
|
+
})),
|
|
1079
|
+
total: plugins.length
|
|
1080
|
+
}, null, 2)
|
|
1081
|
+
}]
|
|
1082
|
+
};
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
return {
|
|
1085
|
+
content: [{
|
|
1086
|
+
type: "text",
|
|
1087
|
+
text: JSON.stringify({
|
|
1088
|
+
success: false,
|
|
1089
|
+
error: error.message,
|
|
1090
|
+
note: "Plugins endpoint may not be available on all WordPress installations"
|
|
1091
|
+
}, null, 2)
|
|
1092
|
+
}]
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
// Get media
|
|
1098
|
+
server.registerTool("wp_get_media", {
|
|
1099
|
+
title: "Get WordPress Media",
|
|
1100
|
+
description: "Access WordPress media library",
|
|
1101
|
+
inputSchema: z.object({
|
|
1102
|
+
per_page: z.number().optional().default(10),
|
|
1103
|
+
media_type: z.string().optional()
|
|
1104
|
+
})
|
|
1105
|
+
}, async (params) => {
|
|
1106
|
+
try {
|
|
1107
|
+
const queryParams = new URLSearchParams();
|
|
1108
|
+
queryParams.append('per_page', params.per_page.toString());
|
|
1109
|
+
if (params.media_type) queryParams.append('media_type', params.media_type);
|
|
1110
|
+
|
|
1111
|
+
const media = await wordpressRequest(`/media?${queryParams.toString()}`);
|
|
1112
|
+
|
|
1113
|
+
return {
|
|
1114
|
+
content: [{
|
|
1115
|
+
type: "text",
|
|
1116
|
+
text: JSON.stringify({
|
|
1117
|
+
success: true,
|
|
1118
|
+
media: media.map(item => ({
|
|
1119
|
+
id: item.id,
|
|
1120
|
+
title: item.title.rendered,
|
|
1121
|
+
source_url: item.source_url,
|
|
1122
|
+
media_type: item.media_type,
|
|
1123
|
+
mime_type: item.mime_type,
|
|
1124
|
+
date: item.date
|
|
1125
|
+
})),
|
|
1126
|
+
total: media.length
|
|
1127
|
+
}, null, 2)
|
|
1128
|
+
}]
|
|
1129
|
+
};
|
|
1130
|
+
} catch (error) {
|
|
1131
|
+
return {
|
|
1132
|
+
content: [{
|
|
1133
|
+
type: "text",
|
|
1134
|
+
text: JSON.stringify({
|
|
1135
|
+
success: false,
|
|
1136
|
+
error: error.message
|
|
1137
|
+
}, null, 2)
|
|
1138
|
+
}]
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
|
|
1143
|
+
// Batch operations tool
|
|
1144
|
+
server.registerTool("wp_batch_publish", {
|
|
1145
|
+
title: "WordPress Batch Publish",
|
|
1146
|
+
description: "Publish multiple posts from markdown files with enhanced tracking",
|
|
1147
|
+
inputSchema: z.object({
|
|
1148
|
+
files: z.array(z.object({
|
|
1149
|
+
path: z.string(),
|
|
1150
|
+
title: z.string().optional(),
|
|
1151
|
+
status: z.enum(["draft", "publish", "private", "pending"]).optional().default("draft"),
|
|
1152
|
+
categories: z.array(z.number()).optional().default([]),
|
|
1153
|
+
tags: z.array(z.number()).optional().default([])
|
|
1154
|
+
})),
|
|
1155
|
+
use_gutenberg: z.boolean().optional().default(WORDPRESS_USE_GUTENBERG),
|
|
1156
|
+
dry_run: z.boolean().optional().default(false)
|
|
1157
|
+
})
|
|
1158
|
+
}, async (params) => {
|
|
1159
|
+
return executeTool('wp_batch_publish', params, async (params, sessionId) => {
|
|
1160
|
+
const results = [];
|
|
1161
|
+
const errors = [];
|
|
1162
|
+
|
|
1163
|
+
for (const file of params.files) {
|
|
1164
|
+
try {
|
|
1165
|
+
if (params.dry_run) {
|
|
1166
|
+
results.push({
|
|
1167
|
+
file: file.path,
|
|
1168
|
+
status: 'dry_run',
|
|
1169
|
+
message: 'Would process this file'
|
|
1170
|
+
});
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// Read file content (this would need file system access in real implementation)
|
|
1175
|
+
// For now, simulate with the provided data
|
|
1176
|
+
const postData = {
|
|
1177
|
+
title: file.title || `Post from ${file.path}`,
|
|
1178
|
+
content: `Content from ${file.path}`, // Would read actual content
|
|
1179
|
+
status: file.status,
|
|
1180
|
+
categories: file.categories,
|
|
1181
|
+
tags: file.tags,
|
|
1182
|
+
use_gutenberg: params.use_gutenberg,
|
|
1183
|
+
store_in_memory: true
|
|
1184
|
+
};
|
|
1185
|
+
|
|
1186
|
+
// Use the existing create_post functionality
|
|
1187
|
+
const post = await wordpressRequest('/posts', 'POST', postData, sessionId);
|
|
1188
|
+
|
|
1189
|
+
results.push({
|
|
1190
|
+
file: file.path,
|
|
1191
|
+
post_id: post.id,
|
|
1192
|
+
post_url: post.link,
|
|
1193
|
+
status: 'success',
|
|
1194
|
+
message: 'Published successfully'
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
} catch (error) {
|
|
1198
|
+
errors.push({
|
|
1199
|
+
file: file.path,
|
|
1200
|
+
error: error.message,
|
|
1201
|
+
status: 'error'
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// Store batch operation result in memory
|
|
1207
|
+
const batchId = `batch_${Date.now()}`;
|
|
1208
|
+
memoryManager.store(batchId, {
|
|
1209
|
+
operation: 'batch_publish',
|
|
1210
|
+
results,
|
|
1211
|
+
errors,
|
|
1212
|
+
total_files: params.files.length,
|
|
1213
|
+
successful: results.filter(r => r.status === 'success').length,
|
|
1214
|
+
failed: errors.length,
|
|
1215
|
+
completed_at: Date.now()
|
|
1216
|
+
}, 'batch_operations', 3600000); // 1 hour TTL
|
|
1217
|
+
|
|
1218
|
+
return formatMCPResponse({
|
|
1219
|
+
batch_id: batchId,
|
|
1220
|
+
summary: {
|
|
1221
|
+
total_files: params.files.length,
|
|
1222
|
+
successful: results.filter(r => r.status === 'success').length,
|
|
1223
|
+
failed: errors.length,
|
|
1224
|
+
dry_run: params.dry_run
|
|
1225
|
+
},
|
|
1226
|
+
results,
|
|
1227
|
+
errors
|
|
1228
|
+
});
|
|
1229
|
+
});
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
// Resource cleanup and server lifecycle management
|
|
1233
|
+
function setupCleanupHandlers() {
|
|
1234
|
+
// Cleanup sessions every 10 minutes
|
|
1235
|
+
setInterval(() => {
|
|
1236
|
+
sessionManager.cleanup();
|
|
1237
|
+
}, 10 * 60 * 1000);
|
|
1238
|
+
|
|
1239
|
+
// Handle graceful shutdown
|
|
1240
|
+
const cleanup = () => {
|
|
1241
|
+
console.error("WordPress MCP Server shutting down...");
|
|
1242
|
+
// Could add more cleanup logic here
|
|
1243
|
+
process.exit(0);
|
|
1244
|
+
};
|
|
1245
|
+
|
|
1246
|
+
process.on('SIGINT', cleanup);
|
|
1247
|
+
process.on('SIGTERM', cleanup);
|
|
1248
|
+
process.on('SIGHUP', cleanup);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// Start the enhanced MCP server
|
|
1252
|
+
async function main() {
|
|
1253
|
+
try {
|
|
1254
|
+
// Initialize session manager
|
|
1255
|
+
sessionManager.createSession('default_session');
|
|
1256
|
+
|
|
1257
|
+
// Setup cleanup handlers
|
|
1258
|
+
setupCleanupHandlers();
|
|
1259
|
+
|
|
1260
|
+
const transport = new StdioServerTransport();
|
|
1261
|
+
await server.connect(transport);
|
|
1262
|
+
|
|
1263
|
+
console.error("Enhanced WordPress MCP Server v2.0.0 running...");
|
|
1264
|
+
console.error(`Connected to WordPress site: ${WORDPRESS_URL}`);
|
|
1265
|
+
console.error(`Active session: ${sessionManager.activeSession}`);
|
|
1266
|
+
console.error("Available tools: session management, memory management, health checks, WordPress operations, batch publishing");
|
|
1267
|
+
|
|
1268
|
+
} catch (error) {
|
|
1269
|
+
console.error("Failed to start server:", error.message);
|
|
1270
|
+
process.exit(1);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
main().catch((error) => {
|
|
1275
|
+
console.error("Server startup error:", error);
|
|
1276
|
+
process.exit(1);
|
|
1277
|
+
});
|