@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.
- package/LICENSE +22 -0
- package/README.md +220 -0
- package/build/cli.d.ts +2 -0
- package/build/cli.js +52 -0
- package/build/server.d.ts +2 -0
- package/build/server.js +97 -0
- package/build/tools/comments.d.ts +212 -0
- package/build/tools/comments.js +181 -0
- package/build/tools/fluent-affiliate.d.ts +2 -0
- package/build/tools/fluent-affiliate.js +3 -0
- package/build/tools/fluent-cart.d.ts +706 -0
- package/build/tools/fluent-cart.js +642 -0
- package/build/tools/fluent-community-BACKUP.d.ts +364 -0
- package/build/tools/fluent-community-BACKUP.js +883 -0
- package/build/tools/fluent-community-MINIMAL.d.ts +69 -0
- package/build/tools/fluent-community-MINIMAL.js +92 -0
- package/build/tools/fluent-community-design.d.ts +3 -0
- package/build/tools/fluent-community-design.js +150 -0
- package/build/tools/fluent-community-layout.d.ts +119 -0
- package/build/tools/fluent-community-layout.js +88 -0
- package/build/tools/fluent-community.d.ts +364 -0
- package/build/tools/fluent-community.js +528 -0
- package/build/tools/fluent-crm.d.ts +3 -0
- package/build/tools/fluent-crm.js +392 -0
- package/build/tools/index.d.ts +2205 -0
- package/build/tools/index.js +54 -0
- package/build/tools/media.d.ts +135 -0
- package/build/tools/media.js +168 -0
- package/build/tools/ml-canvas.d.ts +91 -0
- package/build/tools/ml-canvas.js +109 -0
- package/build/tools/ml-image-editor.d.ts +230 -0
- package/build/tools/ml-image-editor.js +270 -0
- package/build/tools/ml-media-hub.d.ts +575 -0
- package/build/tools/ml-media-hub.js +714 -0
- package/build/tools/plugin-repository.d.ts +62 -0
- package/build/tools/plugin-repository.js +149 -0
- package/build/tools/plugins.d.ts +129 -0
- package/build/tools/plugins.js +148 -0
- package/build/tools/unified-content.d.ts +313 -0
- package/build/tools/unified-content.js +615 -0
- package/build/tools/unified-taxonomies.d.ts +229 -0
- package/build/tools/unified-taxonomies.js +479 -0
- package/build/tools/users.d.ts +227 -0
- package/build/tools/users.js +182 -0
- package/build/types/wordpress-types.d.ts +151 -0
- package/build/types/wordpress-types.js +2 -0
- package/build/wordpress.d.ts +26 -0
- package/build/wordpress.js +223 -0
- 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
|
+
|