@wplaunchify/ml-mcp-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +220 -0
  3. package/build/cli.d.ts +2 -0
  4. package/build/cli.js +52 -0
  5. package/build/server.d.ts +2 -0
  6. package/build/server.js +97 -0
  7. package/build/tools/comments.d.ts +212 -0
  8. package/build/tools/comments.js +181 -0
  9. package/build/tools/fluent-affiliate.d.ts +2 -0
  10. package/build/tools/fluent-affiliate.js +3 -0
  11. package/build/tools/fluent-cart.d.ts +706 -0
  12. package/build/tools/fluent-cart.js +642 -0
  13. package/build/tools/fluent-community-BACKUP.d.ts +364 -0
  14. package/build/tools/fluent-community-BACKUP.js +883 -0
  15. package/build/tools/fluent-community-MINIMAL.d.ts +69 -0
  16. package/build/tools/fluent-community-MINIMAL.js +92 -0
  17. package/build/tools/fluent-community-design.d.ts +3 -0
  18. package/build/tools/fluent-community-design.js +150 -0
  19. package/build/tools/fluent-community-layout.d.ts +119 -0
  20. package/build/tools/fluent-community-layout.js +88 -0
  21. package/build/tools/fluent-community.d.ts +364 -0
  22. package/build/tools/fluent-community.js +528 -0
  23. package/build/tools/fluent-crm.d.ts +3 -0
  24. package/build/tools/fluent-crm.js +392 -0
  25. package/build/tools/index.d.ts +2205 -0
  26. package/build/tools/index.js +54 -0
  27. package/build/tools/media.d.ts +135 -0
  28. package/build/tools/media.js +168 -0
  29. package/build/tools/ml-canvas.d.ts +91 -0
  30. package/build/tools/ml-canvas.js +109 -0
  31. package/build/tools/ml-image-editor.d.ts +230 -0
  32. package/build/tools/ml-image-editor.js +270 -0
  33. package/build/tools/ml-media-hub.d.ts +575 -0
  34. package/build/tools/ml-media-hub.js +714 -0
  35. package/build/tools/plugin-repository.d.ts +62 -0
  36. package/build/tools/plugin-repository.js +149 -0
  37. package/build/tools/plugins.d.ts +129 -0
  38. package/build/tools/plugins.js +148 -0
  39. package/build/tools/unified-content.d.ts +313 -0
  40. package/build/tools/unified-content.js +615 -0
  41. package/build/tools/unified-taxonomies.d.ts +229 -0
  42. package/build/tools/unified-taxonomies.js +479 -0
  43. package/build/tools/users.d.ts +227 -0
  44. package/build/tools/users.js +182 -0
  45. package/build/types/wordpress-types.d.ts +151 -0
  46. package/build/types/wordpress-types.js +2 -0
  47. package/build/wordpress.d.ts +26 -0
  48. package/build/wordpress.js +223 -0
  49. package/package.json +67 -0
@@ -0,0 +1,479 @@
1
+ import { makeWordPressRequest, logToFile } from '../wordpress.js';
2
+ import { z } from 'zod';
3
+ // Cache for taxonomies to reduce API calls
4
+ let taxonomiesCache = null;
5
+ let taxonomyCacheTimestamp = 0;
6
+ const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
7
+ // Helper function to get all taxonomies with caching
8
+ async function getTaxonomies(forceRefresh = false) {
9
+ const now = Date.now();
10
+ if (!forceRefresh && taxonomiesCache && (now - taxonomyCacheTimestamp) < CACHE_DURATION) {
11
+ logToFile('Using cached taxonomies');
12
+ return taxonomiesCache;
13
+ }
14
+ try {
15
+ logToFile('Fetching taxonomies from API');
16
+ const response = await makeWordPressRequest('GET', 'wp/v2/taxonomies');
17
+ taxonomiesCache = response;
18
+ taxonomyCacheTimestamp = now;
19
+ return response;
20
+ }
21
+ catch (error) {
22
+ logToFile(`Error fetching taxonomies: ${error.message}`);
23
+ throw error;
24
+ }
25
+ }
26
+ // Helper function to get the correct endpoint for a taxonomy
27
+ function getTaxonomyEndpoint(taxonomy) {
28
+ const endpointMap = {
29
+ 'category': 'wp/v2/categories',
30
+ 'post_tag': 'wp/v2/tags',
31
+ 'nav_menu': 'wp/v2/menus',
32
+ 'link_category': 'wp/v2/link_categories'
33
+ };
34
+ return endpointMap[taxonomy] || `wp/v2/${taxonomy}`;
35
+ }
36
+ // Helper function to get the correct content endpoint
37
+ function getContentEndpoint(contentType) {
38
+ const endpointMap = {
39
+ 'post': 'wp/v2/posts',
40
+ 'page': 'wp/v2/pages'
41
+ };
42
+ return endpointMap[contentType] || `wp/v2/${contentType}`;
43
+ }
44
+ // Schema definitions
45
+ const discoverTaxonomiesSchema = z.object({
46
+ content_type: z.string().optional().describe("Limit results to taxonomies associated with a specific content type"),
47
+ refresh_cache: z.boolean().optional().describe("Force refresh the taxonomies cache")
48
+ });
49
+ const listTermsSchema = z.object({
50
+ taxonomy: z.string().describe("The taxonomy slug (e.g., 'category', 'post_tag', or custom taxonomies)"),
51
+ page: z.number().optional().describe("Page number (default 1)"),
52
+ per_page: z.number().min(1).max(100).optional().describe("Items per page (default 10, max 100)"),
53
+ search: z.string().optional().describe("Search term for term name"),
54
+ parent: z.number().optional().describe("Parent term ID to retrieve direct children"),
55
+ slug: z.string().optional().describe("Limit result to terms with a specific slug"),
56
+ hide_empty: z.boolean().optional().describe("Whether to hide terms not assigned to any content"),
57
+ orderby: z.enum(['id', 'include', 'name', 'slug', 'term_group', 'description', 'count']).optional().describe("Sort terms by parameter"),
58
+ order: z.enum(['asc', 'desc']).optional().describe("Order sort attribute")
59
+ });
60
+ const getTermSchema = z.object({
61
+ taxonomy: z.string().describe("The taxonomy slug"),
62
+ id: z.number().describe("Term ID")
63
+ });
64
+ const createTermSchema = z.object({
65
+ taxonomy: z.string().describe("The taxonomy slug"),
66
+ name: z.string().describe("Term name"),
67
+ slug: z.string().optional().describe("Term slug"),
68
+ parent: z.number().optional().describe("Parent term ID"),
69
+ description: z.string().optional().describe("Term description"),
70
+ meta: z.record(z.any()).optional().describe("Term meta fields")
71
+ });
72
+ const updateTermSchema = z.object({
73
+ taxonomy: z.string().describe("The taxonomy slug"),
74
+ id: z.number().describe("Term ID"),
75
+ name: z.string().optional().describe("Term name"),
76
+ slug: z.string().optional().describe("Term slug"),
77
+ parent: z.number().optional().describe("Parent term ID"),
78
+ description: z.string().optional().describe("Term description"),
79
+ meta: z.record(z.any()).optional().describe("Term meta fields")
80
+ });
81
+ const deleteTermSchema = z.object({
82
+ taxonomy: z.string().describe("The taxonomy slug"),
83
+ id: z.number().describe("Term ID"),
84
+ force: z.boolean().optional().describe("Required to be true, as terms do not support trashing")
85
+ });
86
+ const assignTermsToContentSchema = z.object({
87
+ content_id: z.number().describe("The content ID"),
88
+ content_type: z.string().describe("The content type slug"),
89
+ taxonomy: z.string().describe("The taxonomy slug"),
90
+ terms: z.array(z.union([z.number(), z.string()])).describe("Array of term IDs or slugs to assign"),
91
+ append: z.boolean().optional().describe("If true, append terms to existing ones. If false, replace all terms")
92
+ });
93
+ const getContentTermsSchema = z.object({
94
+ content_id: z.number().describe("The content ID"),
95
+ content_type: z.string().describe("The content type slug"),
96
+ taxonomy: z.string().optional().describe("Specific taxonomy to retrieve terms from (if not specified, returns all)")
97
+ });
98
+ export const unifiedTaxonomyTools = [
99
+ {
100
+ name: "discover_taxonomies",
101
+ description: "Discovers all available taxonomies (built-in and custom) in the WordPress site",
102
+ inputSchema: { type: "object", properties: discoverTaxonomiesSchema.shape }
103
+ },
104
+ {
105
+ name: "list_terms",
106
+ description: "Lists terms in any taxonomy (categories, tags, or custom taxonomies) with filtering and pagination",
107
+ inputSchema: { type: "object", properties: listTermsSchema.shape }
108
+ },
109
+ {
110
+ name: "get_term",
111
+ description: "Gets a specific term by ID from any taxonomy",
112
+ inputSchema: { type: "object", properties: getTermSchema.shape }
113
+ },
114
+ {
115
+ name: "create_term",
116
+ description: "Creates a new term in any taxonomy",
117
+ inputSchema: { type: "object", properties: createTermSchema.shape }
118
+ },
119
+ {
120
+ name: "update_term",
121
+ description: "Updates an existing term in any taxonomy",
122
+ inputSchema: { type: "object", properties: updateTermSchema.shape }
123
+ },
124
+ {
125
+ name: "delete_term",
126
+ description: "Deletes a term from any taxonomy",
127
+ inputSchema: { type: "object", properties: deleteTermSchema.shape }
128
+ },
129
+ {
130
+ name: "assign_terms_to_content",
131
+ description: "Assigns taxonomy terms to content of any type",
132
+ inputSchema: { type: "object", properties: assignTermsToContentSchema.shape }
133
+ },
134
+ {
135
+ name: "get_content_terms",
136
+ description: "Gets all taxonomy terms assigned to content of any type",
137
+ inputSchema: { type: "object", properties: getContentTermsSchema.shape }
138
+ }
139
+ ];
140
+ export const unifiedTaxonomyHandlers = {
141
+ discover_taxonomies: async (params) => {
142
+ try {
143
+ const taxonomies = await getTaxonomies(params.refresh_cache || false);
144
+ // Filter by content type if specified
145
+ let filteredTaxonomies = taxonomies;
146
+ if (params.content_type) {
147
+ filteredTaxonomies = Object.fromEntries(Object.entries(taxonomies).filter(([_, tax]) => tax.types && tax.types.includes(params.content_type)));
148
+ }
149
+ // Format the response to be more readable
150
+ const formattedTaxonomies = Object.entries(filteredTaxonomies).map(([slug, tax]) => ({
151
+ slug,
152
+ name: tax.name,
153
+ description: tax.description,
154
+ types: tax.types,
155
+ hierarchical: tax.hierarchical,
156
+ rest_base: tax.rest_base,
157
+ labels: tax.labels
158
+ }));
159
+ return {
160
+ toolResult: {
161
+ content: [{
162
+ type: 'text',
163
+ text: JSON.stringify(formattedTaxonomies, null, 2)
164
+ }],
165
+ isError: false
166
+ }
167
+ };
168
+ }
169
+ catch (error) {
170
+ return {
171
+ toolResult: {
172
+ content: [{
173
+ type: 'text',
174
+ text: `Error discovering taxonomies: ${error.message}`
175
+ }],
176
+ isError: true
177
+ }
178
+ };
179
+ }
180
+ },
181
+ list_terms: async (params) => {
182
+ try {
183
+ const endpoint = getTaxonomyEndpoint(params.taxonomy);
184
+ const { taxonomy, ...queryParams } = params;
185
+ const response = await makeWordPressRequest('GET', endpoint, queryParams);
186
+ return {
187
+ toolResult: {
188
+ content: [{
189
+ type: 'text',
190
+ text: JSON.stringify(response, null, 2)
191
+ }],
192
+ isError: false
193
+ }
194
+ };
195
+ }
196
+ catch (error) {
197
+ return {
198
+ toolResult: {
199
+ content: [{
200
+ type: 'text',
201
+ text: `Error listing terms: ${error.message}`
202
+ }],
203
+ isError: true
204
+ }
205
+ };
206
+ }
207
+ },
208
+ get_term: async (params) => {
209
+ try {
210
+ const endpoint = getTaxonomyEndpoint(params.taxonomy);
211
+ const response = await makeWordPressRequest('GET', `${endpoint}/${params.id}`);
212
+ return {
213
+ toolResult: {
214
+ content: [{
215
+ type: 'text',
216
+ text: JSON.stringify(response, null, 2)
217
+ }],
218
+ isError: false
219
+ }
220
+ };
221
+ }
222
+ catch (error) {
223
+ return {
224
+ toolResult: {
225
+ content: [{
226
+ type: 'text',
227
+ text: `Error getting term: ${error.message}`
228
+ }],
229
+ isError: true
230
+ }
231
+ };
232
+ }
233
+ },
234
+ create_term: async (params) => {
235
+ try {
236
+ const endpoint = getTaxonomyEndpoint(params.taxonomy);
237
+ const termData = {
238
+ name: params.name
239
+ };
240
+ if (params.slug !== undefined)
241
+ termData.slug = params.slug;
242
+ if (params.parent !== undefined)
243
+ termData.parent = params.parent;
244
+ if (params.description !== undefined)
245
+ termData.description = params.description;
246
+ if (params.meta !== undefined)
247
+ termData.meta = params.meta;
248
+ const response = await makeWordPressRequest('POST', endpoint, termData);
249
+ return {
250
+ toolResult: {
251
+ content: [{
252
+ type: 'text',
253
+ text: JSON.stringify(response, null, 2)
254
+ }],
255
+ isError: false
256
+ }
257
+ };
258
+ }
259
+ catch (error) {
260
+ return {
261
+ toolResult: {
262
+ content: [{
263
+ type: 'text',
264
+ text: `Error creating term: ${error.message}`
265
+ }],
266
+ isError: true
267
+ }
268
+ };
269
+ }
270
+ },
271
+ update_term: async (params) => {
272
+ try {
273
+ const endpoint = getTaxonomyEndpoint(params.taxonomy);
274
+ const updateData = {};
275
+ if (params.name !== undefined)
276
+ updateData.name = params.name;
277
+ if (params.slug !== undefined)
278
+ updateData.slug = params.slug;
279
+ if (params.parent !== undefined)
280
+ updateData.parent = params.parent;
281
+ if (params.description !== undefined)
282
+ updateData.description = params.description;
283
+ if (params.meta !== undefined)
284
+ updateData.meta = params.meta;
285
+ const response = await makeWordPressRequest('POST', `${endpoint}/${params.id}`, updateData);
286
+ return {
287
+ toolResult: {
288
+ content: [{
289
+ type: 'text',
290
+ text: JSON.stringify(response, null, 2)
291
+ }],
292
+ isError: false
293
+ }
294
+ };
295
+ }
296
+ catch (error) {
297
+ return {
298
+ toolResult: {
299
+ content: [{
300
+ type: 'text',
301
+ text: `Error updating term: ${error.message}`
302
+ }],
303
+ isError: true
304
+ }
305
+ };
306
+ }
307
+ },
308
+ delete_term: async (params) => {
309
+ try {
310
+ const endpoint = getTaxonomyEndpoint(params.taxonomy);
311
+ const response = await makeWordPressRequest('DELETE', `${endpoint}/${params.id}`, {
312
+ force: true // Terms require force to be true
313
+ });
314
+ return {
315
+ toolResult: {
316
+ content: [{
317
+ type: 'text',
318
+ text: JSON.stringify(response, null, 2)
319
+ }],
320
+ isError: false
321
+ }
322
+ };
323
+ }
324
+ catch (error) {
325
+ return {
326
+ toolResult: {
327
+ content: [{
328
+ type: 'text',
329
+ text: `Error deleting term: ${error.message}`
330
+ }],
331
+ isError: true
332
+ }
333
+ };
334
+ }
335
+ },
336
+ assign_terms_to_content: async (params) => {
337
+ try {
338
+ // Determine the content endpoint
339
+ const contentEndpoint = getContentEndpoint(params.content_type);
340
+ // Prepare the update data
341
+ const updateData = {};
342
+ // The field name depends on the taxonomy
343
+ if (params.taxonomy === 'category') {
344
+ updateData.categories = params.terms;
345
+ }
346
+ else if (params.taxonomy === 'post_tag') {
347
+ updateData.tags = params.terms;
348
+ }
349
+ else {
350
+ // For custom taxonomies, use the taxonomy slug as the field name
351
+ updateData[params.taxonomy] = params.terms;
352
+ }
353
+ // If appending, we need to get current terms first
354
+ if (params.append) {
355
+ try {
356
+ const currentContent = await makeWordPressRequest('GET', `${contentEndpoint}/${params.content_id}`);
357
+ const currentTerms = currentContent[params.taxonomy === 'category' ? 'categories' :
358
+ params.taxonomy === 'post_tag' ? 'tags' :
359
+ params.taxonomy] || [];
360
+ // Merge current terms with new terms (remove duplicates)
361
+ const allTerms = [...new Set([...currentTerms, ...params.terms])];
362
+ updateData[params.taxonomy === 'category' ? 'categories' :
363
+ params.taxonomy === 'post_tag' ? 'tags' :
364
+ params.taxonomy] = allTerms;
365
+ }
366
+ catch (error) {
367
+ // If we can't get current terms, just set the new ones
368
+ logToFile(`Warning: Could not get current terms for append operation: ${error}`);
369
+ }
370
+ }
371
+ const response = await makeWordPressRequest('POST', `${contentEndpoint}/${params.content_id}`, updateData);
372
+ return {
373
+ toolResult: {
374
+ content: [{
375
+ type: 'text',
376
+ text: JSON.stringify({
377
+ success: true,
378
+ content_id: params.content_id,
379
+ content_type: params.content_type,
380
+ taxonomy: params.taxonomy,
381
+ assigned_terms: params.terms,
382
+ appended: params.append || false,
383
+ content: response
384
+ }, null, 2)
385
+ }],
386
+ isError: false
387
+ }
388
+ };
389
+ }
390
+ catch (error) {
391
+ return {
392
+ toolResult: {
393
+ content: [{
394
+ type: 'text',
395
+ text: `Error assigning terms to content: ${error.message}`
396
+ }],
397
+ isError: true
398
+ }
399
+ };
400
+ }
401
+ },
402
+ get_content_terms: async (params) => {
403
+ try {
404
+ // First, get the content to see what taxonomies are assigned
405
+ const contentEndpoint = getContentEndpoint(params.content_type);
406
+ const content = await makeWordPressRequest('GET', `${contentEndpoint}/${params.content_id}`);
407
+ // Get all available taxonomies
408
+ const taxonomies = await getTaxonomies();
409
+ const terms = {};
410
+ // If specific taxonomy requested
411
+ if (params.taxonomy) {
412
+ const taxonomyField = params.taxonomy === 'category' ? 'categories' :
413
+ params.taxonomy === 'post_tag' ? 'tags' :
414
+ params.taxonomy;
415
+ if (content[taxonomyField]) {
416
+ // Get full term details
417
+ const endpoint = getTaxonomyEndpoint(params.taxonomy);
418
+ const termDetails = await Promise.all(content[taxonomyField].map(async (termId) => {
419
+ try {
420
+ return await makeWordPressRequest('GET', `${endpoint}/${termId}`);
421
+ }
422
+ catch {
423
+ return { id: termId, error: 'Could not fetch term details' };
424
+ }
425
+ }));
426
+ terms[params.taxonomy] = termDetails;
427
+ }
428
+ }
429
+ else {
430
+ // Get all taxonomy terms for this content
431
+ for (const [taxonomySlug, taxonomyInfo] of Object.entries(taxonomies)) {
432
+ const tax = taxonomyInfo;
433
+ // Check if this taxonomy applies to this content type
434
+ if (tax.types && tax.types.includes(params.content_type)) {
435
+ const taxonomyField = taxonomySlug === 'category' ? 'categories' :
436
+ taxonomySlug === 'post_tag' ? 'tags' :
437
+ taxonomySlug;
438
+ if (content[taxonomyField] && Array.isArray(content[taxonomyField]) && content[taxonomyField].length > 0) {
439
+ const endpoint = getTaxonomyEndpoint(taxonomySlug);
440
+ const termDetails = await Promise.all(content[taxonomyField].map(async (termId) => {
441
+ try {
442
+ return await makeWordPressRequest('GET', `${endpoint}/${termId}`);
443
+ }
444
+ catch {
445
+ return { id: termId, error: 'Could not fetch term details' };
446
+ }
447
+ }));
448
+ terms[taxonomySlug] = termDetails;
449
+ }
450
+ }
451
+ }
452
+ }
453
+ return {
454
+ toolResult: {
455
+ content: [{
456
+ type: 'text',
457
+ text: JSON.stringify({
458
+ content_id: params.content_id,
459
+ content_type: params.content_type,
460
+ terms: terms
461
+ }, null, 2)
462
+ }],
463
+ isError: false
464
+ }
465
+ };
466
+ }
467
+ catch (error) {
468
+ return {
469
+ toolResult: {
470
+ content: [{
471
+ type: 'text',
472
+ text: `Error getting content terms: ${error.message}`
473
+ }],
474
+ isError: true
475
+ }
476
+ };
477
+ }
478
+ }
479
+ };