@democratize-quality/mcp-server 1.2.0 → 1.2.1

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 (56) hide show
  1. package/cli.js +248 -0
  2. package/package.json +7 -5
  3. package/src/chatmodes//360/237/214/220 api-generator.chatmode.md" +409 -0
  4. package/src/chatmodes//360/237/214/220 api-healer.chatmode.md" +494 -0
  5. package/src/chatmodes//360/237/214/220 api-planner.chatmode.md" +954 -0
  6. package/src/config/environments/api-only.js +72 -0
  7. package/src/config/environments/development.js +73 -0
  8. package/src/config/environments/production.js +88 -0
  9. package/src/config/index.js +360 -0
  10. package/src/config/server.js +60 -0
  11. package/src/config/tools/api.js +86 -0
  12. package/src/config/tools/browser.js +109 -0
  13. package/src/config/tools/default.js +51 -0
  14. package/src/docs/Agent_README.md +310 -0
  15. package/src/docs/QUICK_REFERENCE.md +111 -0
  16. package/src/server.ts +234 -0
  17. package/src/services/browserService.js +344 -0
  18. package/src/skills/api-planning/SKILL.md +224 -0
  19. package/src/skills/test-execution/SKILL.md +777 -0
  20. package/src/skills/test-generation/SKILL.md +309 -0
  21. package/src/skills/test-healing/SKILL.md +405 -0
  22. package/src/tools/api/api-generator.js +1884 -0
  23. package/src/tools/api/api-healer.js +636 -0
  24. package/src/tools/api/api-planner.js +2617 -0
  25. package/src/tools/api/api-project-setup.js +332 -0
  26. package/src/tools/api/api-request.js +660 -0
  27. package/src/tools/api/api-session-report.js +1297 -0
  28. package/src/tools/api/api-session-status.js +414 -0
  29. package/src/tools/api/prompts/README.md +293 -0
  30. package/src/tools/api/prompts/generation-prompts.js +722 -0
  31. package/src/tools/api/prompts/healing-prompts.js +214 -0
  32. package/src/tools/api/prompts/index.js +44 -0
  33. package/src/tools/api/prompts/orchestrator.js +353 -0
  34. package/src/tools/api/prompts/validation-rules.js +358 -0
  35. package/src/tools/base/ToolBase.js +249 -0
  36. package/src/tools/base/ToolRegistry.js +288 -0
  37. package/src/tools/browser/advanced/browser-console.js +403 -0
  38. package/src/tools/browser/advanced/browser-dialog.js +338 -0
  39. package/src/tools/browser/advanced/browser-evaluate.js +356 -0
  40. package/src/tools/browser/advanced/browser-file.js +499 -0
  41. package/src/tools/browser/advanced/browser-keyboard.js +362 -0
  42. package/src/tools/browser/advanced/browser-mouse.js +351 -0
  43. package/src/tools/browser/advanced/browser-network.js +440 -0
  44. package/src/tools/browser/advanced/browser-pdf.js +426 -0
  45. package/src/tools/browser/advanced/browser-tabs.js +516 -0
  46. package/src/tools/browser/advanced/browser-wait.js +397 -0
  47. package/src/tools/browser/click.js +187 -0
  48. package/src/tools/browser/close.js +79 -0
  49. package/src/tools/browser/dom.js +89 -0
  50. package/src/tools/browser/launch.js +86 -0
  51. package/src/tools/browser/navigate.js +289 -0
  52. package/src/tools/browser/screenshot.js +370 -0
  53. package/src/tools/browser/type.js +193 -0
  54. package/src/tools/index.js +114 -0
  55. package/src/utils/agentInstaller.js +437 -0
  56. package/src/utils/browserHelpers.js +102 -0
@@ -0,0 +1,370 @@
1
+ /**
2
+ * Copyright (C) 2025 Democratize Quality
3
+ *
4
+ * This file is part of Democratize Quality MCP Server.
5
+ *
6
+ * Democratize Quality MCP Server is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU Affero General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Democratize Quality MCP Server is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU Affero General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Affero General Public License
17
+ * along with Democratize Quality MCP Server. If not, see <https://www.gnu.org/licenses/>.
18
+ */
19
+
20
+ const ToolBase = require('../base/ToolBase');
21
+ const browserService = require('../../services/browserService');
22
+
23
+ /**
24
+ * Enhanced Browser Screenshot Tool
25
+ * Captures screenshots with advanced options including element-specific and full-page captures
26
+ * Inspired by Playwright MCP screenshot capabilities
27
+ */
28
+ class BrowserScreenshotTool extends ToolBase {
29
+ static definition = {
30
+ name: "browser_screenshot",
31
+ description: "Capture screenshots with advanced options including full page, element-specific, and custom formats with quality control.",
32
+ input_schema: {
33
+ type: "object",
34
+ properties: {
35
+ browserId: {
36
+ type: "string",
37
+ description: "The ID of the browser instance."
38
+ },
39
+ fileName: {
40
+ type: "string",
41
+ description: "Optional. The name of the file to save the screenshot as (e.g., 'my_page.png'). Saved to the server's configured output directory. If not provided, a timestamped name is used."
42
+ },
43
+ saveToDisk: {
44
+ type: "boolean",
45
+ description: "Optional. Whether to save the screenshot to disk on the server. Defaults to true. Set to false to only receive base64 data.",
46
+ default: true
47
+ },
48
+ options: {
49
+ type: "object",
50
+ properties: {
51
+ fullPage: {
52
+ type: "boolean",
53
+ default: false,
54
+ description: "Capture full scrollable page instead of just viewport"
55
+ },
56
+ element: {
57
+ type: "string",
58
+ description: "CSS selector of element to screenshot (captures only that element)"
59
+ },
60
+ format: {
61
+ type: "string",
62
+ enum: ["png", "jpeg", "webp"],
63
+ default: "png",
64
+ description: "Image format"
65
+ },
66
+ quality: {
67
+ type: "number",
68
+ minimum: 0,
69
+ maximum: 100,
70
+ description: "JPEG/WebP quality (0-100, ignored for PNG)"
71
+ },
72
+ clip: {
73
+ type: "object",
74
+ properties: {
75
+ x: { type: "number", description: "X coordinate of clip area" },
76
+ y: { type: "number", description: "Y coordinate of clip area" },
77
+ width: { type: "number", description: "Width of clip area" },
78
+ height: { type: "number", description: "Height of clip area" },
79
+ scale: { type: "number", description: "Scale factor for clip area" }
80
+ },
81
+ description: "Specific area to capture"
82
+ },
83
+ omitBackground: {
84
+ type: "boolean",
85
+ default: false,
86
+ description: "Hide default white background for transparent screenshots"
87
+ },
88
+ captureBeyondViewport: {
89
+ type: "boolean",
90
+ default: false,
91
+ description: "Capture content outside viewport"
92
+ }
93
+ },
94
+ description: "Screenshot capture options"
95
+ }
96
+ },
97
+ required: ["browserId"]
98
+ },
99
+ output_schema: {
100
+ type: "object",
101
+ properties: {
102
+ success: { type: "boolean", description: "Whether screenshot was captured successfully" },
103
+ imageData: { type: "string", description: "Base64 encoded image data" },
104
+ format: { type: "string", description: "Image format used" },
105
+ fileName: { type: "string", description: "The file name if saved to disk" },
106
+ dimensions: {
107
+ type: "object",
108
+ properties: {
109
+ width: { type: "number" },
110
+ height: { type: "number" }
111
+ },
112
+ description: "Image dimensions"
113
+ },
114
+ fileSize: { type: "number", description: "File size in bytes" },
115
+ element: { type: "string", description: "CSS selector if element screenshot was taken" },
116
+ browserId: { type: "string", description: "The browser instance ID that was used" }
117
+ },
118
+ required: ["success", "imageData", "format", "browserId"]
119
+ }
120
+ };
121
+
122
+ async execute(parameters) {
123
+ const {
124
+ browserId,
125
+ fileName,
126
+ saveToDisk = true,
127
+ options = {}
128
+ } = parameters;
129
+
130
+ const browser = browserService.getBrowserInstance(browserId);
131
+ if (!browser) {
132
+ throw new Error(`Browser instance '${browserId}' not found. Please launch a browser first using browser_launch.`);
133
+ }
134
+
135
+ // Generate filename if not provided
136
+ const fileExtension = this.getFileExtension(options.format || 'png');
137
+ const finalFileName = fileName || `screenshot_${browserId}_${Date.now()}.${fileExtension}`;
138
+
139
+ console.error(`[BrowserScreenshotTool] Taking screenshot of browser ${browserId}, fileName: ${finalFileName}, saveToDisk: ${saveToDisk}`);
140
+
141
+ try {
142
+ let screenshotResult;
143
+
144
+ if (options.element) {
145
+ screenshotResult = await this.captureElementScreenshot(browser.client, options);
146
+ } else {
147
+ screenshotResult = await this.capturePageScreenshot(browser.client, options);
148
+ }
149
+
150
+ // Save to disk if requested
151
+ let savedPath = null;
152
+ if (saveToDisk) {
153
+ savedPath = await this.saveScreenshot(screenshotResult.data, finalFileName);
154
+ }
155
+
156
+ console.error(`[BrowserScreenshotTool] Successfully captured screenshot for browser: ${browserId}`);
157
+
158
+ return {
159
+ success: true,
160
+ imageData: screenshotResult.data,
161
+ format: options.format || 'png',
162
+ fileName: savedPath ? finalFileName : null,
163
+ dimensions: screenshotResult.dimensions,
164
+ fileSize: screenshotResult.fileSize,
165
+ element: options.element || null,
166
+ browserId: browserId
167
+ };
168
+
169
+ } catch (error) {
170
+ console.error(`[BrowserScreenshotTool] Failed to take screenshot:`, error.message);
171
+ throw new Error(`Failed to take screenshot of browser ${browserId}: ${error.message}`);
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Capture page screenshot with options
177
+ */
178
+ async capturePageScreenshot(client, options) {
179
+ await client.Page.enable();
180
+
181
+ const screenshotOptions = {
182
+ format: options.format || 'png',
183
+ quality: options.format !== 'png' ? options.quality : undefined,
184
+ optimizeForSpeed: false,
185
+ captureBeyondViewport: options.captureBeyondViewport || options.fullPage || false
186
+ };
187
+
188
+ // Handle clip area
189
+ if (options.clip) {
190
+ screenshotOptions.clip = options.clip;
191
+ }
192
+
193
+ // Handle full page screenshot
194
+ if (options.fullPage && !options.clip) {
195
+ const layoutMetrics = await client.Page.getLayoutMetrics();
196
+ screenshotOptions.clip = {
197
+ x: 0,
198
+ y: 0,
199
+ width: layoutMetrics.contentSize.width,
200
+ height: layoutMetrics.contentSize.height,
201
+ scale: 1
202
+ };
203
+ }
204
+
205
+ // Handle transparent background
206
+ if (options.omitBackground) {
207
+ // Set background to transparent (requires format support)
208
+ await client.Emulation.setDefaultBackgroundColorOverride({
209
+ color: { r: 0, g: 0, b: 0, a: 0 }
210
+ });
211
+ }
212
+
213
+ const result = await client.Page.captureScreenshot(screenshotOptions);
214
+
215
+ // Reset background if it was changed
216
+ if (options.omitBackground) {
217
+ await client.Emulation.setDefaultBackgroundColorOverride();
218
+ }
219
+
220
+ return {
221
+ data: result.data,
222
+ dimensions: this.getImageDimensions(screenshotOptions.clip),
223
+ fileSize: Buffer.from(result.data, 'base64').length
224
+ };
225
+ }
226
+
227
+ /**
228
+ * Capture element screenshot
229
+ */
230
+ async captureElementScreenshot(client, options) {
231
+ await client.DOM.enable();
232
+ await client.Page.enable();
233
+
234
+ // Find the element
235
+ const document = await client.DOM.getDocument();
236
+ const element = await client.DOM.querySelector({
237
+ nodeId: document.root.nodeId,
238
+ selector: options.element
239
+ });
240
+
241
+ if (!element.nodeId) {
242
+ throw new Error(`Element not found with selector: ${options.element}`);
243
+ }
244
+
245
+ // Get element bounds
246
+ const box = await client.DOM.getBoxModel({ nodeId: element.nodeId });
247
+ if (!box.model) {
248
+ throw new Error(`Could not get bounds for element: ${options.element}`);
249
+ }
250
+
251
+ // Use content bounds for the clip
252
+ const bounds = box.model.content;
253
+ const clip = {
254
+ x: Math.round(bounds[0]),
255
+ y: Math.round(bounds[1]),
256
+ width: Math.round(bounds[4] - bounds[0]),
257
+ height: Math.round(bounds[5] - bounds[1]),
258
+ scale: 1
259
+ };
260
+
261
+ const screenshotOptions = {
262
+ format: options.format || 'png',
263
+ quality: options.format !== 'png' ? options.quality : undefined,
264
+ clip: clip,
265
+ optimizeForSpeed: false
266
+ };
267
+
268
+ // Handle transparent background for element
269
+ if (options.omitBackground) {
270
+ await client.Emulation.setDefaultBackgroundColorOverride({
271
+ color: { r: 0, g: 0, b: 0, a: 0 }
272
+ });
273
+ }
274
+
275
+ const result = await client.Page.captureScreenshot(screenshotOptions);
276
+
277
+ if (options.omitBackground) {
278
+ await client.Emulation.setDefaultBackgroundColorOverride();
279
+ }
280
+
281
+ return {
282
+ data: result.data,
283
+ dimensions: { width: clip.width, height: clip.height },
284
+ fileSize: Buffer.from(result.data, 'base64').length
285
+ };
286
+ }
287
+
288
+ /**
289
+ * Save screenshot to disk
290
+ */
291
+ async saveScreenshot(base64Data, fileName) {
292
+ const fs = require('fs').promises;
293
+ const path = require('path');
294
+ const os = require('os');
295
+
296
+ // Use output directory from environment or default to user home directory
297
+ const defaultOutputDir = process.env.HOME
298
+ ? path.join(process.env.HOME, '.mcp-browser-control')
299
+ : path.join(os.tmpdir(), 'mcp-browser-control');
300
+ const outputDir = process.env.OUTPUT_DIR || defaultOutputDir;
301
+ const filePath = path.join(outputDir, fileName);
302
+
303
+ // Ensure directory exists
304
+ await fs.mkdir(outputDir, { recursive: true });
305
+
306
+ // Save file
307
+ const buffer = Buffer.from(base64Data, 'base64');
308
+ await fs.writeFile(filePath, buffer);
309
+
310
+ return filePath;
311
+ }
312
+
313
+ /**
314
+ * Get file extension for format
315
+ */
316
+ getFileExtension(format) {
317
+ const extensions = {
318
+ 'png': 'png',
319
+ 'jpeg': 'jpg',
320
+ 'webp': 'webp'
321
+ };
322
+ return extensions[format] || 'png';
323
+ }
324
+
325
+ /**
326
+ * Get image dimensions from clip or default
327
+ */
328
+ getImageDimensions(clip) {
329
+ if (clip) {
330
+ return {
331
+ width: clip.width,
332
+ height: clip.height
333
+ };
334
+ }
335
+ return null; // Will be determined by actual screenshot
336
+ }
337
+
338
+ /**
339
+ * Capture screenshot with scroll handling
340
+ */
341
+ async captureWithScroll(client, options) {
342
+ // Save current scroll position
343
+ const scrollPosition = await client.Runtime.evaluate({
344
+ expression: '({ x: window.scrollX, y: window.scrollY })'
345
+ });
346
+
347
+ try {
348
+ // Scroll to top for full page capture
349
+ if (options.fullPage) {
350
+ await client.Runtime.evaluate({
351
+ expression: 'window.scrollTo(0, 0)'
352
+ });
353
+ // Wait for scroll to complete
354
+ await new Promise(resolve => setTimeout(resolve, 100));
355
+ }
356
+
357
+ const result = await this.capturePageScreenshot(client, options);
358
+
359
+ return result;
360
+ } finally {
361
+ // Restore original scroll position
362
+ const original = scrollPosition.result.value;
363
+ await client.Runtime.evaluate({
364
+ expression: `window.scrollTo(${original.x}, ${original.y})`
365
+ });
366
+ }
367
+ }
368
+ }
369
+
370
+ module.exports = BrowserScreenshotTool;
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Copyright (C) 2025 Democratize Quality
3
+ *
4
+ * This file is part of Democratize Quality MCP Server.
5
+ *
6
+ * Democratize Quality MCP Server is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU Affero General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Democratize Quality MCP Server is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU Affero General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Affero General Public License
17
+ * along with Democratize Quality MCP Server. If not, see <https://www.gnu.org/licenses/>.
18
+ */
19
+
20
+ const ToolBase = require('../base/ToolBase');
21
+ const browserService = require('../../services/browserService');
22
+
23
+ /**
24
+ * Browser Type Tool
25
+ * Types text into a specific input field in the browser with Playwright-style locators
26
+ */
27
+ class BrowserTypeTool extends ToolBase {
28
+ static definition = {
29
+ name: "browser_type",
30
+ description: "Types text into a specific input field in the browser.",
31
+ input_schema: {
32
+ type: "object",
33
+ properties: {
34
+ browserId: {
35
+ type: "string",
36
+ description: "The ID of the browser instance."
37
+ },
38
+ locatorType: {
39
+ type: "string",
40
+ enum: ["css", "xpath", "text", "role", "label", "placeholder", "testId", "altText"],
41
+ default: "css",
42
+ description: "The type of locator to use"
43
+ },
44
+ locatorValue: {
45
+ type: "string",
46
+ description: "The locator value (CSS selector, XPath, text content, etc.)"
47
+ },
48
+ text: {
49
+ type: "string",
50
+ description: "The text to type into the input field."
51
+ },
52
+ // Keep backward compatibility
53
+ selector: {
54
+ type: "string",
55
+ description: "The CSS selector of the input field (deprecated, use locatorType and locatorValue instead)."
56
+ },
57
+ options: {
58
+ type: "object",
59
+ properties: {
60
+ timeout: {
61
+ type: "number",
62
+ default: 30000,
63
+ description: "Timeout in milliseconds"
64
+ },
65
+ delay: {
66
+ type: "number",
67
+ default: 0,
68
+ description: "Delay between keystrokes in milliseconds"
69
+ },
70
+ clear: {
71
+ type: "boolean",
72
+ default: true,
73
+ description: "Clear the field before typing"
74
+ },
75
+ noWaitAfter: {
76
+ type: "boolean",
77
+ default: false,
78
+ description: "Do not wait for navigation after typing"
79
+ }
80
+ },
81
+ description: "Additional typing options"
82
+ }
83
+ },
84
+ anyOf: [
85
+ { required: ["browserId", "locatorType", "locatorValue", "text"] },
86
+ { required: ["browserId", "selector", "text"] }
87
+ ]
88
+ },
89
+ output_schema: {
90
+ type: "object",
91
+ properties: {
92
+ success: { type: "boolean", description: "Indicates if the typing was successful." },
93
+ locatorType: { type: "string", description: "The locator type that was used." },
94
+ locatorValue: { type: "string", description: "The locator value that was used." },
95
+ text: { type: "string", description: "The text that was typed." },
96
+ browserId: { type: "string", description: "The browser instance ID that was used." },
97
+ elementFound: { type: "boolean", description: "Whether the element was found." },
98
+ message: { type: "string", description: "Success or error message." }
99
+ },
100
+ required: ["success", "browserId"]
101
+ }
102
+ };
103
+
104
+ async execute(parameters) {
105
+ const { browserId, locatorType, locatorValue, selector, text, options = {} } = parameters;
106
+
107
+ // Handle backward compatibility
108
+ let finalLocatorType, finalLocatorValue;
109
+ if (selector) {
110
+ finalLocatorType = "css";
111
+ finalLocatorValue = selector;
112
+ } else {
113
+ finalLocatorType = locatorType || "css";
114
+ finalLocatorValue = locatorValue;
115
+ }
116
+
117
+ console.error(`[BrowserTypeTool] Typing in browser ${browserId} with locator: ${finalLocatorType}="${finalLocatorValue}"`);
118
+
119
+ try {
120
+ // Convert Playwright-style locator to appropriate format for browser service
121
+ const elementSelector = this.convertLocatorToSelector(finalLocatorType, finalLocatorValue);
122
+
123
+ await browserService.typeIntoElement(browserId, elementSelector, text, options);
124
+
125
+ console.error(`[BrowserTypeTool] Successfully typed in browser: ${browserId}`);
126
+
127
+ return {
128
+ success: true,
129
+ browserId: browserId,
130
+ locatorType: finalLocatorType,
131
+ locatorValue: finalLocatorValue,
132
+ text: text,
133
+ elementFound: true,
134
+ message: `Successfully typed "${text}" into element with ${finalLocatorType} locator: ${finalLocatorValue}`
135
+ };
136
+ } catch (error) {
137
+ console.error(`[BrowserTypeTool] Failed to type in element:`, error.message);
138
+
139
+ return {
140
+ success: false,
141
+ browserId: browserId,
142
+ locatorType: finalLocatorType,
143
+ locatorValue: finalLocatorValue,
144
+ text: text,
145
+ elementFound: false,
146
+ message: `Failed to type into element: ${error.message}`
147
+ };
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Convert Playwright-style locator to CSS selector or XPath
153
+ */
154
+ convertLocatorToSelector(locatorType, locatorValue) {
155
+ switch (locatorType) {
156
+ case "css":
157
+ return locatorValue;
158
+
159
+ case "xpath":
160
+ return locatorValue;
161
+
162
+ case "text":
163
+ // Convert text locator to XPath for input elements
164
+ return `//input[contains(@placeholder, "${locatorValue}")] | //input[contains(@value, "${locatorValue}")] | //textarea[contains(text(), "${locatorValue}")] | //label[contains(text(), "${locatorValue}")]/following-sibling::input | //label[contains(text(), "${locatorValue}")]/following::input[1]`;
165
+
166
+ case "role":
167
+ // Convert role locator to CSS attribute selector
168
+ return `[role="${locatorValue}"]`;
169
+
170
+ case "label":
171
+ // Convert label locator to XPath for label association
172
+ return `//input[@aria-label="${locatorValue}"] | //input[@id=//label[contains(text(), "${locatorValue}")]/@for] | //label[contains(text(), "${locatorValue}")]/following-sibling::input | //label[contains(text(), "${locatorValue}")]/following::input[1]`;
173
+
174
+ case "placeholder":
175
+ // Convert placeholder locator to CSS attribute selector
176
+ return `[placeholder="${locatorValue}"]`;
177
+
178
+ case "testId":
179
+ // Convert test ID to CSS attribute selector (assuming data-testid)
180
+ return `[data-testid="${locatorValue}"]`;
181
+
182
+ case "altText":
183
+ // Convert alt text to CSS attribute selector (less common for input fields)
184
+ return `[alt="${locatorValue}"]`;
185
+
186
+ default:
187
+ // Default to CSS selector
188
+ return locatorValue;
189
+ }
190
+ }
191
+ }
192
+
193
+ module.exports = BrowserTypeTool;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Copyright (C) 2025 Democratize Quality
3
+ *
4
+ * This file is part of Democratize Quality MCP Server.
5
+ *
6
+ * Democratize Quality MCP Server is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU Affero General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * Democratize Quality MCP Server is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU Affero General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Affero General Public License
17
+ * along with Democratize Quality MCP Server. If not, see <https://www.gnu.org/licenses/>.
18
+ */
19
+
20
+ const ToolRegistry = require('./base/ToolRegistry');
21
+ const path = require('path');
22
+
23
+ /**
24
+ * Initialize and configure the tool registry
25
+ * This file serves as the main entry point for the tools system
26
+ */
27
+
28
+ // Create the global tool registry instance
29
+ const toolRegistry = new ToolRegistry();
30
+
31
+ /**
32
+ * Initialize the tool registry by discovering and loading all tools
33
+ * @param {boolean} debugMode - Whether to enable debug logging
34
+ * @returns {Promise<ToolRegistry>} - The initialized tool registry
35
+ */
36
+ async function initializeTools(debugMode = false) {
37
+ if (debugMode) {
38
+ console.error('[Tools] Initializing tool system...');
39
+ }
40
+
41
+ try {
42
+ // Get the tools directory path
43
+ const toolsDir = path.join(__dirname);
44
+
45
+ // Discover and load all tools
46
+ await toolRegistry.discoverTools(toolsDir, debugMode);
47
+
48
+ // Log registry statistics
49
+ const stats = toolRegistry.getStats();
50
+ console.error(`[Tools] Tool system initialized successfully:`);
51
+ console.error(`[Tools] - Total tools: ${stats.total_tools}`);
52
+ if (debugMode) {
53
+ console.error(`[Tools] - Available tools: ${stats.tool_names.join(', ')}`);
54
+ }
55
+
56
+ return toolRegistry;
57
+
58
+ } catch (error) {
59
+ console.error('[Tools] Failed to initialize tool system:', error.message);
60
+ throw error;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Get the tool registry instance
66
+ * @returns {ToolRegistry} - The tool registry instance
67
+ */
68
+ function getToolRegistry() {
69
+ return toolRegistry;
70
+ }
71
+
72
+ /**
73
+ * Get all tool definitions for MCP tools/list response
74
+ * @returns {Array} - Array of tool definitions
75
+ */
76
+ function getToolDefinitions() {
77
+ return toolRegistry.getDefinitions();
78
+ }
79
+
80
+ /**
81
+ * Execute a tool by name
82
+ * @param {string} toolName - The name of the tool to execute
83
+ * @param {object} parameters - The parameters to pass to the tool
84
+ * @returns {Promise<object>} - The tool execution result
85
+ */
86
+ async function executeTool(toolName, parameters) {
87
+ return await toolRegistry.executeTool(toolName, parameters);
88
+ }
89
+
90
+ /**
91
+ * Check if a tool is available
92
+ * @param {string} toolName - The name of the tool to check
93
+ * @returns {boolean} - True if the tool is available
94
+ */
95
+ function isToolAvailable(toolName) {
96
+ return toolRegistry.hasTool(toolName);
97
+ }
98
+
99
+ /**
100
+ * Get list of available tool names
101
+ * @returns {Array<string>} - Array of available tool names
102
+ */
103
+ function getAvailableTools() {
104
+ return toolRegistry.getToolNames();
105
+ }
106
+
107
+ module.exports = {
108
+ initializeTools,
109
+ getToolRegistry,
110
+ getToolDefinitions,
111
+ executeTool,
112
+ isToolAvailable,
113
+ getAvailableTools
114
+ };