@ricardodeazambuja/browser-mcp-server 1.0.3 → 1.4.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.
Files changed (43) hide show
  1. package/CHANGELOG-v1.3.0.md +42 -0
  2. package/CHANGELOG-v1.4.0.md +8 -0
  3. package/README.md +271 -45
  4. package/package.json +11 -10
  5. package/plugins/.gitkeep +0 -0
  6. package/src/.gitkeep +0 -0
  7. package/src/browser.js +152 -0
  8. package/src/cdp.js +58 -0
  9. package/src/index.js +126 -0
  10. package/src/tools/.gitkeep +0 -0
  11. package/src/tools/console.js +139 -0
  12. package/src/tools/docs.js +1611 -0
  13. package/src/tools/index.js +60 -0
  14. package/src/tools/info.js +139 -0
  15. package/src/tools/interaction.js +126 -0
  16. package/src/tools/keyboard.js +27 -0
  17. package/src/tools/media.js +264 -0
  18. package/src/tools/mouse.js +104 -0
  19. package/src/tools/navigation.js +72 -0
  20. package/src/tools/network.js +552 -0
  21. package/src/tools/pages.js +149 -0
  22. package/src/tools/performance.js +517 -0
  23. package/src/tools/security.js +470 -0
  24. package/src/tools/storage.js +467 -0
  25. package/src/tools/system.js +196 -0
  26. package/src/utils.js +131 -0
  27. package/tests/.gitkeep +0 -0
  28. package/tests/fixtures/.gitkeep +0 -0
  29. package/tests/fixtures/test-media.html +35 -0
  30. package/tests/fixtures/test-network.html +48 -0
  31. package/tests/fixtures/test-performance.html +61 -0
  32. package/tests/fixtures/test-security.html +33 -0
  33. package/tests/fixtures/test-storage.html +76 -0
  34. package/tests/run-all.js +50 -0
  35. package/{test-browser-automation.js → tests/test-browser-automation.js} +44 -5
  36. package/{test-mcp.js → tests/test-mcp.js} +9 -4
  37. package/tests/test-media-tools.js +168 -0
  38. package/tests/test-network.js +212 -0
  39. package/tests/test-performance.js +254 -0
  40. package/tests/test-security.js +203 -0
  41. package/tests/test-storage.js +192 -0
  42. package/CHANGELOG-v1.0.2.md +0 -126
  43. package/browser-mcp-server-playwright.js +0 -792
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Security Tools Test Suite
5
+ * Tests security headers, CSP monitoring, and mixed content detection
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const path = require('path');
10
+ const readline = require('readline');
11
+
12
+ const serverPath = path.join(__dirname, '..', 'src', 'index.js');
13
+ const proc = spawn('node', [serverPath], { stdio: ['pipe', 'pipe', 'pipe'] });
14
+
15
+ proc.stderr.on('data', (data) => {
16
+ // Suppress stderr for cleaner test output
17
+ });
18
+
19
+ proc.on('error', (err) => {
20
+ console.error('Server error:', err);
21
+ process.exit(1);
22
+ });
23
+
24
+ const rl = readline.createInterface({ input: proc.stdout, terminal: false });
25
+
26
+ let messageId = 1;
27
+ let testStep = 0;
28
+
29
+ function sendRequest(method, params) {
30
+ const request = { jsonrpc: '2.0', id: messageId++, method, params };
31
+ proc.stdin.write(JSON.stringify(request) + '\n');
32
+ }
33
+
34
+ console.log('🔒 Security Tools Test Suite\n');
35
+
36
+ rl.on('line', (line) => {
37
+ try {
38
+ const response = JSON.parse(line);
39
+ if (response.method === 'notifications/resources/list_changed') return;
40
+ if (response.error) {
41
+ console.error('❌ Error:', response.error.message);
42
+ process.exit(1);
43
+ }
44
+ if (response.result && response.id) {
45
+ handleResponse(response);
46
+ }
47
+ } catch (e) {
48
+ // Ignore non-JSON lines
49
+ }
50
+ });
51
+
52
+ function handleResponse(response) {
53
+ const currentTest = steps[testStep];
54
+ if (!currentTest) return;
55
+
56
+ console.log(`➡️ ${currentTest.name}`);
57
+
58
+ try {
59
+ currentTest.verify(response);
60
+ console.log(` ✅ Passed\n`);
61
+ } catch (err) {
62
+ console.error(` ❌ Failed: ${err.message}`);
63
+ process.exit(1);
64
+ }
65
+
66
+ testStep++;
67
+ if (testStep < steps.length) {
68
+ setTimeout(() => {
69
+ sendRequest(steps[testStep].method, steps[testStep].params());
70
+ }, 500);
71
+ } else {
72
+ console.log('🎉 All security tests passed!');
73
+ proc.kill();
74
+ process.exit(0);
75
+ }
76
+ }
77
+
78
+ const steps = [
79
+ {
80
+ name: 'Initialize',
81
+ method: 'initialize',
82
+ params: () => ({
83
+ protocolVersion: '2024-11-05',
84
+ capabilities: {},
85
+ clientInfo: { name: 'security-test', version: '1.0.0' }
86
+ }),
87
+ verify: () => { }
88
+ },
89
+ {
90
+ name: 'Navigate to Security Test Page',
91
+ method: 'tools/call',
92
+ params: () => ({
93
+ name: 'browser_navigate',
94
+ arguments: { url: 'file://' + path.join(__dirname, 'fixtures', 'test-security.html') }
95
+ }),
96
+ verify: () => { }
97
+ },
98
+ {
99
+ name: 'Wait for Page Load',
100
+ method: 'tools/call',
101
+ params: () => ({
102
+ name: 'browser_wait',
103
+ arguments: { ms: 1000 }
104
+ }),
105
+ verify: () => { }
106
+ },
107
+ {
108
+ name: 'Get Security Headers',
109
+ method: 'tools/call',
110
+ params: () => ({
111
+ name: 'browser_sec_get_security_headers',
112
+ arguments: {}
113
+ }),
114
+ verify: (res) => {
115
+ const text = res.result.content[0].text;
116
+ if (res.result.isError) {
117
+ throw new Error('Get security headers failed: ' + text);
118
+ }
119
+ if (!text.includes('content-security-policy') && !text.includes('Security Headers')) {
120
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
121
+ }
122
+ }
123
+ },
124
+ {
125
+ name: 'Start CSP Monitoring',
126
+ method: 'tools/call',
127
+ params: () => ({
128
+ name: 'browser_sec_start_csp_monitoring',
129
+ arguments: {}
130
+ }),
131
+ verify: (res) => {
132
+ const text = res.result.content[0].text;
133
+ // Accept success, already active, or error
134
+ if (!text.includes('monitoring started') && !text.includes('already active') && !text.includes('Error')) {
135
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
136
+ }
137
+ }
138
+ },
139
+ {
140
+ name: 'Wait for CSP Events',
141
+ method: 'tools/call',
142
+ params: () => ({
143
+ name: 'browser_wait',
144
+ arguments: { ms: 1000 }
145
+ }),
146
+ verify: () => { }
147
+ },
148
+ {
149
+ name: 'Get CSP Violations',
150
+ method: 'tools/call',
151
+ params: () => ({
152
+ name: 'browser_sec_get_csp_violations',
153
+ arguments: {}
154
+ }),
155
+ verify: (res) => {
156
+ const text = res.result.content[0].text;
157
+ // May or may not have violations depending on browser behavior
158
+ if (!text.includes('violations') && !text.includes('No CSP') && !text.includes('not active') && !text.includes('Error')) {
159
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
160
+ }
161
+ }
162
+ },
163
+ {
164
+ name: 'Stop CSP Monitoring',
165
+ method: 'tools/call',
166
+ params: () => ({
167
+ name: 'browser_sec_stop_csp_monitoring',
168
+ arguments: {}
169
+ }),
170
+ verify: (res) => {
171
+ const text = res.result.content[0].text;
172
+ // Accept stopped, not active, or error
173
+ if (!text.includes('stopped') && !text.includes('not active') && !text.includes('Error')) {
174
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
175
+ }
176
+ }
177
+ },
178
+ {
179
+ name: 'Detect Mixed Content (HTTP page)',
180
+ method: 'tools/call',
181
+ params: () => ({
182
+ name: 'browser_sec_detect_mixed_content',
183
+ arguments: {}
184
+ }),
185
+ verify: (res) => {
186
+ const text = res.result.content[0].text;
187
+ // On file:// protocol, should indicate HTTPS-only
188
+ if (!text.includes('HTTPS') && !text.includes('No mixed content')) {
189
+ throw new Error('Invalid mixed content response');
190
+ }
191
+ }
192
+ }
193
+ ];
194
+
195
+ // Start tests
196
+ setTimeout(() => sendRequest(steps[0].method, steps[0].params()), 500);
197
+
198
+ // Timeout after 60 seconds
199
+ setTimeout(() => {
200
+ console.error('\n❌ Test timeout');
201
+ proc.kill();
202
+ process.exit(1);
203
+ }, 60000);
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Storage Tools Test Suite
5
+ * Tests IndexedDB, Cache Storage, and Service Worker inspection
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const path = require('path');
10
+ const readline = require('readline');
11
+
12
+ const serverPath = path.join(__dirname, '..', 'src', 'index.js');
13
+ const proc = spawn('node', [serverPath], { stdio: ['pipe', 'pipe', 'pipe'] });
14
+
15
+ proc.stderr.on('data', (data) => {
16
+ // Suppress stderr for cleaner test output
17
+ });
18
+
19
+ proc.on('error', (err) => {
20
+ console.error('Server error:', err);
21
+ process.exit(1);
22
+ });
23
+
24
+ const rl = readline.createInterface({ input: proc.stdout, terminal: false });
25
+
26
+ let messageId = 1;
27
+ let testStep = 0;
28
+
29
+ function sendRequest(method, params) {
30
+ const request = { jsonrpc: '2.0', id: messageId++, method, params };
31
+ proc.stdin.write(JSON.stringify(request) + '\n');
32
+ }
33
+
34
+ console.log('💾 Storage Tools Test Suite\n');
35
+
36
+ rl.on('line', (line) => {
37
+ try {
38
+ const response = JSON.parse(line);
39
+ if (response.method === 'notifications/resources/list_changed') return;
40
+ if (response.error) {
41
+ console.error('❌ Error:', response.error.message);
42
+ process.exit(1);
43
+ }
44
+ if (response.result && response.id) {
45
+ handleResponse(response);
46
+ }
47
+ } catch (e) {
48
+ // Ignore non-JSON lines
49
+ }
50
+ });
51
+
52
+ function handleResponse(response) {
53
+ const currentTest = steps[testStep];
54
+ if (!currentTest) return;
55
+
56
+ console.log(`➡️ ${currentTest.name}`);
57
+
58
+ try {
59
+ currentTest.verify(response);
60
+ console.log(` ✅ Passed\n`);
61
+ } catch (err) {
62
+ console.error(` ❌ Failed: ${err.message}`);
63
+ process.exit(1);
64
+ }
65
+
66
+ testStep++;
67
+ if (testStep < steps.length) {
68
+ setTimeout(() => {
69
+ sendRequest(steps[testStep].method, steps[testStep].params());
70
+ }, 500);
71
+ } else {
72
+ console.log('🎉 All storage tests passed!');
73
+ proc.kill();
74
+ process.exit(0);
75
+ }
76
+ }
77
+
78
+ const steps = [
79
+ {
80
+ name: 'Initialize',
81
+ method: 'initialize',
82
+ params: () => ({
83
+ protocolVersion: '2024-11-05',
84
+ capabilities: {},
85
+ clientInfo: { name: 'storage-test', version: '1.0.0' }
86
+ }),
87
+ verify: () => { }
88
+ },
89
+ {
90
+ name: 'Navigate to Storage Test Page',
91
+ method: 'tools/call',
92
+ params: () => ({
93
+ name: 'browser_navigate',
94
+ arguments: { url: 'file://' + path.join(__dirname, 'fixtures', 'test-storage.html') }
95
+ }),
96
+ verify: () => { }
97
+ },
98
+ {
99
+ name: 'Wait for Storage Setup',
100
+ method: 'tools/call',
101
+ params: () => ({
102
+ name: 'browser_wait',
103
+ arguments: { ms: 2000 }
104
+ }),
105
+ verify: () => { }
106
+ },
107
+ {
108
+ name: 'List IndexedDB Databases',
109
+ method: 'tools/call',
110
+ params: () => ({
111
+ name: 'browser_storage_get_indexeddb',
112
+ arguments: {}
113
+ }),
114
+ verify: (res) => {
115
+ const text = res.result.content[0].text;
116
+ // Should list databases, indicate none found, or CDP error
117
+ if (!text.includes('databases') && !text.includes('No IndexedDB') && !text.includes('CDP Error') && !text.includes('Error')) {
118
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
119
+ }
120
+ }
121
+ },
122
+ {
123
+ name: 'Inspect IndexedDB Database',
124
+ method: 'tools/call',
125
+ params: () => ({
126
+ name: 'browser_storage_get_indexeddb',
127
+ arguments: { databaseName: 'testDB' }
128
+ }),
129
+ verify: (res) => {
130
+ const text = res.result.content[0].text;
131
+ // Should show database structure or error if not found
132
+ if (!text.includes('objectStores') && !text.includes('not found') && !text.includes('error') && !text.includes('Error') && !text.includes('CDP Error')) {
133
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
134
+ }
135
+ }
136
+ },
137
+ {
138
+ name: 'List Cache Storage',
139
+ method: 'tools/call',
140
+ params: () => ({
141
+ name: 'browser_storage_get_cache_storage',
142
+ arguments: {}
143
+ }),
144
+ verify: (res) => {
145
+ const text = res.result.content[0].text;
146
+ // Should list caches, indicate none found, or error
147
+ if (!text.includes('caches') && !text.includes('No Cache') && !text.includes('CDP Error') && !text.includes('Error')) {
148
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
149
+ }
150
+ }
151
+ },
152
+ {
153
+ name: 'Inspect Cache Entries',
154
+ method: 'tools/call',
155
+ params: () => ({
156
+ name: 'browser_storage_get_cache_storage',
157
+ arguments: { cacheName: 'test-cache-v1' }
158
+ }),
159
+ verify: (res) => {
160
+ const text = res.result.content[0].text;
161
+ // Should show cache entries, not found, or error
162
+ if (!text.includes('entries') && !text.includes('not found') && !text.includes('CDP Error') && !text.includes('Error')) {
163
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
164
+ }
165
+ }
166
+ },
167
+ {
168
+ name: 'Get Service Workers',
169
+ method: 'tools/call',
170
+ params: () => ({
171
+ name: 'browser_storage_get_service_workers',
172
+ arguments: {}
173
+ }),
174
+ verify: (res) => {
175
+ const text = res.result.content[0].text;
176
+ // Should list service workers, indicate none/not supported, or error
177
+ if (!text.includes('Service Worker') && !text.includes('supported') && !text.includes('No service') && !text.includes('Error') && !text.includes('CDP Error')) {
178
+ throw new Error('Unexpected response: ' + text.substring(0, 100));
179
+ }
180
+ }
181
+ }
182
+ ];
183
+
184
+ // Start tests
185
+ setTimeout(() => sendRequest(steps[0].method, steps[0].params()), 500);
186
+
187
+ // Timeout after 60 seconds
188
+ setTimeout(() => {
189
+ console.error('\n❌ Test timeout');
190
+ proc.kill();
191
+ process.exit(1);
192
+ }, 60000);
@@ -1,126 +0,0 @@
1
- # Changelog - Version 1.0.2
2
-
3
- ## Release Date
4
- 2025-12-26
5
-
6
- ## Summary
7
- Enhanced browser detection and standalone mode support. The MCP server now intelligently searches for and uses system Chrome/Chromium installations, eliminating the need for redundant browser downloads.
8
-
9
- ## New Features
10
-
11
- ### 1. Smart Chrome/Chromium Detection
12
- - **New function**: `findChromeExecutable()` searches for Chrome/Chromium in common system locations
13
- - **Search locations**:
14
- - Linux: `/usr/bin/google-chrome`, `/usr/bin/chromium`, `/usr/bin/chromium-browser`, `/snap/bin/chromium`
15
- - macOS: `/Applications/Google Chrome.app`, `/Applications/Chromium.app`
16
- - Windows: `C:\Program Files\Google\Chrome\Application\chrome.exe`
17
- - Also uses `which` command as fallback on Unix systems
18
-
19
- ### 2. Three-Tier Browser Strategy
20
- The server now tries browsers in this order:
21
- 1. **Antigravity Mode**: Connect to existing Chrome on port 9222 (if available)
22
- 2. **System Browser**: Use system-installed Chrome/Chromium (if found)
23
- 3. **Playwright Chromium**: Fall back to Playwright's Chromium (if installed)
24
-
25
- ### 3. Improved Error Messages
26
- When no browser is found, users get clear, actionable instructions:
27
-
28
- ```
29
- ❌ No Chrome/Chromium browser found!
30
-
31
- This MCP server needs a Chrome or Chromium browser to work.
32
-
33
- Option 1 - Install Chrome/Chromium on your system:
34
- • Ubuntu/Debian: sudo apt install google-chrome-stable
35
- • Ubuntu/Debian: sudo apt install chromium-browser
36
- • Fedora: sudo dnf install google-chrome-stable
37
- • macOS: brew install --cask google-chrome
38
- • Or download from: https://www.google.com/chrome/
39
-
40
- Option 2 - Install Playwright's Chromium:
41
- npm install playwright
42
- npx playwright install chromium
43
-
44
- Option 3 - Use with Antigravity:
45
- Open Antigravity and click the Chrome logo (top right) to start the browser.
46
- This MCP server will automatically connect to it.
47
- ```
48
-
49
- ## Bug Fixes
50
-
51
- ### 1. Browser Reconnection
52
- - Fixed browser disconnection detection
53
- - Improved reconnection logic after browser crashes or closures
54
-
55
- ## Changes
56
-
57
- ### package.json
58
- - Moved Playwright from `peerDependencies` to `dependencies` (^1.57.0)
59
- - Removed `postinstall` script (no longer auto-installs Chromium)
60
- - Users can now choose: system Chrome, Chromium, or Playwright Chromium
61
-
62
- ### browser-mcp-server-playwright.js
63
- - Added `findChromeExecutable()` function (+43 lines)
64
- - Enhanced browser launch logic with Chrome detection
65
- - Improved error handling with context-aware messages
66
- - Better debug logging for troubleshooting
67
-
68
- ## Benefits
69
-
70
- ✅ **No Redundant Downloads**: Uses existing Chrome/Chromium installations
71
- ✅ **Disk Space Savings**: Avoids downloading ~275MB Playwright Chromium if system browser exists
72
- ✅ **Faster Installation**: No browser download during npm install
73
- ✅ **Better UX**: Clear error messages guide users to solutions
74
- ✅ **Flexible**: Works with Antigravity, system browsers, OR Playwright Chromium
75
- ✅ **Cross-Platform**: Supports Linux, macOS, and Windows
76
-
77
- ## Compatibility
78
-
79
- - **Node.js**: >=16.0.0
80
- - **Playwright**: ^1.57.0
81
- - **Browsers**: Chrome, Chromium, or Playwright Chromium
82
-
83
- ## Testing
84
-
85
- All 16 browser automation tools tested and verified:
86
- - ✅ browser_navigate
87
- - ✅ browser_click
88
- - ✅ browser_screenshot
89
- - ✅ browser_get_text
90
- - ✅ browser_type
91
- - ✅ browser_evaluate
92
- - ✅ browser_wait_for_selector
93
- - ✅ browser_scroll
94
- - ✅ browser_resize_window
95
- - ✅ browser_get_dom
96
- - ✅ browser_start_video_recording
97
- - ✅ browser_stop_video_recording
98
- - ✅ browser_health_check
99
- - ✅ browser_console_start
100
- - ✅ browser_console_get
101
- - ✅ browser_console_clear
102
-
103
- ## Migration Guide
104
-
105
- ### From v1.0.1 to v1.0.2
106
-
107
- **No action required!** The update is fully backward compatible.
108
-
109
- **If you had Playwright Chromium installed:**
110
- - It will still work as a fallback
111
- - But the server will prefer your system Chrome/Chromium if available
112
-
113
- **If you didn't have any browser:**
114
- - The new error messages will guide you through installation options
115
- - Choose the option that works best for your system
116
-
117
- ## Debug Logs
118
-
119
- Server logs are written to: `/tmp/mcp-browser-server.log`
120
-
121
- Example log output:
122
- ```
123
- Found Chrome at: /usr/bin/google-chrome
124
- Using system Chrome/Chromium: /usr/bin/google-chrome
125
- ✅ Successfully launched new Chrome instance (Standalone mode)
126
- ```