myaidev-method 0.2.19 → 0.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +123 -5
  2. package/README.md +205 -13
  3. package/TECHNICAL_ARCHITECTURE.md +64 -2
  4. package/USER_GUIDE.md +453 -48
  5. package/bin/cli.js +187 -2
  6. package/content-rules.example.md +80 -0
  7. package/dist/mcp/mcp-config.json +138 -1
  8. package/dist/mcp/mcp-launcher.js +237 -0
  9. package/dist/mcp/openstack-server.js +1607 -0
  10. package/dist/server/.tsbuildinfo +1 -1
  11. package/dist/server/auth/layers.d.ts +1 -1
  12. package/dist/server/auth/services/AuthService.d.ts +1 -1
  13. package/dist/server/auth/services/TokenService.js.map +1 -1
  14. package/dist/server/auth/services/example.d.ts +5 -5
  15. package/package.json +17 -17
  16. package/src/config/workflows.js +532 -0
  17. package/src/index.js +21 -8
  18. package/src/lib/payloadcms-utils.js +206 -0
  19. package/src/lib/update-manager.js +2 -1
  20. package/src/lib/visual-config-utils.js +321 -295
  21. package/src/lib/visual-generation-utils.js +1080 -740
  22. package/src/lib/workflow-installer.js +512 -0
  23. package/src/libs/security/authorization-checker.js +606 -0
  24. package/src/mcp/openstack-server.js +1607 -0
  25. package/src/scripts/configure-wordpress-mcp.js +8 -3
  26. package/src/scripts/generate-visual-cli.js +365 -235
  27. package/src/scripts/openstack-setup.sh +110 -0
  28. package/src/scripts/ping.js +250 -0
  29. package/src/scripts/security/environment-detect.js +425 -0
  30. package/src/scripts/wordpress/publish-to-wordpress.js +165 -0
  31. package/src/server/auth/services/TokenService.ts +1 -1
  32. package/src/templates/claude/agents/content-rules-setup.md +657 -0
  33. package/src/templates/claude/agents/content-writer.md +328 -1
  34. package/src/templates/claude/agents/openstack-vm-manager.md +281 -0
  35. package/src/templates/claude/agents/osint-researcher.md +1075 -0
  36. package/src/templates/claude/agents/penetration-tester.md +908 -0
  37. package/src/templates/claude/agents/security-auditor.md +244 -0
  38. package/src/templates/claude/agents/security-setup.md +1094 -0
  39. package/src/templates/claude/agents/visual-content-generator.md +182 -4
  40. package/src/templates/claude/agents/webapp-security-tester.md +581 -0
  41. package/src/templates/claude/commands/myai-configure.md +85 -1
  42. package/src/templates/claude/commands/myai-content-rules-setup.md +204 -0
  43. package/src/templates/claude/commands/myai-openstack.md +229 -0
  44. package/src/templates/claude/commands/sc:security-exploit.md +464 -0
  45. package/src/templates/claude/commands/sc:security-recon.md +281 -0
  46. package/src/templates/claude/commands/sc:security-report.md +756 -0
  47. package/src/templates/claude/commands/sc:security-scan.md +441 -0
  48. package/src/templates/claude/commands/sc:security-setup.md +501 -0
  49. package/src/templates/codex/commands/myai-content-rules-setup.md +85 -0
  50. package/src/templates/gemini/commands/myai-content-rules-setup.toml +57 -0
  51. package/.claude/mcp/sparc-orchestrator-server.js +0 -607
  52. package/.claude/mcp/wordpress-server.js +0 -1277
  53. package/src/agents/content-writer-prompt.md +0 -164
  54. package/src/agents/content-writer.json +0 -70
  55. package/src/templates/claude/mcp_config.json +0 -30
  56. package/src/templates/claude/slash_commands.json +0 -166
  57. package/src/templates/scripts/configure-wordpress-mcp.js +0 -181
@@ -1,1277 +0,0 @@
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
- });