@democratize-quality/mcp-server 1.1.9 ā 1.2.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/dist/server.d.ts +41 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +225 -0
- package/dist/server.js.map +1 -0
- package/package.json +23 -24
- package/browserControl.js +0 -113
- package/cli.js +0 -228
- package/mcpServer.js +0 -335
- package/run-server.js +0 -140
- package/src/chatmodes//360/237/214/220 api-generator.chatmode.md" +0 -409
- package/src/chatmodes//360/237/214/220 api-healer.chatmode.md" +0 -494
- package/src/chatmodes//360/237/214/220 api-planner.chatmode.md" +0 -954
- package/src/config/environments/api-only.js +0 -53
- package/src/config/environments/development.js +0 -54
- package/src/config/environments/production.js +0 -69
- package/src/config/index.js +0 -341
- package/src/config/server.js +0 -41
- package/src/config/tools/api.js +0 -67
- package/src/config/tools/browser.js +0 -90
- package/src/config/tools/default.js +0 -32
- package/src/docs/Agent_README.md +0 -310
- package/src/docs/QUICK_REFERENCE.md +0 -111
- package/src/services/browserService.js +0 -325
- package/src/skills/api-planning/SKILL.md +0 -224
- package/src/skills/test-execution/SKILL.md +0 -777
- package/src/skills/test-generation/SKILL.md +0 -309
- package/src/skills/test-healing/SKILL.md +0 -405
- package/src/tools/api/api-generator.js +0 -1865
- package/src/tools/api/api-healer.js +0 -617
- package/src/tools/api/api-planner.js +0 -2598
- package/src/tools/api/api-project-setup.js +0 -313
- package/src/tools/api/api-request.js +0 -641
- package/src/tools/api/api-session-report.js +0 -1278
- package/src/tools/api/api-session-status.js +0 -395
- package/src/tools/api/prompts/README.md +0 -293
- package/src/tools/api/prompts/generation-prompts.js +0 -703
- package/src/tools/api/prompts/healing-prompts.js +0 -195
- package/src/tools/api/prompts/index.js +0 -25
- package/src/tools/api/prompts/orchestrator.js +0 -334
- package/src/tools/api/prompts/validation-rules.js +0 -339
- package/src/tools/base/ToolBase.js +0 -230
- package/src/tools/base/ToolRegistry.js +0 -269
- package/src/tools/browser/advanced/browser-console.js +0 -384
- package/src/tools/browser/advanced/browser-dialog.js +0 -319
- package/src/tools/browser/advanced/browser-evaluate.js +0 -337
- package/src/tools/browser/advanced/browser-file.js +0 -480
- package/src/tools/browser/advanced/browser-keyboard.js +0 -343
- package/src/tools/browser/advanced/browser-mouse.js +0 -332
- package/src/tools/browser/advanced/browser-network.js +0 -421
- package/src/tools/browser/advanced/browser-pdf.js +0 -407
- package/src/tools/browser/advanced/browser-tabs.js +0 -497
- package/src/tools/browser/advanced/browser-wait.js +0 -378
- package/src/tools/browser/click.js +0 -168
- package/src/tools/browser/close.js +0 -60
- package/src/tools/browser/dom.js +0 -70
- package/src/tools/browser/launch.js +0 -67
- package/src/tools/browser/navigate.js +0 -270
- package/src/tools/browser/screenshot.js +0 -351
- package/src/tools/browser/type.js +0 -174
- package/src/tools/index.js +0 -95
- package/src/utils/agentInstaller.js +0 -418
- package/src/utils/browserHelpers.js +0 -83
package/cli.js
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Democratize Quality MCP Server CLI
|
|
5
|
-
* Can be run via npx @democratize-quality/mcp-server
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { spawn } = require('child_process');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const os = require('os');
|
|
12
|
-
|
|
13
|
-
// Handle CLI arguments
|
|
14
|
-
const args = process.argv.slice(2);
|
|
15
|
-
const isHelp = args.includes('--help') || args.includes('-h');
|
|
16
|
-
const isVersion = args.includes('--version') || args.includes('-v');
|
|
17
|
-
const isAgents = args.includes('--agents');
|
|
18
|
-
|
|
19
|
-
if (isVersion) {
|
|
20
|
-
const packageJson = require('./package.json');
|
|
21
|
-
console.log(`Democratize Quality MCP Server v${packageJson.version}`);
|
|
22
|
-
process.exit(0);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Handle agents installation
|
|
26
|
-
if (isAgents) {
|
|
27
|
-
const AgentInstaller = require('./src/utils/agentInstaller');
|
|
28
|
-
const isVerbose = args.includes('--verbose') || args.includes('--debug');
|
|
29
|
-
const isRollback = args.includes('--rollback');
|
|
30
|
-
|
|
31
|
-
(async () => {
|
|
32
|
-
try {
|
|
33
|
-
const installer = new AgentInstaller({ verbose: isVerbose });
|
|
34
|
-
|
|
35
|
-
if (isRollback) {
|
|
36
|
-
await installer.rollback();
|
|
37
|
-
} else {
|
|
38
|
-
await installer.install();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
process.exit(0);
|
|
42
|
-
} catch (error) {
|
|
43
|
-
console.error('Installation failed:', error.message);
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
})();
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (isVersion) {
|
|
51
|
-
const packageJson = require('./package.json');
|
|
52
|
-
console.log(`Democratize Quality MCP Server v${packageJson.version}`);
|
|
53
|
-
process.exit(0);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (isHelp) {
|
|
57
|
-
console.log(`
|
|
58
|
-
šÆ Democratize Quality MCP Server
|
|
59
|
-
|
|
60
|
-
A comprehensive MCP server for democratizing quality through browser automation and API testing.
|
|
61
|
-
|
|
62
|
-
Usage:
|
|
63
|
-
npx @democratize-quality/mcp-server [options]
|
|
64
|
-
democratize-quality-mcp [options]
|
|
65
|
-
dq-mcp-server [options]
|
|
66
|
-
|
|
67
|
-
Options:
|
|
68
|
-
--help, -h Show this help
|
|
69
|
-
--version, -v Show version
|
|
70
|
-
--agents Install GitHub Copilot Chat agents and VS Code MCP configuration
|
|
71
|
-
--agents --rollback Rollback agents installation (future feature)
|
|
72
|
-
--debug Enable debug mode
|
|
73
|
-
--verbose Enable verbose output (useful with --agents)
|
|
74
|
-
--port <number> Set server port
|
|
75
|
-
--env <environment> Set environment (development|production|api-only)
|
|
76
|
-
|
|
77
|
-
Agent Installation:
|
|
78
|
-
--agents Installs API testing agents for GitHub Copilot Chat:
|
|
79
|
-
⢠Copies chatmode files to .github/chatmodes/
|
|
80
|
-
⢠Sets up MCP configuration in .vscode/mcp.json
|
|
81
|
-
⢠Enables @š api-planner, @š api-generator, @š api-healer agents
|
|
82
|
-
|
|
83
|
-
Tool Category Options:
|
|
84
|
-
--api-only Enable only API tools (shortcut for api-only environment)
|
|
85
|
-
--browser-only Enable only browser tools
|
|
86
|
-
--no-api Disable API tools
|
|
87
|
-
--no-browser Disable browser tools
|
|
88
|
-
--no-advanced Disable advanced browser tools
|
|
89
|
-
--enable-all Enable all tool categories (default in development)
|
|
90
|
-
|
|
91
|
-
Environment Variables:
|
|
92
|
-
MCP_FEATURES_ENABLEAPITOOLS=true/false Enable/disable API tools
|
|
93
|
-
MCP_FEATURES_ENABLEBROWSERTOOLS=true/false Enable/disable browser tools
|
|
94
|
-
MCP_FEATURES_ENABLEADVANCEDTOOLS=true/false Enable/disable advanced tools
|
|
95
|
-
NODE_ENV=api-only Use API-only configuration
|
|
96
|
-
|
|
97
|
-
Integration with Claude Desktop:
|
|
98
|
-
Add this to ~/Library/Application Support/Claude/claude_desktop_config.json
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
"mcpServers": {
|
|
102
|
-
"democratize-quality": {
|
|
103
|
-
"command": "npx",
|
|
104
|
-
"args": ["@democratize-quality/mcp-server"]
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
Or if installed globally:
|
|
110
|
-
{
|
|
111
|
-
"mcpServers": {
|
|
112
|
-
"democratize-quality": {
|
|
113
|
-
"command": "democratize-quality-mcp"
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
Available Tools: 20
|
|
119
|
-
⢠Browser Automation (17): launch, navigate, click, type, screenshot, pdf, etc.
|
|
120
|
-
⢠API Testing (3): request, session status, HTML reports
|
|
121
|
-
|
|
122
|
-
GitHub: https://github.com/democratize-quality/mcp-server
|
|
123
|
-
`);
|
|
124
|
-
process.exit(0);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Set up environment
|
|
128
|
-
const env = { ...process.env };
|
|
129
|
-
|
|
130
|
-
// Handle debug flag
|
|
131
|
-
if (args.includes('--debug')) {
|
|
132
|
-
env.MCP_FEATURES_ENABLEDEBUGMODE = 'true';
|
|
133
|
-
env.NODE_ENV = 'development';
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Handle environment flag
|
|
137
|
-
const envIndex = args.indexOf('--env');
|
|
138
|
-
if (envIndex !== -1 && args[envIndex + 1]) {
|
|
139
|
-
env.NODE_ENV = args[envIndex + 1];
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Handle tool category flags
|
|
143
|
-
if (args.includes('--api-only')) {
|
|
144
|
-
env.NODE_ENV = 'api-only';
|
|
145
|
-
} else if (args.includes('--browser-only')) {
|
|
146
|
-
env.MCP_FEATURES_ENABLEAPITOOLS = 'false';
|
|
147
|
-
env.MCP_FEATURES_ENABLEBROWSERTOOLS = 'true';
|
|
148
|
-
env.MCP_FEATURES_ENABLEADVANCEDTOOLS = 'true';
|
|
149
|
-
env.MCP_FEATURES_ENABLEFILETOOLS = 'false';
|
|
150
|
-
env.MCP_FEATURES_ENABLENETWORKTOOLS = 'false';
|
|
151
|
-
env.MCP_FEATURES_ENABLEOTHERTOOLS = 'false';
|
|
152
|
-
} else if (args.includes('--enable-all')) {
|
|
153
|
-
env.MCP_FEATURES_ENABLEAPITOOLS = 'true';
|
|
154
|
-
env.MCP_FEATURES_ENABLEBROWSERTOOLS = 'true';
|
|
155
|
-
env.MCP_FEATURES_ENABLEADVANCEDTOOLS = 'true';
|
|
156
|
-
env.MCP_FEATURES_ENABLEFILETOOLS = 'true';
|
|
157
|
-
env.MCP_FEATURES_ENABLENETWORKTOOLS = 'true';
|
|
158
|
-
env.MCP_FEATURES_ENABLEOTHERTOOLS = 'true';
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Handle individual tool category disable flags
|
|
162
|
-
if (args.includes('--no-api')) {
|
|
163
|
-
env.MCP_FEATURES_ENABLEAPITOOLS = 'false';
|
|
164
|
-
}
|
|
165
|
-
if (args.includes('--no-browser')) {
|
|
166
|
-
env.MCP_FEATURES_ENABLEBROWSERTOOLS = 'false';
|
|
167
|
-
}
|
|
168
|
-
if (args.includes('--no-advanced')) {
|
|
169
|
-
env.MCP_FEATURES_ENABLEADVANCEDTOOLS = 'false';
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Handle port flag
|
|
173
|
-
const portIndex = args.indexOf('--port');
|
|
174
|
-
if (portIndex !== -1 && args[portIndex + 1]) {
|
|
175
|
-
env.PORT = args[portIndex + 1];
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Ensure output directory exists
|
|
179
|
-
// When run via npx/Claude, process.cwd() might be root, so use home directory or temp
|
|
180
|
-
const defaultOutputDir = env.HOME
|
|
181
|
-
? path.join(env.HOME, '.mcp-browser-control')
|
|
182
|
-
: path.join(os.tmpdir(), 'mcp-browser-control');
|
|
183
|
-
|
|
184
|
-
const outputDir = env.OUTPUT_DIR || defaultOutputDir;
|
|
185
|
-
if (!fs.existsSync(outputDir)) {
|
|
186
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
187
|
-
}
|
|
188
|
-
env.OUTPUT_DIR = outputDir;
|
|
189
|
-
|
|
190
|
-
// Debug output (if enabled)
|
|
191
|
-
if (args.includes('--debug')) {
|
|
192
|
-
console.error(`š Output directory: ${outputDir}`);
|
|
193
|
-
console.error(`š Working directory: ${process.cwd()}`);
|
|
194
|
-
console.error(`š Environment: ${env.NODE_ENV || 'development'}`);
|
|
195
|
-
console.error(`š§ Tool Categories:`);
|
|
196
|
-
console.error(` API Tools: ${env.MCP_FEATURES_ENABLEAPITOOLS || 'default'}`);
|
|
197
|
-
console.error(` Browser Tools: ${env.MCP_FEATURES_ENABLEBROWSERTOOLS || 'default'}`);
|
|
198
|
-
console.error(` Advanced Tools: ${env.MCP_FEATURES_ENABLEADVANCEDTOOLS || 'default'}`);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Start the MCP server
|
|
202
|
-
const serverPath = path.join(__dirname, 'mcpServer.js');
|
|
203
|
-
const serverProcess = spawn('node', [serverPath], {
|
|
204
|
-
env,
|
|
205
|
-
stdio: 'inherit'
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// Handle process cleanup
|
|
209
|
-
const cleanup = (signal) => {
|
|
210
|
-
console.error(`\nReceived ${signal}, shutting down gracefully...`);
|
|
211
|
-
serverProcess.kill(signal);
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
process.on('SIGINT', () => cleanup('SIGINT'));
|
|
215
|
-
process.on('SIGTERM', () => cleanup('SIGTERM'));
|
|
216
|
-
|
|
217
|
-
serverProcess.on('error', (error) => {
|
|
218
|
-
console.error('Failed to start CDP Browser Control MCP Server:', error.message);
|
|
219
|
-
process.exit(1);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
serverProcess.on('exit', (code, signal) => {
|
|
223
|
-
if (signal) {
|
|
224
|
-
process.exit(0);
|
|
225
|
-
} else {
|
|
226
|
-
process.exit(code || 0);
|
|
227
|
-
}
|
|
228
|
-
});
|
package/mcpServer.js
DELETED
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// mcpServer.js - Democratize Quality MCP Server entry point
|
|
3
|
-
//
|
|
4
|
-
// Debug/Logging Modes:
|
|
5
|
-
// - Production mode (default): NODE_ENV=production or npm start - Minimal logging
|
|
6
|
-
// - Debug mode: MCP_FEATURES_ENABLEDEBUGMODE=true or npm run dev - Detailed logging
|
|
7
|
-
// - Development mode: NODE_ENV=development - Detailed logging (same as debug)
|
|
8
|
-
//
|
|
9
|
-
// The server automatically detects the mode and adjusts logging verbosity accordingly.
|
|
10
|
-
|
|
11
|
-
const { JSONRPCServer } = require("json-rpc-2.0");
|
|
12
|
-
const browserService = require('./src/services/browserService'); // Keep for shutdown functionality
|
|
13
|
-
const { initializeTools, getToolDefinitions, executeTool } = require('./src/tools');
|
|
14
|
-
const config = require('./src/config');
|
|
15
|
-
|
|
16
|
-
// Initialize JSON-RPC server
|
|
17
|
-
const server = new JSONRPCServer();
|
|
18
|
-
|
|
19
|
-
// Check if debug mode is requested via environment variable first
|
|
20
|
-
const debugFromEnv = process.env.MCP_FEATURES_ENABLEDEBUGMODE === 'true' || process.env.NODE_ENV === 'development';
|
|
21
|
-
const isDebugMode = config.get('features.enableDebugMode', false) || debugFromEnv;
|
|
22
|
-
|
|
23
|
-
// Set quiet mode if not in debug
|
|
24
|
-
config.setQuiet(!isDebugMode);
|
|
25
|
-
|
|
26
|
-
// Global variable to hold tool definitions after initialization
|
|
27
|
-
let toolDefinitions = [];
|
|
28
|
-
|
|
29
|
-
// Helper function for debug logging
|
|
30
|
-
function debugLog(...args) {
|
|
31
|
-
if (isDebugMode) {
|
|
32
|
-
console.error('[Democratize Quality MCP]', ...args);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Helper function for important logs (always shown)
|
|
37
|
-
function log(...args) {
|
|
38
|
-
console.error('[Democratize Quality MCP]', ...args);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Initialize the tool system
|
|
42
|
-
async function initializeServer() {
|
|
43
|
-
try {
|
|
44
|
-
if (isDebugMode) {
|
|
45
|
-
log('Initializing tool system...');
|
|
46
|
-
}
|
|
47
|
-
await initializeTools(isDebugMode);
|
|
48
|
-
toolDefinitions = getToolDefinitions();
|
|
49
|
-
log(`Tool system initialized with ${toolDefinitions.length} tools`);
|
|
50
|
-
} catch (error) {
|
|
51
|
-
log('Failed to initialize tool system:', error.message);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// --- Register MCP Standard Methods ---
|
|
57
|
-
|
|
58
|
-
// Initialize method for MCP protocol
|
|
59
|
-
server.addMethod("initialize", async (params) => {
|
|
60
|
-
debugLog("Received 'initialize' request.");
|
|
61
|
-
return {
|
|
62
|
-
protocolVersion: "2024-11-05",
|
|
63
|
-
capabilities: {
|
|
64
|
-
tools: {},
|
|
65
|
-
prompts: {},
|
|
66
|
-
resources: {
|
|
67
|
-
subscribe: false,
|
|
68
|
-
listChanged: false
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
serverInfo: {
|
|
72
|
-
name: "democratize-quality-mcp-server",
|
|
73
|
-
version: "1.1.6"
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// The `tools/list` method for tool discovery
|
|
79
|
-
// Replace your tools/list method with this Draft 7 compatible version:
|
|
80
|
-
|
|
81
|
-
server.addMethod("tools/list", async () => {
|
|
82
|
-
debugLog("Received 'tools/list' request.");
|
|
83
|
-
|
|
84
|
-
// Convert all tool definitions to Claude Desktop compatible format
|
|
85
|
-
const compatibleTools = toolDefinitions.map(tool => {
|
|
86
|
-
// Ensure we use the correct property name and clean schema
|
|
87
|
-
return {
|
|
88
|
-
name: tool.name,
|
|
89
|
-
description: tool.description,
|
|
90
|
-
// Claude Desktop expects 'inputSchema', not 'input_schema'
|
|
91
|
-
inputSchema: {
|
|
92
|
-
type: "object",
|
|
93
|
-
properties: {
|
|
94
|
-
// Add minimal properties to avoid empty schema issues
|
|
95
|
-
...((tool.input_schema && tool.input_schema.properties) || {}),
|
|
96
|
-
// Fallback to ensure there's always at least one property
|
|
97
|
-
...(Object.keys((tool.input_schema && tool.input_schema.properties) || {}).length === 0 ? {
|
|
98
|
-
_placeholder: { type: "string", description: "Placeholder parameter" }
|
|
99
|
-
} : {})
|
|
100
|
-
},
|
|
101
|
-
// Only add required if it exists and is not empty
|
|
102
|
-
...(tool.input_schema && tool.input_schema.required && tool.input_schema.required.length > 0 ? {
|
|
103
|
-
required: tool.input_schema.required
|
|
104
|
-
} : {}),
|
|
105
|
-
// Ensure no additionalProperties or other Draft 2020-12 features
|
|
106
|
-
additionalProperties: false
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
debugLog(`Returning ${compatibleTools.length} tools with compatible schemas`);
|
|
112
|
-
debugLog('First tool schema sample:', JSON.stringify(compatibleTools[0]?.inputSchema, null, 2));
|
|
113
|
-
|
|
114
|
-
return { tools: compatibleTools };
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// The `tools/call` method for tool invocation (note: it's tools/call, not tool/call)
|
|
118
|
-
server.addMethod("tools/call", async ({ name, arguments: parameters }) => {
|
|
119
|
-
debugLog(`Received 'tools/call' for method: ${name} with params: ${JSON.stringify(parameters)}`);
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
// Use the new tool system to execute the tool
|
|
123
|
-
const result = await executeTool(name, parameters);
|
|
124
|
-
return result;
|
|
125
|
-
|
|
126
|
-
} catch (error) {
|
|
127
|
-
log(`Error executing tool '${name}':`, error.message);
|
|
128
|
-
|
|
129
|
-
// If it's already a properly formatted MCP error, re-throw it
|
|
130
|
-
if (error.code && error.message) {
|
|
131
|
-
throw error;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Otherwise, format it as an MCP error
|
|
135
|
-
throw {
|
|
136
|
-
code: -32000,
|
|
137
|
-
message: `Tool execution failed: ${error.message}`,
|
|
138
|
-
data: { tool_name: name, original_error: error.message }
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// The `prompts/list` method for prompt discovery
|
|
144
|
-
server.addMethod("prompts/list", async () => {
|
|
145
|
-
debugLog("Received 'prompts/list' request.");
|
|
146
|
-
// This server doesn't provide any prompts, so return an empty array
|
|
147
|
-
return { prompts: [] };
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// The `resources/list` method for resource discovery
|
|
151
|
-
server.addMethod("resources/list", async () => {
|
|
152
|
-
debugLog("Received 'resources/list' request.");
|
|
153
|
-
|
|
154
|
-
// Expose tools as resources so they can be inspected via tool: URIs
|
|
155
|
-
// This is needed for Claude Code's resource-based tool inspection
|
|
156
|
-
const toolResources = toolDefinitions.map(tool => ({
|
|
157
|
-
uri: `tool:${tool.name}`,
|
|
158
|
-
name: tool.name,
|
|
159
|
-
description: tool.description,
|
|
160
|
-
mimeType: "application/json"
|
|
161
|
-
}));
|
|
162
|
-
|
|
163
|
-
debugLog(`Returning ${toolResources.length} tool resources`);
|
|
164
|
-
return { resources: toolResources };
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// The `resources/read` method for reading resource content
|
|
168
|
-
server.addMethod("resources/read", async ({ uri }) => {
|
|
169
|
-
debugLog(`Received 'resources/read' request for URI: ${uri}`);
|
|
170
|
-
|
|
171
|
-
// Handle tool: URIs (e.g., tool:api_planner)
|
|
172
|
-
if (uri.startsWith('tool:')) {
|
|
173
|
-
const toolName = uri.substring(5); // Remove 'tool:' prefix
|
|
174
|
-
const tool = toolDefinitions.find(t => t.name === toolName);
|
|
175
|
-
|
|
176
|
-
if (!tool) {
|
|
177
|
-
throw {
|
|
178
|
-
code: -32602,
|
|
179
|
-
message: `Tool resource not found: ${toolName}`,
|
|
180
|
-
data: { uri }
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Return the tool definition as a resource
|
|
185
|
-
const toolInfo = {
|
|
186
|
-
name: tool.name,
|
|
187
|
-
description: tool.description,
|
|
188
|
-
inputSchema: tool.input_schema || tool.inputSchema
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
debugLog(`Returning tool resource for: ${toolName}`);
|
|
192
|
-
return {
|
|
193
|
-
contents: [{
|
|
194
|
-
uri: uri,
|
|
195
|
-
mimeType: "application/json",
|
|
196
|
-
text: JSON.stringify(toolInfo, null, 2)
|
|
197
|
-
}]
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Unknown URI scheme
|
|
202
|
-
throw {
|
|
203
|
-
code: -32602,
|
|
204
|
-
message: `Unsupported resource URI scheme: ${uri}`,
|
|
205
|
-
data: { uri }
|
|
206
|
-
};
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// Notification methods (these don't return responses)
|
|
210
|
-
server.addMethod("notifications/initialized", async () => {
|
|
211
|
-
debugLog("Received 'notifications/initialized' notification.");
|
|
212
|
-
// Notifications don't return responses
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
server.addMethod("notifications/cancelled", async ({ requestId, reason }) => {
|
|
216
|
-
debugLog(`Received 'notifications/cancelled' for request ${requestId}: ${reason}`);
|
|
217
|
-
// Notifications don't return responses
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// Add a catch-all method handler for debugging
|
|
221
|
-
server.addMethod("*", async (params, method) => {
|
|
222
|
-
debugLog(`Unknown method called: ${method}`);
|
|
223
|
-
throw {
|
|
224
|
-
code: -32601,
|
|
225
|
-
message: `Method '${method}' not found`
|
|
226
|
-
};
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
// --- STDIO Communication Loop ---
|
|
230
|
-
// This part handles reading JSON-RPC requests from stdin and writing responses to stdout.
|
|
231
|
-
|
|
232
|
-
let inputBuffer = '';
|
|
233
|
-
|
|
234
|
-
process.stdin.on('data', (chunk) => {
|
|
235
|
-
inputBuffer += chunk.toString();
|
|
236
|
-
|
|
237
|
-
// Process messages delimited by newline. This is a common pattern for STDIO RPC.
|
|
238
|
-
// In a production-grade server, you'd want a more robust JSON stream parser
|
|
239
|
-
// to handle partial messages or multiple messages in one chunk.
|
|
240
|
-
let newlineIndex;
|
|
241
|
-
while ((newlineIndex = inputBuffer.indexOf('\n')) !== -1) {
|
|
242
|
-
const messageString = inputBuffer.substring(0, newlineIndex).trim();
|
|
243
|
-
inputBuffer = inputBuffer.substring(newlineIndex + 1);
|
|
244
|
-
|
|
245
|
-
if (messageString) { // Ensure it's not an empty line
|
|
246
|
-
try {
|
|
247
|
-
const jsonRpcRequest = JSON.parse(messageString);
|
|
248
|
-
debugLog(`Received request: ${JSON.stringify(jsonRpcRequest)}`);
|
|
249
|
-
|
|
250
|
-
// Handle notifications (no response expected)
|
|
251
|
-
if (!jsonRpcRequest.id && jsonRpcRequest.method && jsonRpcRequest.method.startsWith('notifications/')) {
|
|
252
|
-
server.receive(jsonRpcRequest).catch(err => {
|
|
253
|
-
log("Error processing notification:", err.message);
|
|
254
|
-
});
|
|
255
|
-
return; // Don't send a response for notifications
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// The receive method handles processing the request and generating a response
|
|
259
|
-
server.receive(jsonRpcRequest).then((jsonRpcResponse) => {
|
|
260
|
-
if (jsonRpcResponse) {
|
|
261
|
-
debugLog(`Sending response: ${JSON.stringify(jsonRpcResponse)}`);
|
|
262
|
-
// All responses must go to stdout
|
|
263
|
-
process.stdout.write(JSON.stringify(jsonRpcResponse) + '\n');
|
|
264
|
-
}
|
|
265
|
-
}).catch(err => {
|
|
266
|
-
// Catch errors from receive() if it rejects (e.g., malformed JSON-RPC request)
|
|
267
|
-
log("Error processing JSON-RPC request:", err.message);
|
|
268
|
-
|
|
269
|
-
// Send an error response if we have an ID
|
|
270
|
-
if (jsonRpcRequest.id) {
|
|
271
|
-
const errorResponse = {
|
|
272
|
-
jsonrpc: "2.0",
|
|
273
|
-
error: {
|
|
274
|
-
code: -32603,
|
|
275
|
-
message: "Internal error",
|
|
276
|
-
data: err.message
|
|
277
|
-
},
|
|
278
|
-
id: jsonRpcRequest.id
|
|
279
|
-
};
|
|
280
|
-
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
} catch (parseError) {
|
|
284
|
-
log("JSON parse error on input:", messageString, parseError);
|
|
285
|
-
// If the input itself is not valid JSON, we can't get an ID, so ID is null
|
|
286
|
-
const errorResponse = {
|
|
287
|
-
jsonrpc: "2.0",
|
|
288
|
-
error: {
|
|
289
|
-
code: -32700, // Parse error
|
|
290
|
-
message: "Parse error"
|
|
291
|
-
},
|
|
292
|
-
id: null
|
|
293
|
-
};
|
|
294
|
-
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
// Handle graceful shutdown signals (Ctrl+C, termination)
|
|
301
|
-
process.on('SIGINT', async () => {
|
|
302
|
-
log('\nSIGINT received. Shutting down...');
|
|
303
|
-
try {
|
|
304
|
-
await browserService.shutdownAllBrowsers();
|
|
305
|
-
log('All browser instances closed. Exiting gracefully.');
|
|
306
|
-
} catch (err) {
|
|
307
|
-
log('Error during graceful shutdown:', err.message);
|
|
308
|
-
process.exit(1); // Exit with error code
|
|
309
|
-
}
|
|
310
|
-
process.exit(0); // Exit successfully
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
process.on('SIGTERM', async () => {
|
|
314
|
-
log('\nSIGTERM received. Shutting down...');
|
|
315
|
-
try {
|
|
316
|
-
await browserService.shutdownAllBrowsers();
|
|
317
|
-
log('All browser instances closed. Exiting gracefully.');
|
|
318
|
-
} catch (err) {
|
|
319
|
-
log('Error during graceful shutdown:', err.message);
|
|
320
|
-
process.exit(1);
|
|
321
|
-
}
|
|
322
|
-
process.exit(0);
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
// Initialize the server and start listening
|
|
326
|
-
(async () => {
|
|
327
|
-
await initializeServer();
|
|
328
|
-
|
|
329
|
-
// Initial message to indicate server is ready (to stderr)
|
|
330
|
-
log(`Server started. Waiting for input on stdin.`);
|
|
331
|
-
if (isDebugMode) {
|
|
332
|
-
log(`To integrate with a host, provide the command: node ${__filename}`);
|
|
333
|
-
log(`Debug mode enabled - showing detailed logs`);
|
|
334
|
-
}
|
|
335
|
-
})();
|
package/run-server.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Democratize Quality MCP Server Startup Script
|
|
5
|
-
* Provides easy configuration and startup options
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { spawn } = require('child_process');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
|
|
11
|
-
// Parse command line arguments
|
|
12
|
-
const args = process.argv.slice(2);
|
|
13
|
-
const options = {
|
|
14
|
-
debug: args.includes('--debug') || args.includes('-d'),
|
|
15
|
-
production: args.includes('--production') || args.includes('-p'),
|
|
16
|
-
help: args.includes('--help') || args.includes('-h')
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
if (options.help) {
|
|
20
|
-
console.log(`
|
|
21
|
-
šÆ Democratize Quality MCP Server
|
|
22
|
-
|
|
23
|
-
Usage: npm run server [options]
|
|
24
|
-
or: node run-server.js [options]
|
|
25
|
-
|
|
26
|
-
Options:
|
|
27
|
-
--debug, -d Enable debug mode with verbose logging
|
|
28
|
-
--production, -p Run in production mode
|
|
29
|
-
--help, -h Show this help message
|
|
30
|
-
|
|
31
|
-
Environment Variables:
|
|
32
|
-
NODE_ENV Set environment (development/production)
|
|
33
|
-
OUTPUT_DIR Directory for screenshots, PDFs, reports
|
|
34
|
-
PORT Server port (default: 3000)
|
|
35
|
-
|
|
36
|
-
Integration Examples:
|
|
37
|
-
|
|
38
|
-
1. Claude Desktop (add to claude_desktop_config.json):
|
|
39
|
-
{
|
|
40
|
-
"mcpServers": {
|
|
41
|
-
"democratize-quality": {
|
|
42
|
-
"command": "node",
|
|
43
|
-
"args": ["${path.join(__dirname, 'mcpServer.js')}"]
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
2. MCP Inspector (for testing):
|
|
49
|
-
npx @modelcontextprotocol/inspector node mcpServer.js
|
|
50
|
-
|
|
51
|
-
3. Direct STDIO communication:
|
|
52
|
-
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node mcpServer.js
|
|
53
|
-
|
|
54
|
-
Available Tools: 20 total
|
|
55
|
-
- Browser Tools (17): automation, interaction, content capture
|
|
56
|
-
- API Tools (3): HTTP testing, session management, reporting
|
|
57
|
-
|
|
58
|
-
Repository: https://github.com/democratize-quality/mcp-server
|
|
59
|
-
`);
|
|
60
|
-
process.exit(0);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Set environment variables
|
|
64
|
-
const env = { ...process.env };
|
|
65
|
-
|
|
66
|
-
if (options.debug) {
|
|
67
|
-
env.MCP_FEATURES_ENABLEDEBUGMODE = 'true';
|
|
68
|
-
env.NODE_ENV = 'development';
|
|
69
|
-
console.log('š Debug mode enabled');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (options.production) {
|
|
73
|
-
env.NODE_ENV = 'production';
|
|
74
|
-
console.log('š Production mode enabled');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (!env.OUTPUT_DIR) {
|
|
78
|
-
env.OUTPUT_DIR = path.join(__dirname, 'output');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Ensure output directory exists
|
|
82
|
-
const fs = require('fs');
|
|
83
|
-
if (!fs.existsSync(env.OUTPUT_DIR)) {
|
|
84
|
-
fs.mkdirSync(env.OUTPUT_DIR, { recursive: true });
|
|
85
|
-
console.log(`š Created output directory: ${env.OUTPUT_DIR}`);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
console.log(`
|
|
89
|
-
š Starting CDP Browser Control MCP Server
|
|
90
|
-
|
|
91
|
-
š Configuration:
|
|
92
|
-
Environment: ${env.NODE_ENV || 'development'}
|
|
93
|
-
Debug Mode: ${env.MCP_FEATURES_ENABLEDEBUGMODE || 'false'}
|
|
94
|
-
Output Dir: ${env.OUTPUT_DIR}
|
|
95
|
-
|
|
96
|
-
š§ Available Tools: 20
|
|
97
|
-
Browser Automation: 17 tools
|
|
98
|
-
API Testing: 3 tools
|
|
99
|
-
|
|
100
|
-
š Integration ready for:
|
|
101
|
-
⢠Claude Desktop
|
|
102
|
-
⢠MCP Inspector
|
|
103
|
-
⢠Custom MCP clients
|
|
104
|
-
|
|
105
|
-
š” Use --help for integration examples
|
|
106
|
-
`);
|
|
107
|
-
|
|
108
|
-
// Start the server
|
|
109
|
-
const serverPath = path.join(__dirname, 'mcpServer.js');
|
|
110
|
-
const serverProcess = spawn('node', [serverPath], {
|
|
111
|
-
env,
|
|
112
|
-
stdio: 'inherit'
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Handle process events
|
|
116
|
-
serverProcess.on('error', (error) => {
|
|
117
|
-
console.error('ā Failed to start server:', error.message);
|
|
118
|
-
process.exit(1);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
serverProcess.on('exit', (code, signal) => {
|
|
122
|
-
if (signal) {
|
|
123
|
-
console.log(`\nš Server stopped by signal: ${signal}`);
|
|
124
|
-
} else if (code !== 0) {
|
|
125
|
-
console.error(`ā Server exited with code: ${code}`);
|
|
126
|
-
process.exit(code);
|
|
127
|
-
} else {
|
|
128
|
-
console.log('\nš Server stopped gracefully');
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
// Forward signals to server
|
|
133
|
-
process.on('SIGINT', () => {
|
|
134
|
-
console.log('\nā¹ļø Stopping server...');
|
|
135
|
-
serverProcess.kill('SIGINT');
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
process.on('SIGTERM', () => {
|
|
139
|
-
serverProcess.kill('SIGTERM');
|
|
140
|
-
});
|