@dynamicu/chromedebug-mcp 2.5.8 → 2.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,6 +5,14 @@
5
5
 
6
6
  ChromeDebug MCP is a Model Context Protocol (MCP) server that gives AI assistants like Claude Code full control over a Chrome browser instance. It provides comprehensive browser automation, debugging, and screen recording capabilities optimized for AI-assisted development.
7
7
 
8
+ ## 🎥 See It In Action
9
+
10
+ Watch the demo video to see how ChromeDebug MCP works:
11
+
12
+ [![ChromeDebug MCP Demo](https://img.youtube.com/vi/2Y9nIsvEjks/0.jpg)](https://youtu.be/2Y9nIsvEjks?si=x5XjN0ZPHYhjZAqd)
13
+
14
+ **[▶️ Watch Demo Video](https://youtu.be/2Y9nIsvEjks?si=x5XjN0ZPHYhjZAqd)**
15
+
8
16
  ## Quick Start
9
17
 
10
18
  ### Installation from npm
@@ -19,6 +27,17 @@ npm install @dynamicu/chromedebug-mcp
19
27
 
20
28
  > **Want unlimited recordings and advanced features?** See [Installing PRO Version](#installing-pro-version) below for automated PRO installation.
21
29
 
30
+ ### Chrome Extension Installation
31
+
32
+ Install the Chrome extension to enable visual element selection and recording features:
33
+
34
+ 🌐 **[Install from Chrome Web Store](https://chromewebstore.google.com/detail/chromedebug-mcp-assistant/lemgbmdnephoaniipapgeciebfeakffn)**
35
+
36
+ - ✅ 5 recordings per day (FREE version)
37
+ - ✅ Visual element selection
38
+ - ✅ Full MCP integration
39
+ - ✅ Automatic updates
40
+
22
41
  ### Development Installation
23
42
 
24
43
  ```bash
@@ -109,15 +128,49 @@ When you launch Chrome with `chromedebug-mcp`, you should see:
109
128
 
110
129
  ### As MCP Server
111
130
 
112
- #### macOS / Linux
131
+ #### Quick Setup (Claude Code CLI)
113
132
 
133
+ **macOS / Linux:**
114
134
  ```bash
115
135
  claude mcp add chromedebug -s user -- chromedebug-mcp
116
136
  ```
117
137
 
138
+ **Windows (WSL2):**
139
+ ```bash
140
+ claude mcp add chromedebug -s user -- wsl chromedebug-mcp
141
+ ```
142
+
118
143
  The MCP server will automatically start both the stdio MCP server and HTTP server for Chrome extension integration.
119
144
 
120
- #### Windows
145
+ #### Manual Configuration (Any MCP Client)
146
+
147
+ If you're not using Claude Code CLI or want to configure manually, add this to your MCP settings file:
148
+
149
+ **Location:** `~/.claude/config.json` or your MCP client's configuration file
150
+
151
+ ```json
152
+ {
153
+ "mcpServers": {
154
+ "chromedebug": {
155
+ "command": "chromedebug-mcp"
156
+ }
157
+ }
158
+ }
159
+ ```
160
+
161
+ **For WSL2 users:**
162
+ ```json
163
+ {
164
+ "mcpServers": {
165
+ "chromedebug": {
166
+ "command": "wsl",
167
+ "args": ["chromedebug-mcp"]
168
+ }
169
+ }
170
+ }
171
+ ```
172
+
173
+ #### Windows Setup Details
121
174
 
122
175
  ⚠️ **Important: WSL2 Recommended for Windows Users**
123
176
 
@@ -260,7 +313,7 @@ Chrome Debug includes a Chrome extension that enables visual element selection f
260
313
 
261
314
  Install the FREE version directly from the Chrome Web Store:
262
315
 
263
- 🌐 **[Install from Chrome Web Store](https://chromewebstore.google.com/detail/lemgbmdnephoaniipapgeciebfeakffn?utm_source=item-share-cb)**
316
+ 🌐 **[Install from Chrome Web Store](https://chromewebstore.google.com/detail/chromedebug-mcp-assistant/lemgbmdnephoaniipapgeciebfeakffn)**
264
317
 
265
318
  - ✅ 5 recordings per day
266
319
  - ✅ Full MCP integration
@@ -1,4 +1,4 @@
1
- import { FUNCTIONS_URL } from './firebase-config.module.js';
1
+ import { FUNCTIONS_URL } from './firebase-config.public.js';
2
2
 
3
3
  /**
4
4
  * Firebase License Client
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Firebase Cloud Functions configuration - PUBLIC VERSION
3
+ * For Service Worker (background.js) via importScripts
4
+ *
5
+ * SECURITY NOTE: This API key is intentionally public and restricted:
6
+ * - Restricted by HTTP referrers in Google Cloud Console
7
+ * - Protected by Firebase Security Rules server-side
8
+ * - Standard practice for all web/mobile Firebase apps
9
+ */
10
+
11
+ // Firebase configuration (public, restricted API key)
12
+ const FIREBASE_CONFIG = {
13
+ projectId: 'chrome-debug-mcp',
14
+ apiKey: 'AIzaSyDu4r5k7J4gb76CVN9evBNg3DV6KjworCE',
15
+ authDomain: 'chromedebug.com'
16
+ };
17
+
18
+ // Cloud Functions base URL
19
+ const FUNCTIONS_URL = `https://us-central1-${FIREBASE_CONFIG.projectId}.cloudfunctions.net`;
20
+
21
+ // LemonSqueezy checkout URL (Production)
22
+ const LEMONSQUEEZY_CHECKOUT_URL = 'https://chromedebug.com/buy/996773cb-682b-430f-b9e3-9ce2130bd967';
23
+
24
+ // Make available globally for service worker context
25
+ if (typeof self !== 'undefined') {
26
+ self.FIREBASE_CONFIG = FIREBASE_CONFIG;
27
+ self.FUNCTIONS_URL = FUNCTIONS_URL;
28
+ self.LEMONSQUEEZY_CHECKOUT_URL = LEMONSQUEEZY_CHECKOUT_URL;
29
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Firebase Cloud Functions configuration - PUBLIC VERSION
3
+ * Safe for client-side use and Web Store distribution
4
+ *
5
+ * SECURITY NOTE: This API key is intentionally public and restricted:
6
+ * - Restricted by HTTP referrers in Google Cloud Console
7
+ * - Protected by Firebase Security Rules server-side
8
+ * - Standard practice for all web/mobile Firebase apps
9
+ *
10
+ * This file is committed to the repository and used for:
11
+ * - Web Store extension builds
12
+ * - Development environments
13
+ * - License validation via Firebase Cloud Functions
14
+ */
15
+
16
+ // Firebase configuration (public, restricted API key)
17
+ const FIREBASE_CONFIG = {
18
+ projectId: 'chrome-debug-mcp',
19
+ apiKey: 'AIzaSyDu4r5k7J4gb76CVN9evBNg3DV6KjworCE',
20
+ authDomain: 'chromedebug.com'
21
+ };
22
+
23
+ // Cloud Functions base URL
24
+ const FUNCTIONS_URL = `https://us-central1-${FIREBASE_CONFIG.projectId}.cloudfunctions.net`;
25
+
26
+ // LemonSqueezy checkout URL (Production)
27
+ const LEMONSQUEEZY_CHECKOUT_URL = 'https://chromedebug.com/buy/996773cb-682b-430f-b9e3-9ce2130bd967';
28
+
29
+ // Export for ES6 modules (popup.js, firebase-client.js)
30
+ export { FIREBASE_CONFIG, FUNCTIONS_URL, LEMONSQUEEZY_CHECKOUT_URL };
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "manifest_version": 3,
3
- "name": "ChromeDebug MCP Assistant FREE v2.4.1",
4
- "version": "2.4.1",
5
- "description": "ChromeDebug MCP visual element selector [FREE Edition] [Build: 2025-01-20-v2.4.1]",
3
+ "name": "ChromeDebug MCP Assistant FREE v2.5.0",
4
+ "version": "2.5.0",
5
+ "description": "ChromeDebug MCP visual element selector [FREE Edition] [Build: 2025-10-21-v2.5.0]",
6
6
  "permissions": [
7
7
  "activeTab",
8
8
  "scripting",
@@ -2,14 +2,30 @@
2
2
  const EXTENSION_VERSION = '2.0.4-BUILD-20250119';
3
3
  console.log(`[popup.js] Loaded version: ${EXTENSION_VERSION}`);
4
4
 
5
- // Import Firebase license client
6
- import { FirebaseLicenseClient } from './firebase-client.js';
7
- import { LEMONSQUEEZY_CHECKOUT_URL } from './firebase-config.module.js';
8
-
9
- // Initialize license client
10
- const licenseClient = new FirebaseLicenseClient();
5
+ // Import Firebase license client with graceful fallback
6
+ let FirebaseLicenseClient = null;
7
+ let LEMONSQUEEZY_CHECKOUT_URL = 'https://chromedebug.com/buy/996773cb-682b-430f-b9e3-9ce2130bd967';
8
+ let licenseClient = null;
11
9
  let currentUserId = null;
12
10
 
11
+ // Load Firebase asynchronously to avoid blocking module execution
12
+ (async () => {
13
+ try {
14
+ const firebaseClientModule = await import('./firebase-client.js');
15
+ FirebaseLicenseClient = firebaseClientModule.FirebaseLicenseClient;
16
+
17
+ const firebaseConfigModule = await import('./firebase-config.public.js');
18
+ LEMONSQUEEZY_CHECKOUT_URL = firebaseConfigModule.LEMONSQUEEZY_CHECKOUT_URL;
19
+
20
+ // Initialize license client if Firebase loaded successfully
21
+ licenseClient = new FirebaseLicenseClient();
22
+ console.log('[popup.js] Firebase license client initialized');
23
+ } catch (error) {
24
+ console.warn('[popup.js] Firebase not available - license features disabled:', error);
25
+ // Extension will work without Firebase, just no license validation
26
+ }
27
+ })();
28
+
13
29
  // Global variables for recording functionality
14
30
  let isRecording = false;
15
31
  let recordingTimer = null;
@@ -102,8 +118,24 @@ function stopWorkflowTimer() {
102
118
  }
103
119
  }
104
120
 
105
- // Import configuration - this will be available globally
106
- const CONFIG_PORTS = CHROMEDEBUG_CONFIG?.ports || [3001, 3000, 3002, 3028]; // Fallback to defaults
121
+ // Smart tiered port discovery configuration
122
+ const PORT_TIERS = {
123
+ // Try common ports first with short timeout (fast discovery)
124
+ common: [3000, 3001, 3002, 3028, 3033],
125
+ // Then try extended range if not found
126
+ extended: [3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010,
127
+ 3029, 3030, 3031, 3032, 3034, 3035, 3036],
128
+ // Finally try alternative common development ports
129
+ alternative: [8080, 8081, 8082, 8083, 8084, 8085,
130
+ 9000, 9001, 9002, 9003, 9004, 9005]
131
+ };
132
+
133
+ // All ports in one array for compatibility (used by CONFIG_PORTS references)
134
+ const CONFIG_PORTS = [
135
+ ...PORT_TIERS.common,
136
+ ...PORT_TIERS.extended,
137
+ ...PORT_TIERS.alternative
138
+ ];
107
139
 
108
140
  // Site management functions
109
141
  async function initializeSiteManagement() {
@@ -262,45 +294,122 @@ function testSiteAccess(hostname, mode, allowedSites, restrictedSites) {
262
294
 
263
295
  // Function definitions (outside DOMContentLoaded for proper scope)
264
296
  async function checkServerStatus() {
297
+ console.log('[popup.js] checkServerStatus() called');
265
298
  const statusEl = document.getElementById('serverStatus');
266
299
  const statusTextEl = document.getElementById('statusText');
267
-
268
- const ports = CONFIG_PORTS;
300
+
301
+ if (!statusEl || !statusTextEl) {
302
+ console.error('[popup.js] Status elements not found in DOM');
303
+ return { connected: false, connectedPort: null };
304
+ }
305
+
269
306
  let connected = false;
270
307
  let connectedPort = null;
271
-
272
- for (const port of ports) {
308
+
309
+ // Helper function to try a port with timeout
310
+ const tryPort = async (port, timeout = 1000) => {
273
311
  try {
312
+ const controller = new AbortController();
313
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
314
+
274
315
  const response = await fetch(`http://localhost:${port}/chromedebug/status`, {
275
316
  method: 'GET',
276
- mode: 'cors'
317
+ mode: 'cors',
318
+ signal: controller.signal
277
319
  });
278
-
279
- if (response.ok) {
320
+
321
+ clearTimeout(timeoutId);
322
+ console.log(`[popup.js] Port ${port} responded: ${response.ok}`);
323
+ return response.ok;
324
+ } catch (error) {
325
+ console.log(`[popup.js] Port ${port} failed:`, error.message);
326
+ return false;
327
+ }
328
+ };
329
+
330
+ // Check if we have a cached successful port from previous session
331
+ const cachedPort = await chrome.storage.local.get('lastSuccessfulPort');
332
+ if (cachedPort.lastSuccessfulPort) {
333
+ if (await tryPort(cachedPort.lastSuccessfulPort, 500)) {
334
+ connected = true;
335
+ connectedPort = cachedPort.lastSuccessfulPort;
336
+ console.log(`[popup.js] Connected to cached port ${connectedPort}`);
337
+ }
338
+ }
339
+
340
+ // If cached port didn't work, try tiered discovery
341
+ if (!connected) {
342
+ // Phase 1: Try common ports with short timeout (fast)
343
+ for (const port of PORT_TIERS.common) {
344
+ if (await tryPort(port, 500)) {
280
345
  connected = true;
281
346
  connectedPort = port;
347
+ console.log(`[popup.js] Connected to common port ${connectedPort}`);
282
348
  break;
283
349
  }
284
- } catch (error) {
285
- // Try next port
286
350
  }
287
351
  }
288
-
352
+
353
+ // Phase 2: Try extended range with longer timeout
354
+ if (!connected) {
355
+ for (const port of PORT_TIERS.extended) {
356
+ if (await tryPort(port, 1000)) {
357
+ connected = true;
358
+ connectedPort = port;
359
+ console.log(`[popup.js] Connected to extended port ${connectedPort}`);
360
+ break;
361
+ }
362
+ }
363
+ }
364
+
365
+ // Phase 3: Try alternative ports as last resort
366
+ if (!connected) {
367
+ for (const port of PORT_TIERS.alternative) {
368
+ if (await tryPort(port, 1000)) {
369
+ connected = true;
370
+ connectedPort = port;
371
+ console.log(`[popup.js] Connected to alternative port ${connectedPort}`);
372
+ break;
373
+ }
374
+ }
375
+ }
376
+
377
+ // Cache the successful port for faster connection next time
378
+ if (connected && connectedPort) {
379
+ await chrome.storage.local.set({ lastSuccessfulPort: connectedPort });
380
+ }
381
+
289
382
  if (connected) {
290
383
  statusEl.className = 'server-status connected';
291
- statusTextEl.innerHTML = `Server connected (port ${connectedPort})`;
384
+ statusTextEl.innerHTML = `
385
+ Server connected (port ${connectedPort})
386
+ <div style="margin-top: 4px;">
387
+ <a href="https://www.npmjs.com/package/@dynamicu/chromedebug-mcp" target="_blank" style="font-size: 10px; color: #666; text-decoration: none;">
388
+ 📚 Documentation
389
+ </a>
390
+ </div>
391
+ `;
292
392
  } else {
293
393
  statusEl.className = 'server-status disconnected';
294
394
 
295
395
  // Enhanced disconnected state with install instructions
296
396
  statusTextEl.innerHTML = `
297
- <span style="display: block; margin-bottom: 8px;">Server not installed</span>
397
+ <div style="font-weight: bold; margin-bottom: 8px;">Server Not Running</div>
398
+ <div style="font-size: 11px; color: #666; margin-bottom: 8px; line-height: 1.4;">
399
+ To use ChromeDebug, install and start the MCP server:
400
+ </div>
401
+ <div style="background: #f5f5f5; padding: 8px; border-radius: 4px; font-family: monospace; font-size: 10px; margin-bottom: 8px;">
402
+ <div style="margin-bottom: 4px;"># Install the server</div>
403
+ <div style="color: #1976d2; margin-bottom: 8px;">npm install -g @dynamicu/chromedebug-mcp</div>
404
+ <div style="margin-bottom: 4px;"># Start the server</div>
405
+ <div style="color: #1976d2;">chromedebug-mcp-server</div>
406
+ </div>
298
407
  <div style="display: flex; gap: 5px; align-items: center;">
299
- <button id="copyInstallCmd" style="padding: 4px 8px; font-size: 11px; background: #2196F3; color: white; border: none; border-radius: 3px; cursor: pointer; flex-shrink: 0;">
300
- 📋 Copy Install Command
408
+ <button id="copyInstallCmd" style="padding: 4px 8px; font-size: 11px; background: #2196F3; color: white; border: none; border-radius: 3px; cursor: pointer;">
409
+ 📋 Copy Commands
301
410
  </button>
302
- <a href="https://www.npmjs.com/package/@dynamicu/chromedebug-mcp" target="_blank" style="font-size: 11px; white-space: nowrap;">
303
- View Installation Guide
411
+ <a href="https://www.npmjs.com/package/@dynamicu/chromedebug-mcp" target="_blank" style="font-size: 11px; color: #2196F3; text-decoration: none;">
412
+ 📚 Full Documentation
304
413
  </a>
305
414
  </div>
306
415
  `;
@@ -311,10 +420,14 @@ async function checkServerStatus() {
311
420
  if (copyBtn) {
312
421
  copyBtn.addEventListener('click', async (e) => {
313
422
  e.preventDefault();
314
- const installCommand = 'npm install -g @dynamicu/chromedebug-mcp';
423
+ const installCommands = `# Install the server
424
+ npm install -g @dynamicu/chromedebug-mcp
425
+
426
+ # Start the server
427
+ chromedebug-mcp-server`;
315
428
 
316
429
  try {
317
- await navigator.clipboard.writeText(installCommand);
430
+ await navigator.clipboard.writeText(installCommands);
318
431
  const originalText = copyBtn.innerHTML;
319
432
  copyBtn.innerHTML = '✅ Copied!';
320
433
  copyBtn.style.background = '#4CAF50';
@@ -327,7 +440,7 @@ async function checkServerStatus() {
327
440
  console.error('Failed to copy:', err);
328
441
  copyBtn.innerHTML = '❌ Failed';
329
442
  setTimeout(() => {
330
- copyBtn.innerHTML = '📋 Copy Install Command';
443
+ copyBtn.innerHTML = '📋 Copy Commands';
331
444
  }, 2000);
332
445
  }
333
446
  });
@@ -829,6 +942,25 @@ async function initializeLicenseUI() {
829
942
  console.log('[License] Created new user ID:', currentUserId);
830
943
  }
831
944
 
945
+ // Check for license activation file and pre-fill license key
946
+ try {
947
+ const activationFileUrl = chrome.runtime.getURL('license-activation.json');
948
+ const response = await fetch(activationFileUrl);
949
+ if (response.ok) {
950
+ const activationData = await response.json();
951
+ if (activationData.license_key) {
952
+ const licenseKeyInput = document.getElementById('license-key-input');
953
+ if (licenseKeyInput) {
954
+ licenseKeyInput.value = activationData.license_key;
955
+ console.log('[License UI] Pre-filled license key from activation file');
956
+ }
957
+ }
958
+ }
959
+ } catch (error) {
960
+ // Activation file doesn't exist or is inaccessible - this is normal for FREE version
961
+ console.log('[License UI] No activation file found - normal for FREE version');
962
+ }
963
+
832
964
  // Check license status
833
965
  const licenseStatus = await licenseClient.getCachedLicenseStatus();
834
966
  console.log('[License] License status:', licenseStatus);
@@ -878,6 +1010,11 @@ async function handleLicenseActivation() {
878
1010
  messageDiv.style.color = '#2196F3';
879
1011
  console.log('[License] Validating license key...');
880
1012
 
1013
+ // Clear any existing instance ID to force fresh activation
1014
+ // This ensures we don't try to validate with stale/deleted instance IDs
1015
+ await chrome.storage.local.remove(['ls_instance_id']);
1016
+ console.log('[License] Cleared existing instance ID for fresh activation');
1017
+
881
1018
  const result = await licenseClient.validateLicense(licenseKey);
882
1019
  console.log('[License] Validation result:', result);
883
1020
  console.log('[License] Error value:', result.error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamicu/chromedebug-mcp",
3
- "version": "2.5.8",
3
+ "version": "2.5.10",
4
4
  "description": "ChromeDebug MCP - MCP server that provides full control over a Chrome browser instance for debugging and automation with AI assistants like Claude Code",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -49,8 +49,10 @@ const filesToInclude = [
49
49
  'chrome-session-manager.js',
50
50
  'logger.js',
51
51
  'extension-config.js',
52
+ 'upload-manager.js',
52
53
  'firebase-client.js',
53
- 'firebase-config.js',
54
+ { source: 'firebase-config.public.js', target: 'firebase-config.public.js' },
55
+ { source: 'firebase-config.public-sw.js', target: 'firebase-config.js' }, // For service worker importScripts
54
56
  'license-helper.js',
55
57
 
56
58
  // Content scripts (from manifest)
@@ -78,7 +80,6 @@ const filesToInclude = [
78
80
 
79
81
  // Offscreen
80
82
  'offscreen.html',
81
- 'offscreen.js',
82
83
 
83
84
  // Frame capture
84
85
  'frame-capture.js',