@wplaunchify/ml-mcp-server 2.5.8 → 2.5.10

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/build/server.js CHANGED
@@ -5,6 +5,7 @@ import * as dotenv from 'dotenv';
5
5
  dotenv.config({ path: '.env' });
6
6
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
7
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
+ import { allTools, toolHandlers } from './tools/index.js';
8
9
  import { z } from 'zod';
9
10
  // Generate server name from WordPress URL
10
11
  function generateServerName() {
@@ -39,50 +40,56 @@ function generateServerName() {
39
40
  return 'wordpress';
40
41
  }
41
42
  }
42
- /**
43
- * Register tools with the MCP server
44
- * This function is called after async tool loading completes
45
- */
46
- function registerTools(server, loadedTools, handlers) {
47
- let registeredCount = 0;
48
- for (const tool of loadedTools) {
49
- const handler = handlers[tool.name];
50
- if (!handler) {
51
- console.error(`⚠️ No handler for tool: ${tool.name}`);
52
- continue;
53
- }
54
- const wrappedHandler = async (args) => {
55
- try {
56
- // The handler functions are already typed with their specific parameter types
57
- const result = await handler(args);
58
- return {
59
- content: result.toolResult.content.map((item) => ({
60
- ...item,
61
- type: "text"
62
- })),
63
- isError: result.toolResult.isError
64
- };
65
- }
66
- catch (error) {
67
- // Return error as tool result instead of throwing
68
- return {
69
- content: [{
70
- type: "text",
71
- text: `Error executing ${tool.name}: ${error.message || String(error)}`
72
- }],
73
- isError: true
74
- };
75
- }
76
- };
77
- const zodSchema = z.object(tool.inputSchema.properties);
78
- server.tool(tool.name, zodSchema.shape, wrappedHandler);
79
- registeredCount++;
43
+ // Create MCP server instance
44
+ const server = new McpServer({
45
+ name: generateServerName(),
46
+ version: "1.0.7"
47
+ }, {
48
+ capabilities: {
49
+ tools: allTools.reduce((acc, tool) => {
50
+ acc[tool.name] = tool;
51
+ return acc;
52
+ }, {})
53
+ }
54
+ });
55
+ // Register each tool from our tools list with its corresponding handler
56
+ let registeredCount = 0;
57
+ for (const tool of allTools) {
58
+ const handler = toolHandlers[tool.name];
59
+ if (!handler) {
60
+ console.error(`⚠️ No handler for tool: ${tool.name}`);
61
+ continue;
80
62
  }
81
- console.error(`✅ Registered ${registeredCount} of ${loadedTools.length} tools`);
82
- return registeredCount;
63
+ const wrappedHandler = async (args) => {
64
+ try {
65
+ // The handler functions are already typed with their specific parameter types
66
+ const result = await handler(args);
67
+ return {
68
+ content: result.toolResult.content.map((item) => ({
69
+ ...item,
70
+ type: "text"
71
+ })),
72
+ isError: result.toolResult.isError
73
+ };
74
+ }
75
+ catch (error) {
76
+ // Return error as tool result instead of throwing
77
+ return {
78
+ content: [{
79
+ type: "text",
80
+ text: `Error executing ${tool.name}: ${error.message || String(error)}`
81
+ }],
82
+ isError: true
83
+ };
84
+ }
85
+ };
86
+ const zodSchema = z.object(tool.inputSchema.properties);
87
+ server.tool(tool.name, zodSchema.shape, wrappedHandler);
88
+ registeredCount++;
83
89
  }
90
+ console.error(`✅ Registered ${registeredCount} of ${allTools.length} tools`);
84
91
  async function main() {
85
- const { logToFile, initWordPress } = await import('./wordpress.js');
92
+ const { logToFile } = await import('./wordpress.js');
86
93
  logToFile('Starting WordPress MCP server...');
87
94
  // Environment variables are passed by MCP client (Claude Desktop, Cursor, etc.)
88
95
  // Don't exit here - let initWordPress() handle the validation
@@ -91,28 +98,9 @@ async function main() {
91
98
  }
92
99
  try {
93
100
  logToFile('Initializing WordPress client...');
101
+ const { initWordPress } = await import('./wordpress.js');
94
102
  await initWordPress();
95
103
  logToFile('WordPress client initialized successfully.');
96
- // Load tools with graceful plugin detection
97
- logToFile('Loading tools with plugin detection...');
98
- const { getFilteredToolsAsync, getFilteredHandlersAsync } = await import('./tools/index.js');
99
- const loadedTools = await getFilteredToolsAsync();
100
- const loadedHandlers = await getFilteredHandlersAsync(loadedTools);
101
- logToFile(`Loaded ${loadedTools.length} tools based on installed plugins`);
102
- // Create MCP server instance with loaded tools
103
- const server = new McpServer({
104
- name: generateServerName(),
105
- version: "1.0.7"
106
- }, {
107
- capabilities: {
108
- tools: loadedTools.reduce((acc, tool) => {
109
- acc[tool.name] = tool;
110
- return acc;
111
- }, {})
112
- }
113
- });
114
- // Register tools with handlers
115
- registerTools(server, loadedTools, loadedHandlers);
116
104
  logToFile('Setting up server transport...');
117
105
  const transport = new StdioServerTransport();
118
106
  await server.connect(transport);
@@ -1,13 +1,3 @@
1
1
  import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
- /**
3
- * Async version of getFilteredTools() that detects installed plugins
4
- * and only loads tools for installed plugins when ENABLED_TOOLS='all' or not set
5
- */
6
- declare function getFilteredToolsAsync(): Promise<Tool[]>;
7
- /**
8
- * Async version that returns handlers matching the tools loaded by getFilteredToolsAsync()
9
- */
10
- declare function getFilteredHandlersAsync(loadedTools: Tool[]): Promise<Record<string, any>>;
11
2
  export declare const allTools: Tool[];
12
3
  export declare const toolHandlers: Record<string, any>;
13
- export { getFilteredToolsAsync, getFilteredHandlersAsync };
@@ -1,4 +1,3 @@
1
- import { detectInstalledPlugins } from '../wordpress.js';
2
1
  import { unifiedContentTools, unifiedContentHandlers } from './unified-content.js';
3
2
  import { unifiedTaxonomyTools, unifiedTaxonomyHandlers } from './unified-taxonomies.js';
4
3
  import { pluginTools, pluginHandlers } from './plugins.js';
@@ -130,26 +129,10 @@ const handlerCategories = {
130
129
  ...debugHandlers
131
130
  }
132
131
  };
133
- // Plugin slug mappings - which plugin slugs indicate which tool categories should load
134
- const pluginRequirements = {
135
- fluentcommunity: ['fluent-community', 'fluentcommunity'],
136
- 'fluentcommunity-core': ['fluent-community', 'fluentcommunity'],
137
- 'fluentcommunity-learning': ['fluent-community', 'fluentcommunity'],
138
- fluentcart: ['fluent-cart', 'fluentcart', 'wp-payment-form'],
139
- fluentcrm: ['fluent-crm', 'fluentcrm'],
140
- mlplugins: ['ml-image-editor', 'ml-media-hub', 'fluent-affiliate'],
141
- pro: ['fluent-mcp-pro', 'fluentmcp-pro']
142
- };
143
- /**
144
- * Check if any of the required plugin slugs are installed
145
- */
146
- function hasAnyPlugin(installedPlugins, requiredSlugs) {
147
- return requiredSlugs.some(slug => installedPlugins.has(slug));
148
- }
149
132
  // Filter tools based on ENABLED_TOOLS environment variable
150
133
  function getFilteredTools() {
151
134
  const enabledTools = process.env.ENABLED_TOOLS?.toLowerCase();
152
- // If specific category requested, honor it (no detection needed)
135
+ // If specific category requested, honor it
153
136
  if (enabledTools && enabledTools !== 'all') {
154
137
  // Map user-friendly names to internal category names
155
138
  const categoryMap = {
@@ -177,8 +160,8 @@ function getFilteredTools() {
177
160
  }
178
161
  console.error(`⚠️ Unknown ENABLED_TOOLS value: ${enabledTools}. Loading all tools.`);
179
162
  }
180
- // ENABLED_TOOLS not set or 'all' - load all tools without detection
181
- // Detection will happen async in getFilteredToolsAsync()
163
+ // ENABLED_TOOLS not set or 'all' - load all tools
164
+ // No plugin detection during startup to prevent Claude Desktop crashes
182
165
  return [
183
166
  ...toolCategories.wordpress,
184
167
  ...toolCategories.fluentcommunity,
@@ -189,51 +172,6 @@ function getFilteredTools() {
189
172
  ...toolCategories.debug
190
173
  ];
191
174
  }
192
- /**
193
- * Async version of getFilteredTools() that detects installed plugins
194
- * and only loads tools for installed plugins when ENABLED_TOOLS='all' or not set
195
- */
196
- async function getFilteredToolsAsync() {
197
- const enabledTools = process.env.ENABLED_TOOLS?.toLowerCase();
198
- // If specific category requested, use sync version (no detection needed)
199
- if (enabledTools && enabledTools !== 'all') {
200
- return getFilteredTools();
201
- }
202
- // Detect installed plugins
203
- console.error('🔍 Detecting installed plugins...');
204
- const installedPlugins = await detectInstalledPlugins();
205
- if (installedPlugins.size === 0) {
206
- // Detection failed - fall back to loading all tools (safe default)
207
- console.error('⚠️ Plugin detection failed. Loading all tools as fallback.');
208
- return getFilteredTools();
209
- }
210
- // Always include WordPress core tools and debug tools
211
- const tools = [...toolCategories.wordpress, ...toolCategories.debug];
212
- let loadedCategories = ['wordpress', 'debug'];
213
- // Conditionally add plugin tools based on detection
214
- if (hasAnyPlugin(installedPlugins, pluginRequirements.fluentcommunity)) {
215
- tools.push(...toolCategories.fluentcommunity);
216
- loadedCategories.push('fluentcommunity');
217
- }
218
- if (hasAnyPlugin(installedPlugins, pluginRequirements.fluentcart)) {
219
- tools.push(...toolCategories.fluentcart);
220
- loadedCategories.push('fluentcart');
221
- }
222
- if (hasAnyPlugin(installedPlugins, pluginRequirements.fluentcrm)) {
223
- tools.push(...toolCategories.fluentcrm);
224
- loadedCategories.push('fluentcrm');
225
- }
226
- if (hasAnyPlugin(installedPlugins, pluginRequirements.mlplugins)) {
227
- tools.push(...toolCategories.mlplugins);
228
- loadedCategories.push('mlplugins');
229
- }
230
- if (hasAnyPlugin(installedPlugins, pluginRequirements.pro)) {
231
- tools.push(...toolCategories.pro);
232
- loadedCategories.push('pro');
233
- }
234
- console.error(`✅ Loaded ${tools.length} tools from categories: ${loadedCategories.join(', ')}`);
235
- return tools;
236
- }
237
175
  function getFilteredHandlers() {
238
176
  const enabledTools = process.env.ENABLED_TOOLS?.toLowerCase();
239
177
  if (!enabledTools || enabledTools === 'all') {
@@ -281,45 +219,6 @@ function getFilteredHandlers() {
281
219
  ...handlerCategories.debug
282
220
  };
283
221
  }
284
- /**
285
- * Async version that returns handlers matching the tools loaded by getFilteredToolsAsync()
286
- */
287
- async function getFilteredHandlersAsync(loadedTools) {
288
- const enabledTools = process.env.ENABLED_TOOLS?.toLowerCase();
289
- // If specific category requested, use sync version
290
- if (enabledTools && enabledTools !== 'all') {
291
- return getFilteredHandlers();
292
- }
293
- // Build handlers object based on which tools were loaded
294
- const handlers = {
295
- ...handlerCategories.wordpress,
296
- ...handlerCategories.debug
297
- };
298
- // Check which tool categories are present in loadedTools
299
- const hasFluentCommunity = loadedTools.some(t => t.name.startsWith('fc_'));
300
- const hasFluentCart = loadedTools.some(t => t.name.startsWith('fcart_'));
301
- const hasFluentCRM = loadedTools.some(t => t.name.startsWith('fcrm_'));
302
- const hasMLPlugins = loadedTools.some(t => t.name.startsWith('mlimg_') || t.name.startsWith('mlmh_') || t.name.startsWith('faf_'));
303
- const hasPro = loadedTools.some(t => t.name.startsWith('fmcp_pro_'));
304
- if (hasFluentCommunity) {
305
- Object.assign(handlers, handlerCategories.fluentcommunity);
306
- }
307
- if (hasFluentCart) {
308
- Object.assign(handlers, handlerCategories.fluentcart);
309
- }
310
- if (hasFluentCRM) {
311
- Object.assign(handlers, handlerCategories.fluentcrm);
312
- }
313
- if (hasMLPlugins) {
314
- Object.assign(handlers, handlerCategories.mlplugins);
315
- }
316
- if (hasPro) {
317
- Object.assign(handlers, handlerCategories.pro);
318
- }
319
- return handlers;
320
- }
321
- // Export filtered tools and handlers (sync versions for backward compatibility)
222
+ // Export filtered tools and handlers
322
223
  export const allTools = getFilteredTools();
323
224
  export const toolHandlers = getFilteredHandlers();
324
- // Export async versions for graceful plugin detection
325
- export { getFilteredToolsAsync, getFilteredHandlersAsync };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wplaunchify/ml-mcp-server",
3
- "version": "2.5.8",
3
+ "version": "2.5.10",
4
4
  "description": "Universal MCP Server for WordPress + Fluent Suite (Community, CRM, Cart) + FluentMCP Pro. Comprehensive tools for AI-powered WordPress management via Claude, Cursor, and other MCP clients.",
5
5
  "type": "module",
6
6
  "main": "./build/server.js",