@democratize-quality/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 +15 -0
- package/README.md +423 -0
- package/browserControl.js +113 -0
- package/cli.js +187 -0
- package/docs/api/tool-reference.md +317 -0
- package/docs/api_tools_usage.md +477 -0
- package/docs/development/adding-tools.md +274 -0
- package/docs/development/configuration.md +332 -0
- package/docs/examples/authentication.md +124 -0
- package/docs/examples/basic-automation.md +105 -0
- package/docs/getting-started.md +214 -0
- package/docs/index.md +61 -0
- package/mcpServer.js +280 -0
- package/package.json +83 -0
- package/run-server.js +140 -0
- package/src/config/environments/api-only.js +53 -0
- package/src/config/environments/development.js +54 -0
- package/src/config/environments/production.js +69 -0
- package/src/config/index.js +341 -0
- package/src/config/server.js +41 -0
- package/src/config/tools/api.js +67 -0
- package/src/config/tools/browser.js +90 -0
- package/src/config/tools/default.js +32 -0
- package/src/services/browserService.js +325 -0
- package/src/tools/api/api-request.js +641 -0
- package/src/tools/api/api-session-report.js +1262 -0
- package/src/tools/api/api-session-status.js +395 -0
- package/src/tools/base/ToolBase.js +230 -0
- package/src/tools/base/ToolRegistry.js +269 -0
- package/src/tools/browser/advanced/browser-console.js +384 -0
- package/src/tools/browser/advanced/browser-dialog.js +319 -0
- package/src/tools/browser/advanced/browser-evaluate.js +337 -0
- package/src/tools/browser/advanced/browser-file.js +480 -0
- package/src/tools/browser/advanced/browser-keyboard.js +343 -0
- package/src/tools/browser/advanced/browser-mouse.js +332 -0
- package/src/tools/browser/advanced/browser-network.js +421 -0
- package/src/tools/browser/advanced/browser-pdf.js +407 -0
- package/src/tools/browser/advanced/browser-tabs.js +497 -0
- package/src/tools/browser/advanced/browser-wait.js +378 -0
- package/src/tools/browser/click.js +168 -0
- package/src/tools/browser/close.js +60 -0
- package/src/tools/browser/dom.js +70 -0
- package/src/tools/browser/launch.js +67 -0
- package/src/tools/browser/navigate.js +270 -0
- package/src/tools/browser/screenshot.js +351 -0
- package/src/tools/browser/type.js +174 -0
- package/src/tools/index.js +95 -0
- package/src/utils/browserHelpers.js +83 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Basic Browser Automation
|
|
2
|
+
|
|
3
|
+
This example demonstrates basic browser automation tasks using the Democratize Quality MCP Server.
|
|
4
|
+
|
|
5
|
+
## Complete Workflow
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
// 1. Launch browser
|
|
9
|
+
{
|
|
10
|
+
"jsonrpc": "2.0",
|
|
11
|
+
"id": 1,
|
|
12
|
+
"method": "tools/call",
|
|
13
|
+
"params": {
|
|
14
|
+
"name": "browser_launch",
|
|
15
|
+
"arguments": {
|
|
16
|
+
"headless": true,
|
|
17
|
+
"userDataDir": "./browser-session"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Response: { "browserId": "browser-abc123", "port": 9222 }
|
|
23
|
+
|
|
24
|
+
// 2. Navigate to page
|
|
25
|
+
{
|
|
26
|
+
"jsonrpc": "2.0",
|
|
27
|
+
"id": 2,
|
|
28
|
+
"method": "tools/call",
|
|
29
|
+
"params": {
|
|
30
|
+
"name": "browser_navigate",
|
|
31
|
+
"arguments": {
|
|
32
|
+
"browserId": "browser-abc123",
|
|
33
|
+
"url": "https://example.com"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 3. Take screenshot
|
|
39
|
+
{
|
|
40
|
+
"jsonrpc": "2.0",
|
|
41
|
+
"id": 3,
|
|
42
|
+
"method": "tools/call",
|
|
43
|
+
"params": {
|
|
44
|
+
"name": "browser_screenshot",
|
|
45
|
+
"arguments": {
|
|
46
|
+
"browserId": "browser-abc123",
|
|
47
|
+
"fileName": "homepage.png"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 4. Extract page content
|
|
53
|
+
{
|
|
54
|
+
"jsonrpc": "2.0",
|
|
55
|
+
"id": 4,
|
|
56
|
+
"method": "tools/call",
|
|
57
|
+
"params": {
|
|
58
|
+
"name": "browser_dom",
|
|
59
|
+
"arguments": {
|
|
60
|
+
"browserId": "browser-abc123"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 5. Close browser
|
|
66
|
+
{
|
|
67
|
+
"jsonrpc": "2.0",
|
|
68
|
+
"id": 5,
|
|
69
|
+
"method": "tools/call",
|
|
70
|
+
"params": {
|
|
71
|
+
"name": "browser_close",
|
|
72
|
+
"arguments": {
|
|
73
|
+
"browserId": "browser-abc123"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Error Handling
|
|
80
|
+
|
|
81
|
+
Always handle errors appropriately:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
// If a tool call fails, you'll receive an error response:
|
|
85
|
+
{
|
|
86
|
+
"jsonrpc": "2.0",
|
|
87
|
+
"id": 1,
|
|
88
|
+
"error": {
|
|
89
|
+
"code": -32000,
|
|
90
|
+
"message": "Tool 'browser_navigate' execution failed: Browser instance 'invalid-id' not found",
|
|
91
|
+
"data": {
|
|
92
|
+
"tool_name": "browser_navigate",
|
|
93
|
+
"original_error": "Browser instance 'invalid-id' not found"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Best Practices
|
|
100
|
+
|
|
101
|
+
1. **Always close browsers** when done to free resources
|
|
102
|
+
2. **Use persistent profiles** for authenticated sessions
|
|
103
|
+
3. **Handle errors gracefully** with retry logic
|
|
104
|
+
4. **Take screenshots** for debugging and verification
|
|
105
|
+
5. **Use meaningful file names** for screenshots
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
Quick start guide for the Democratize Quality MCP Server.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
### Prerequisites
|
|
10
|
+
|
|
11
|
+
- Node.js 18+
|
|
12
|
+
- Chrome/Chromium browser
|
|
13
|
+
- Git
|
|
14
|
+
|
|
15
|
+
### Clone and Setup
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
git clone https://github.com/democratize-quality/mcp-server.git
|
|
19
|
+
cd mcp-server
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Basic Usage
|
|
24
|
+
|
|
25
|
+
### 1. Start the Server
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
node mcpServer.js
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The server will start and display available tools:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
[Tools] Tool system initialized successfully:
|
|
35
|
+
[Tools] - Total tools: 7
|
|
36
|
+
[Tools] - Available tools: browser_launch, browser_navigate, browser_screenshot, ...
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Connect an MCP Client
|
|
40
|
+
|
|
41
|
+
The server communicates via JSON-RPC over stdin/stdout. Example client integration:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"jsonrpc": "2.0",
|
|
46
|
+
"id": 1,
|
|
47
|
+
"method": "tools/list"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 3. Basic Browser Automation
|
|
52
|
+
|
|
53
|
+
Here's a complete example of launching a browser, navigating to a page, and taking a screenshot:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
// 1. Launch browser
|
|
57
|
+
{
|
|
58
|
+
"jsonrpc": "2.0",
|
|
59
|
+
"id": 1,
|
|
60
|
+
"method": "tools/call",
|
|
61
|
+
"params": {
|
|
62
|
+
"name": "browser_launch",
|
|
63
|
+
"arguments": { "headless": true }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 2. Navigate to page
|
|
68
|
+
{
|
|
69
|
+
"jsonrpc": "2.0",
|
|
70
|
+
"id": 2,
|
|
71
|
+
"method": "tools/call",
|
|
72
|
+
"params": {
|
|
73
|
+
"name": "browser_navigate",
|
|
74
|
+
"arguments": {
|
|
75
|
+
"browserId": "browser-123",
|
|
76
|
+
"url": "https://example.com"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 3. Take screenshot
|
|
82
|
+
{
|
|
83
|
+
"jsonrpc": "2.0",
|
|
84
|
+
"id": 3,
|
|
85
|
+
"method": "tools/call",
|
|
86
|
+
"params": {
|
|
87
|
+
"name": "browser_screenshot",
|
|
88
|
+
"arguments": {
|
|
89
|
+
"browserId": "browser-123",
|
|
90
|
+
"fileName": "example.png"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Configuration
|
|
97
|
+
|
|
98
|
+
### Environment Modes
|
|
99
|
+
|
|
100
|
+
**Development Mode** (default):
|
|
101
|
+
- Shows browser UI
|
|
102
|
+
- Detailed logging
|
|
103
|
+
- Debug features enabled
|
|
104
|
+
|
|
105
|
+
**Production Mode**:
|
|
106
|
+
```bash
|
|
107
|
+
NODE_ENV=production node mcpServer.js
|
|
108
|
+
```
|
|
109
|
+
- Headless browsers only
|
|
110
|
+
- Minimal logging
|
|
111
|
+
- Optimized performance
|
|
112
|
+
|
|
113
|
+
### Feature Flags
|
|
114
|
+
|
|
115
|
+
Disable specific tool categories:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Disable browser tools
|
|
119
|
+
MCP_FEATURES_ENABLEBROWSERTOOLS=false node mcpServer.js
|
|
120
|
+
|
|
121
|
+
# Run with only specific tools
|
|
122
|
+
MCP_FEATURES_ENABLEFILETOOLS=false \
|
|
123
|
+
MCP_FEATURES_ENABLENETWORKTOOLS=false \
|
|
124
|
+
node mcpServer.js
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Custom Configuration
|
|
128
|
+
|
|
129
|
+
Create environment-specific configs in `src/config/environments/`:
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
// src/config/environments/testing.js
|
|
133
|
+
module.exports = {
|
|
134
|
+
tools: {
|
|
135
|
+
browser: {
|
|
136
|
+
browser_launch: {
|
|
137
|
+
defaultHeadless: true,
|
|
138
|
+
maxInstances: 1
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Run with custom environment:
|
|
146
|
+
```bash
|
|
147
|
+
NODE_ENV=testing node mcpServer.js
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Common Use Cases
|
|
151
|
+
|
|
152
|
+
### Web Scraping
|
|
153
|
+
1. Launch browser with persistent profile
|
|
154
|
+
2. Navigate to login page
|
|
155
|
+
3. Fill credentials
|
|
156
|
+
4. Navigate to target pages
|
|
157
|
+
5. Extract data
|
|
158
|
+
6. Close browser
|
|
159
|
+
|
|
160
|
+
### Automated Testing
|
|
161
|
+
1. Launch browser in headless mode
|
|
162
|
+
2. Navigate to application
|
|
163
|
+
3. Perform user interactions
|
|
164
|
+
4. Take screenshots for verification
|
|
165
|
+
5. Assert expected outcomes
|
|
166
|
+
|
|
167
|
+
### Content Generation
|
|
168
|
+
1. Navigate to webpage
|
|
169
|
+
2. Take full-page screenshots
|
|
170
|
+
3. Extract text content
|
|
171
|
+
4. Generate reports
|
|
172
|
+
|
|
173
|
+
## Troubleshooting
|
|
174
|
+
|
|
175
|
+
### Common Issues
|
|
176
|
+
|
|
177
|
+
**Browser fails to launch:**
|
|
178
|
+
- Ensure Chrome/Chromium is installed
|
|
179
|
+
- Check user permissions
|
|
180
|
+
- Try running with `--no-sandbox` flag
|
|
181
|
+
|
|
182
|
+
**Tools not loading:**
|
|
183
|
+
- Check feature flags are enabled
|
|
184
|
+
- Verify file permissions
|
|
185
|
+
- Review server logs for errors
|
|
186
|
+
|
|
187
|
+
**Connection issues:**
|
|
188
|
+
- Ensure proper JSON-RPC formatting
|
|
189
|
+
- Check stdin/stdout communication
|
|
190
|
+
- Verify MCP client implementation
|
|
191
|
+
|
|
192
|
+
### Debug Mode
|
|
193
|
+
|
|
194
|
+
Enable detailed logging:
|
|
195
|
+
```bash
|
|
196
|
+
MCP_FEATURES_ENABLEDEBUGMODE=true node mcpServer.js
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Logs Location
|
|
200
|
+
|
|
201
|
+
- Server logs: stderr output
|
|
202
|
+
- Screenshots: `./output/` directory
|
|
203
|
+
- Browser data: Temporary profiles in system temp
|
|
204
|
+
|
|
205
|
+
## Next Steps
|
|
206
|
+
|
|
207
|
+
- [Tool Reference](api/tool-reference.md) - Complete tool documentation
|
|
208
|
+
- [Developer Guide](development/adding-tools.md) - Extend the server
|
|
209
|
+
- [Configuration Guide](development/configuration.md) - Advanced configuration
|
|
210
|
+
- [Examples](examples/) - Real-world usage examples
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
*For more help, check the documentation or open an issue on GitHub.*
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Documentation Index
|
|
2
|
+
|
|
3
|
+
Welcome to the Democratize Quality MCP Server documentation!
|
|
4
|
+
|
|
5
|
+
## 📚 Table of Contents
|
|
6
|
+
|
|
7
|
+
### Getting Started
|
|
8
|
+
- [🚀 Getting Started](getting-started.md) - Quick start guide and basic usage
|
|
9
|
+
- [📦 Installation](getting-started.md#installation) - Setup and prerequisites
|
|
10
|
+
|
|
11
|
+
### API Reference
|
|
12
|
+
- [🔧 Tool Reference](api/tool-reference.md) - Complete documentation for all tools
|
|
13
|
+
- [⚙️ Feature Flags](api/tool-reference.md#feature-flags) - Tool control and configuration
|
|
14
|
+
|
|
15
|
+
### Development
|
|
16
|
+
- [👨💻 Adding Tools](development/adding-tools.md) - Developer guide for extending the server
|
|
17
|
+
- [🏗️ Architecture](development/adding-tools.md#architecture-overview) - System architecture overview
|
|
18
|
+
- [⚙️ Configuration](development/configuration.md) - Advanced configuration options
|
|
19
|
+
- [🧪 Testing](development/adding-tools.md#testing) - Testing guidelines and examples
|
|
20
|
+
|
|
21
|
+
### Examples
|
|
22
|
+
- [🤖 Basic Automation](examples/basic-automation.md) - Essential browser automation workflows
|
|
23
|
+
- [🔐 Authentication](examples/authentication.md) - Login flows and session management
|
|
24
|
+
|
|
25
|
+
### Additional Resources
|
|
26
|
+
- [📄 Main README](../README.md) - Project overview and quick reference
|
|
27
|
+
- [📋 Package Info](../package.json) - Project dependencies and scripts
|
|
28
|
+
|
|
29
|
+
## 🎯 Quick Navigation
|
|
30
|
+
|
|
31
|
+
### By Use Case
|
|
32
|
+
- **First-time setup**: [Getting Started](getting-started.md)
|
|
33
|
+
- **Tool usage**: [Tool Reference](api/tool-reference.md)
|
|
34
|
+
- **Extending functionality**: [Adding Tools](development/adding-tools.md)
|
|
35
|
+
- **Configuration tuning**: [Configuration Guide](development/configuration.md)
|
|
36
|
+
- **Real-world examples**: [Examples](examples/)
|
|
37
|
+
|
|
38
|
+
### By Role
|
|
39
|
+
- **🤖 AI Agent Developers**: Start with [Tool Reference](api/tool-reference.md)
|
|
40
|
+
- **🛠️ Server Developers**: Read [Adding Tools](development/adding-tools.md)
|
|
41
|
+
- **⚙️ System Administrators**: Check [Configuration Guide](development/configuration.md)
|
|
42
|
+
- **📊 Integration Teams**: Review [Examples](examples/)
|
|
43
|
+
|
|
44
|
+
## 🔄 Keeping Documentation Updated
|
|
45
|
+
|
|
46
|
+
Documentation is automatically generated from the codebase:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Regenerate all documentation
|
|
50
|
+
npm run docs:generate
|
|
51
|
+
|
|
52
|
+
# Watch for changes and regenerate
|
|
53
|
+
npm run docs:watch
|
|
54
|
+
|
|
55
|
+
# Clean and regenerate
|
|
56
|
+
npm run docs:clean && npm run docs:generate
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
*Documentation generated automatically from tool definitions and configuration - Last updated: ${new Date().toISOString().split('T')[0]}*
|
package/mcpServer.js
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
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
|
+
},
|
|
68
|
+
serverInfo: {
|
|
69
|
+
name: "browser-control-server",
|
|
70
|
+
version: "1.0.0"
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// The `tools/list` method for tool discovery
|
|
76
|
+
// Replace your tools/list method with this Draft 7 compatible version:
|
|
77
|
+
|
|
78
|
+
server.addMethod("tools/list", async () => {
|
|
79
|
+
debugLog("Received 'tools/list' request.");
|
|
80
|
+
|
|
81
|
+
// Convert all tool definitions to Claude Desktop compatible format
|
|
82
|
+
const compatibleTools = toolDefinitions.map(tool => {
|
|
83
|
+
// Ensure we use the correct property name and clean schema
|
|
84
|
+
return {
|
|
85
|
+
name: tool.name,
|
|
86
|
+
description: tool.description,
|
|
87
|
+
// Claude Desktop expects 'inputSchema', not 'input_schema'
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {
|
|
91
|
+
// Add minimal properties to avoid empty schema issues
|
|
92
|
+
...((tool.input_schema && tool.input_schema.properties) || {}),
|
|
93
|
+
// Fallback to ensure there's always at least one property
|
|
94
|
+
...(Object.keys((tool.input_schema && tool.input_schema.properties) || {}).length === 0 ? {
|
|
95
|
+
_placeholder: { type: "string", description: "Placeholder parameter" }
|
|
96
|
+
} : {})
|
|
97
|
+
},
|
|
98
|
+
// Only add required if it exists and is not empty
|
|
99
|
+
...(tool.input_schema && tool.input_schema.required && tool.input_schema.required.length > 0 ? {
|
|
100
|
+
required: tool.input_schema.required
|
|
101
|
+
} : {}),
|
|
102
|
+
// Ensure no additionalProperties or other Draft 2020-12 features
|
|
103
|
+
additionalProperties: false
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
debugLog(`Returning ${compatibleTools.length} tools with compatible schemas`);
|
|
109
|
+
debugLog('First tool schema sample:', JSON.stringify(compatibleTools[0]?.inputSchema, null, 2));
|
|
110
|
+
|
|
111
|
+
return { tools: compatibleTools };
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// The `tools/call` method for tool invocation (note: it's tools/call, not tool/call)
|
|
115
|
+
server.addMethod("tools/call", async ({ name, arguments: parameters }) => {
|
|
116
|
+
debugLog(`Received 'tools/call' for method: ${name} with params: ${JSON.stringify(parameters)}`);
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
// Use the new tool system to execute the tool
|
|
120
|
+
const result = await executeTool(name, parameters);
|
|
121
|
+
return result;
|
|
122
|
+
|
|
123
|
+
} catch (error) {
|
|
124
|
+
log(`Error executing tool '${name}':`, error.message);
|
|
125
|
+
|
|
126
|
+
// If it's already a properly formatted MCP error, re-throw it
|
|
127
|
+
if (error.code && error.message) {
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Otherwise, format it as an MCP error
|
|
132
|
+
throw {
|
|
133
|
+
code: -32000,
|
|
134
|
+
message: `Tool execution failed: ${error.message}`,
|
|
135
|
+
data: { tool_name: name, original_error: error.message }
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// The `prompts/list` method for prompt discovery
|
|
141
|
+
server.addMethod("prompts/list", async () => {
|
|
142
|
+
debugLog("Received 'prompts/list' request.");
|
|
143
|
+
// This server doesn't provide any prompts, so return an empty array
|
|
144
|
+
return { prompts: [] };
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// The `resources/list` method for resource discovery
|
|
148
|
+
server.addMethod("resources/list", async () => {
|
|
149
|
+
debugLog("Received 'resources/list' request.");
|
|
150
|
+
// This server doesn't provide any resources, so return an empty array
|
|
151
|
+
return { resources: [] };
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Notification methods (these don't return responses)
|
|
155
|
+
server.addMethod("notifications/initialized", async () => {
|
|
156
|
+
debugLog("Received 'notifications/initialized' notification.");
|
|
157
|
+
// Notifications don't return responses
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
server.addMethod("notifications/cancelled", async ({ requestId, reason }) => {
|
|
161
|
+
debugLog(`Received 'notifications/cancelled' for request ${requestId}: ${reason}`);
|
|
162
|
+
// Notifications don't return responses
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Add a catch-all method handler for debugging
|
|
166
|
+
server.addMethod("*", async (params, method) => {
|
|
167
|
+
debugLog(`Unknown method called: ${method}`);
|
|
168
|
+
throw {
|
|
169
|
+
code: -32601,
|
|
170
|
+
message: `Method '${method}' not found`
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// --- STDIO Communication Loop ---
|
|
175
|
+
// This part handles reading JSON-RPC requests from stdin and writing responses to stdout.
|
|
176
|
+
|
|
177
|
+
let inputBuffer = '';
|
|
178
|
+
|
|
179
|
+
process.stdin.on('data', (chunk) => {
|
|
180
|
+
inputBuffer += chunk.toString();
|
|
181
|
+
|
|
182
|
+
// Process messages delimited by newline. This is a common pattern for STDIO RPC.
|
|
183
|
+
// In a production-grade server, you'd want a more robust JSON stream parser
|
|
184
|
+
// to handle partial messages or multiple messages in one chunk.
|
|
185
|
+
let newlineIndex;
|
|
186
|
+
while ((newlineIndex = inputBuffer.indexOf('\n')) !== -1) {
|
|
187
|
+
const messageString = inputBuffer.substring(0, newlineIndex).trim();
|
|
188
|
+
inputBuffer = inputBuffer.substring(newlineIndex + 1);
|
|
189
|
+
|
|
190
|
+
if (messageString) { // Ensure it's not an empty line
|
|
191
|
+
try {
|
|
192
|
+
const jsonRpcRequest = JSON.parse(messageString);
|
|
193
|
+
debugLog(`Received request: ${JSON.stringify(jsonRpcRequest)}`);
|
|
194
|
+
|
|
195
|
+
// Handle notifications (no response expected)
|
|
196
|
+
if (!jsonRpcRequest.id && jsonRpcRequest.method && jsonRpcRequest.method.startsWith('notifications/')) {
|
|
197
|
+
server.receive(jsonRpcRequest).catch(err => {
|
|
198
|
+
log("Error processing notification:", err.message);
|
|
199
|
+
});
|
|
200
|
+
return; // Don't send a response for notifications
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// The receive method handles processing the request and generating a response
|
|
204
|
+
server.receive(jsonRpcRequest).then((jsonRpcResponse) => {
|
|
205
|
+
if (jsonRpcResponse) {
|
|
206
|
+
debugLog(`Sending response: ${JSON.stringify(jsonRpcResponse)}`);
|
|
207
|
+
// All responses must go to stdout
|
|
208
|
+
process.stdout.write(JSON.stringify(jsonRpcResponse) + '\n');
|
|
209
|
+
}
|
|
210
|
+
}).catch(err => {
|
|
211
|
+
// Catch errors from receive() if it rejects (e.g., malformed JSON-RPC request)
|
|
212
|
+
log("Error processing JSON-RPC request:", err.message);
|
|
213
|
+
|
|
214
|
+
// Send an error response if we have an ID
|
|
215
|
+
if (jsonRpcRequest.id) {
|
|
216
|
+
const errorResponse = {
|
|
217
|
+
jsonrpc: "2.0",
|
|
218
|
+
error: {
|
|
219
|
+
code: -32603,
|
|
220
|
+
message: "Internal error",
|
|
221
|
+
data: err.message
|
|
222
|
+
},
|
|
223
|
+
id: jsonRpcRequest.id
|
|
224
|
+
};
|
|
225
|
+
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
} catch (parseError) {
|
|
229
|
+
log("JSON parse error on input:", messageString, parseError);
|
|
230
|
+
// If the input itself is not valid JSON, we can't get an ID, so ID is null
|
|
231
|
+
const errorResponse = {
|
|
232
|
+
jsonrpc: "2.0",
|
|
233
|
+
error: {
|
|
234
|
+
code: -32700, // Parse error
|
|
235
|
+
message: "Parse error"
|
|
236
|
+
},
|
|
237
|
+
id: null
|
|
238
|
+
};
|
|
239
|
+
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Handle graceful shutdown signals (Ctrl+C, termination)
|
|
246
|
+
process.on('SIGINT', async () => {
|
|
247
|
+
log('\nSIGINT received. Shutting down...');
|
|
248
|
+
try {
|
|
249
|
+
await browserService.shutdownAllBrowsers();
|
|
250
|
+
log('All browser instances closed. Exiting gracefully.');
|
|
251
|
+
} catch (err) {
|
|
252
|
+
log('Error during graceful shutdown:', err.message);
|
|
253
|
+
process.exit(1); // Exit with error code
|
|
254
|
+
}
|
|
255
|
+
process.exit(0); // Exit successfully
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
process.on('SIGTERM', async () => {
|
|
259
|
+
log('\nSIGTERM received. Shutting down...');
|
|
260
|
+
try {
|
|
261
|
+
await browserService.shutdownAllBrowsers();
|
|
262
|
+
log('All browser instances closed. Exiting gracefully.');
|
|
263
|
+
} catch (err) {
|
|
264
|
+
log('Error during graceful shutdown:', err.message);
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
process.exit(0);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Initialize the server and start listening
|
|
271
|
+
(async () => {
|
|
272
|
+
await initializeServer();
|
|
273
|
+
|
|
274
|
+
// Initial message to indicate server is ready (to stderr)
|
|
275
|
+
log(`Server started. Waiting for input on stdin.`);
|
|
276
|
+
if (isDebugMode) {
|
|
277
|
+
log(`To integrate with a host, provide the command: node ${__filename}`);
|
|
278
|
+
log(`Debug mode enabled - showing detailed logs`);
|
|
279
|
+
}
|
|
280
|
+
})();
|