@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,223 @@
1
+ import axios from 'axios';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ // Global WordPress API client instance
5
+ let wpClient;
6
+ /**
7
+ * Initialize the WordPress API client with authentication
8
+ */
9
+ export async function initWordPress() {
10
+ const apiUrl = process.env.WORDPRESS_API_URL;
11
+ const username = process.env.WORDPRESS_USERNAME;
12
+ const appPassword = process.env.WORDPRESS_PASSWORD;
13
+ if (!apiUrl) {
14
+ throw new Error('WordPress API URL not found in environment variables');
15
+ }
16
+ // Ensure the API URL has the WordPress REST API path
17
+ let baseURL = apiUrl.endsWith('/') ? apiUrl : `${apiUrl}/`;
18
+ // Add the WordPress REST API base path if not already included
19
+ if (!baseURL.includes('/wp-json/')) {
20
+ baseURL = baseURL + 'wp-json/';
21
+ }
22
+ else if (!baseURL.endsWith('/')) {
23
+ // Ensure the URL ends with a trailing slash
24
+ baseURL = baseURL + '/';
25
+ }
26
+ const config = {
27
+ baseURL,
28
+ timeout: 120000, // 120 seconds for AI image generation (OpenRouter can be slow)
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ },
32
+ };
33
+ // Add authentication if credentials are provided
34
+ if (username && appPassword) {
35
+ logToFile('Adding authentication headers');
36
+ logToFile(`Username: ${username}`);
37
+ logToFile(`App Password: ${appPassword}`);
38
+ const auth = Buffer.from(`${username}:${appPassword}`).toString('base64');
39
+ config.headers = {
40
+ ...config.headers,
41
+ 'Authorization': `Basic ${auth}`
42
+ };
43
+ }
44
+ wpClient = axios.create(config);
45
+ // Verify connection to WordPress API
46
+ try {
47
+ await wpClient.get('');
48
+ logToFile('Successfully connected to WordPress API');
49
+ }
50
+ catch (error) {
51
+ logToFile(`Failed to connect to WordPress API: ${error.message}`);
52
+ throw new Error(`Failed to connect to WordPress API: ${error.message}`);
53
+ }
54
+ }
55
+ // Configure logging
56
+ const META_URL = import.meta.url.replace(/^file:\/\/\//, '');
57
+ const LOG_DIR = path.join(path.dirname(META_URL), '../logs');
58
+ const LOG_FILE = path.join(LOG_DIR, 'wordpress-api.log');
59
+ // Ensure log directory exists
60
+ if (!fs.existsSync(LOG_DIR)) {
61
+ fs.mkdirSync(LOG_DIR, { recursive: true });
62
+ }
63
+ export function logToFile(message) {
64
+ const timestamp = new Date().toISOString();
65
+ const logMessage = `[${timestamp}] ${message}\n`;
66
+ fs.appendFileSync(LOG_FILE, logMessage);
67
+ }
68
+ /**
69
+ * Make a request to the WordPress API
70
+ * @param method HTTP method
71
+ * @param endpoint API endpoint (relative to the baseURL)
72
+ * @param data Request data
73
+ * @param options Additional request options
74
+ * @returns Response data
75
+ */
76
+ export async function makeWordPressRequest(method, endpoint, data, options) {
77
+ if (!wpClient) {
78
+ throw new Error('WordPress client not initialized');
79
+ }
80
+ // Log data (skip for FormData which can't be stringified)
81
+ if (!options?.isFormData) {
82
+ logToFile(`Data: ${JSON.stringify(data, null, 2)}`);
83
+ }
84
+ else {
85
+ logToFile('Request contains FormData (not shown in logs)');
86
+ }
87
+ // Handle potential leading slash in endpoint
88
+ const path = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
89
+ try {
90
+ const fullUrl = `${wpClient.defaults.baseURL}${path}`;
91
+ // Prepare request config
92
+ const requestConfig = {
93
+ method,
94
+ url: path,
95
+ headers: options?.headers || {}
96
+ };
97
+ // Handle different data formats based on method and options
98
+ if (method === 'GET') {
99
+ requestConfig.params = data;
100
+ }
101
+ else if (options?.isFormData) {
102
+ // For FormData, pass it directly without stringifying
103
+ requestConfig.data = data;
104
+ }
105
+ else if (method === 'POST') {
106
+ requestConfig.data = JSON.stringify(data);
107
+ }
108
+ else {
109
+ requestConfig.data = data;
110
+ }
111
+ const requestLog = `
112
+ REQUEST:
113
+ URL: ${fullUrl}
114
+ Method: ${method}
115
+ Headers: ${JSON.stringify({ ...wpClient.defaults.headers, ...requestConfig.headers }, null, 2)}
116
+ Data: ${options?.isFormData ? '(FormData not shown)' : JSON.stringify(data, null, 2)}
117
+ `;
118
+ logToFile(requestLog);
119
+ const response = await wpClient.request(requestConfig);
120
+ const responseLog = `
121
+ RESPONSE:
122
+ Status: ${response.status}
123
+ Data: ${JSON.stringify(response.data, null, 2)}
124
+ `;
125
+ logToFile(responseLog);
126
+ return options?.rawResponse ? response : response.data;
127
+ }
128
+ catch (error) {
129
+ const errorLog = `
130
+ ERROR:
131
+ Message: ${error.message}
132
+ Status: ${error.response?.status || 'N/A'}
133
+ Data: ${JSON.stringify(error.response?.data || {}, null, 2)}
134
+ `;
135
+ console.error(errorLog);
136
+ logToFile(errorLog);
137
+ throw error;
138
+ }
139
+ }
140
+ /**
141
+ * Make a request to the WordPress.org Plugin Repository API
142
+ * @param searchQuery Search query string
143
+ * @param page Page number (1-based)
144
+ * @param perPage Number of results per page
145
+ * @returns Response data from WordPress.org Plugin API
146
+ */
147
+ export async function searchWordPressPluginRepository(searchQuery, page = 1, perPage = 10) {
148
+ try {
149
+ // WordPress.org Plugin API endpoint
150
+ const apiUrl = 'https://api.wordpress.org/plugins/info/1.2/';
151
+ // Build the request data according to WordPress.org Plugin API format
152
+ const requestData = {
153
+ action: 'query_plugins',
154
+ request: {
155
+ search: searchQuery,
156
+ page: page,
157
+ per_page: perPage,
158
+ fields: {
159
+ description: true,
160
+ sections: false,
161
+ tested: true,
162
+ requires: true,
163
+ rating: true,
164
+ ratings: false,
165
+ downloaded: true,
166
+ downloadlink: true,
167
+ last_updated: true,
168
+ homepage: true,
169
+ tags: true
170
+ }
171
+ }
172
+ };
173
+ const requestLog = `
174
+ WORDPRESS.ORG PLUGIN API REQUEST:
175
+ URL: ${apiUrl}
176
+ Method: GET
177
+ Params: ${JSON.stringify(requestData, null, 2)}
178
+ `;
179
+ logToFile(requestLog);
180
+ // WordPress.org Plugin API requires GET requests with serialized query parameters
181
+ const response = await axios.get(apiUrl, {
182
+ params: requestData,
183
+ paramsSerializer: (params) => {
184
+ // Serialize nested objects properly for WordPress.org API
185
+ // Format: action=query_plugins&request[search]=term&request[page]=1
186
+ const flatParams = new URLSearchParams();
187
+ flatParams.append('action', params.action);
188
+ Object.keys(params.request).forEach(key => {
189
+ const value = params.request[key];
190
+ if (typeof value === 'object' && value !== null) {
191
+ // Handle nested objects like fields
192
+ Object.keys(value).forEach(subKey => {
193
+ flatParams.append(`request[${key}][${subKey}]`, String(value[subKey]));
194
+ });
195
+ }
196
+ else {
197
+ flatParams.append(`request[${key}]`, String(value));
198
+ }
199
+ });
200
+ return flatParams.toString();
201
+ }
202
+ });
203
+ const responseLog = `
204
+ WORDPRESS.ORG PLUGIN API RESPONSE:
205
+ Status: ${response.status}
206
+ Info: ${JSON.stringify(response.data.info, null, 2)}
207
+ Plugins Count: ${response.data.plugins?.length || 0}
208
+ `;
209
+ logToFile(responseLog);
210
+ return response.data;
211
+ }
212
+ catch (error) {
213
+ const errorLog = `
214
+ WORDPRESS.ORG PLUGIN API ERROR:
215
+ Message: ${error.message}
216
+ Status: ${error.response?.status || 'N/A'}
217
+ Data: ${JSON.stringify(error.response?.data || {}, null, 2)}
218
+ `;
219
+ console.error(errorLog);
220
+ logToFile(errorLog);
221
+ throw error;
222
+ }
223
+ }
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@wplaunchify/ml-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "Universal MCP Server for WordPress + Fluent Suite (Community, CRM, Cart) + MinuteLaunch Plugins. 145 tools for AI-powered WordPress management via Claude, Cursor, and other MCP clients.",
5
+ "type": "module",
6
+ "main": "./build/server.js",
7
+ "exports": "./build/server.js",
8
+ "bin": {
9
+ "ml-mcp-server": "./build/server.js"
10
+ },
11
+ "engines": {
12
+ "node": ">=18.0.0"
13
+ },
14
+ "scripts": {
15
+ "build": "tsc --project tsconfig.json",
16
+ "start": "node ./build/server.js",
17
+ "dev": "tsx watch src/server.ts",
18
+ "clean": "rimraf build",
19
+ "prepare": "npm run build"
20
+ },
21
+ "keywords": [
22
+ "wordpress",
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "fluent-community",
26
+ "fluent-crm",
27
+ "fluent-cart",
28
+ "minutelaunch",
29
+ "ai",
30
+ "claude",
31
+ "cursor"
32
+ ],
33
+ "author": "1WD LLC",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/wplaunchify/ml-mcp-server.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/wplaunchify/ml-mcp-server/issues"
41
+ },
42
+ "homepage": "https://github.com/wplaunchify/ml-mcp-server#readme",
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.4.1",
45
+ "axios": "^1.6.7",
46
+ "dotenv": "^16.4.5",
47
+ "fs-extra": "^11.2.0",
48
+ "zod": "^3.23.8",
49
+ "zod-to-json-schema": "^3.24.1"
50
+ },
51
+ "devDependencies": {
52
+ "@types/fs-extra": "^11.0.4",
53
+ "@types/node": "^22.10.0",
54
+ "rimraf": "^5.0.5",
55
+ "tsx": "^4.7.1",
56
+ "typescript": "^5.3.3"
57
+ },
58
+ "publishConfig": {
59
+ "access": "public"
60
+ },
61
+ "files": [
62
+ "build",
63
+ "README.md",
64
+ "LICENSE"
65
+ ]
66
+ }
67
+