browser-lens-mcp 2.1.0 → 2.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/README.md CHANGED
@@ -290,34 +290,58 @@ Works with **any design tool** — Figma, Sketch, Adobe XD, Zeplin. Just provide
290
290
 
291
291
  ---
292
292
 
293
- ## MCP Prompts (5)
293
+ ## MCP Prompts (5) — `/` Commands in IDE
294
294
 
295
- | Prompt | Description |
296
- |--------|-------------|
297
- | `compare_with_figma` | Guided Figma comparison workflow |
298
- | `audit_ui` | Comprehensive UI audit |
299
- | `describe_page` | Detailed page description |
300
- | `suggest_fixes` | Prioritized fix list |
301
- | `visual_qa` | Visual QA pass/fail report |
295
+ Type `/` in your IDE chat to see these guided workflows:
296
+
297
+ | Prompt | When to Use | What It Does |
298
+ |--------|-------------|-------------|
299
+ | `/compare_with_figma` | After implementing a UI from Figma | Walks through comparing each element, generates CSS fixes |
300
+ | `/audit_ui` | Before PR review or release | Audits colors, typography, spacing, accessibility — rates 1-10 |
301
+ | `/describe_page` | When you need to explain the current UI to AI | Generates detailed page description with structure, styles, elements |
302
+ | `/suggest_fixes` | After running comparisons | Collects all failing comparisons + a11y issues → prioritized fix list |
303
+ | `/visual_qa` | Final check before shipping | Takes screenshot, compares elements, outputs PASS/NEEDS_WORK/FAIL |
304
+
305
+ **Example usage in Antigravity/Cursor:**
306
+ ```
307
+ /compare_with_figma
308
+ → AI reads current page data, asks for Figma specs, runs comparisons, suggests fixes
309
+
310
+ /audit_ui
311
+ → AI analyzes colors (too many?), typography (consistent?), spacing (scale?), a11y (issues?)
312
+ ```
302
313
 
303
314
  ---
304
315
 
305
- ## MCP Resources (12)
306
-
307
- | URI | Description |
308
- |-----|-------------|
309
- | `dom://snapshot` | Full DOM tree |
310
- | `dom://elements` | Element selectors |
311
- | `dom://mutations` | DOM changes |
312
- | `css://variables` | Custom properties |
313
- | `css://typography` | Font analysis |
314
- | `css://colors` | Color palette |
315
- | `layout://responsive` | Viewport info |
316
- | `layout://spacing` | Spacing analysis |
317
- | `visual://screenshots` | Screenshot metadata |
318
- | `a11y://audit` | Accessibility audit |
319
- | `figma://comparisons` | Comparison results |
320
- | `browser://page` | Page info |
316
+ ## MCP Resources (12) — `@` References in IDE
317
+
318
+ Type `@mcp:browser-lens/` in your IDE to access these data sources directly:
319
+
320
+ | Resource | Shorthand | When to Use | Example |
321
+ |----------|-----------|-------------|---------|
322
+ | `dom://snapshot` | `@browser-lens/dom-snapshot` | Get the full DOM tree structure | "Show me the page structure" |
323
+ | `dom://elements` | `@browser-lens/dom-elements` | List all captured element selectors | "What elements are captured?" |
324
+ | `dom://mutations` | `@browser-lens/mutations-log` | Check recent DOM changes | "What changed since last sync?" |
325
+ | `css://variables` | `@browser-lens/css-variables` | Get all CSS custom properties | "What design tokens exist?" |
326
+ | `css://typography` | `@browser-lens/css-typography` | Get font usage analysis | "What fonts are used?" |
327
+ | `css://colors` | `@browser-lens/css-colors` | Get color palette | "What colors are on this page?" |
328
+ | `layout://responsive` | `@browser-lens/layout-responsive` | Get viewport & breakpoints | "What breakpoint is active?" |
329
+ | `layout://spacing` | `@browser-lens/layout-spacing` | Get spacing analysis | "Is spacing consistent?" |
330
+ | `visual://screenshots` | `@browser-lens/visual-screenshots` | List captured screenshots | "How many screenshots exist?" |
331
+ | `a11y://audit` | `@browser-lens/accessibility-info` | Get accessibility audit | "Any a11y issues?" |
332
+ | `figma://comparisons` | `@browser-lens/comparison-results` | Get comparison results | "How did the last comparison go?" |
333
+ | `browser://page` | `@browser-lens/page-info` | Get page info summary | "Is browser connected?" |
334
+
335
+ **Example usage:**
336
+ ```
337
+ @browser-lens/css-colors Tell me the primary colors used on this page
338
+ @browser-lens/dom-snapshot Show me the semantic structure
339
+ @browser-lens/accessibility-info Are there any accessibility issues?
340
+ ```
341
+
342
+ **Resources vs Tools:**
343
+ - **Resources** (`@`) = Read-only data snapshots. Fast, no browser command needed. Use for quick lookups.
344
+ - **Tools** = Actions that can query the browser live, take screenshots, compare with Figma. Use for interactive work.
321
345
 
322
346
  ---
323
347
 
@@ -334,11 +358,13 @@ IDE ← MCP Server ← WebSocket ← Send result
334
358
  ```
335
359
 
336
360
  **Commands the server can send to the browser:**
337
- - `screenshot` — Capture and send a fresh screenshot
361
+ - `screenshot` — Capture viewport screenshot (cross-origin images auto-replaced with placeholders)
362
+ - `element_screenshot` — Capture a specific element by CSS selector
338
363
  - `query_element` — Inspect any element by CSS selector on-demand
339
364
  - `fullsync` — Trigger a full data re-capture
340
365
 
341
- This means your AI agent can ask about ANY element, even ones not in the initial auto-capture.
366
+ **Screenshot CORS handling:**
367
+ Cross-origin images (CDN logos, external assets) are temporarily replaced with same-size grey placeholders before capture, then restored. This ensures screenshots always succeed while preserving layout accuracy.
342
368
 
343
369
  ---
344
370
 
@@ -1 +1 @@
1
- {"version":3,"file":"connector-script.d.ts","sourceRoot":"","sources":["../../../src/transport/connector-script.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA2a3E"}
1
+ {"version":3,"file":"connector-script.d.ts","sourceRoot":"","sources":["../../../src/transport/connector-script.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAqa3E"}
@@ -221,47 +221,62 @@ function captureSpacing(){
221
221
  return{timestamp:Date.now(),elements:entries,inconsistencies:[],spacingScale:Object.keys(Object.assign({},vals.margin,vals.padding)).sort(function(a,b){return parseFloat(a)-parseFloat(b)})};
222
222
  }
223
223
 
224
- var _ssLastOk=0,_ssFailing=false,_ssAttempts=0;
225
224
  function _safeExport(canvas){
226
225
  try{return canvas.toDataURL('image/png');}
227
226
  catch(e){return null;}
228
227
  }
229
- function _doCapture(opts){
230
- var w=Math.min(window.innerWidth,1440),h=Math.min(window.innerHeight,900);
231
- return html2canvas(document.body,Object.assign({scale:1,width:w,height:h,logging:false,removeContainer:true,imageTimeout:5000},opts)).then(function(canvas){
228
+
229
+ function _neutralizeCrossOrigin(root){
230
+ var originals=[];
231
+ root.querySelectorAll('img').forEach(function(img){
232
+ var src=img.src||'';
233
+ if(src&&!src.startsWith(location.origin)&&!src.startsWith('data:')&&!src.startsWith('blob:')){
234
+ var w=img.naturalWidth||img.offsetWidth||100;
235
+ var h=img.naturalHeight||img.offsetHeight||100;
236
+ originals.push({el:img,src:img.src,srcset:img.srcset||''});
237
+ img.srcset='';
238
+ img.src='data:image/svg+xml,'+encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="'+w+'" height="'+h+'"><rect width="100%" height="100%" fill="%2327272a"/><text x="50%" y="50%" fill="%2371717a" font-size="12" text-anchor="middle" dominant-baseline="middle">img</text></svg>');
239
+ }
240
+ });
241
+ root.querySelectorAll('iframe,video').forEach(function(el){
242
+ originals.push({el:el,vis:el.style.visibility});
243
+ el.style.visibility='hidden';
244
+ });
245
+ return originals;
246
+ }
247
+
248
+ function _restoreCrossOrigin(originals){
249
+ originals.forEach(function(o){
250
+ if(o.src!==undefined){o.el.src=o.src;if(o.srcset)o.el.srcset=o.srcset;}
251
+ if(o.vis!==undefined)o.el.style.visibility=o.vis;
252
+ });
253
+ }
254
+
255
+ function _renderScreenshot(target,type,selector){
256
+ var saved=_neutralizeCrossOrigin(target);
257
+ var w=target===document.body?Math.min(window.innerWidth,1440):undefined;
258
+ var h=target===document.body?Math.min(window.innerHeight,900):undefined;
259
+ var opts={scale:1,logging:false,removeContainer:true,imageTimeout:3000,useCORS:false,allowTaint:false,foreignObjectRendering:false};
260
+ if(w)opts.width=w;
261
+ if(h)opts.height=h;
262
+ return html2canvas(target,opts).then(function(canvas){
263
+ _restoreCrossOrigin(saved);
232
264
  var dataUrl=_safeExport(canvas);
233
- if(!dataUrl)throw new Error('Canvas tainted - toDataURL blocked');
234
- _ssLastOk=Date.now();_ssFailing=false;_ssAttempts=0;
235
- log('Screenshot OK: '+canvas.width+'x'+canvas.height);
236
- return{timestamp:Date.now(),type:'viewport',width:canvas.width,height:canvas.height,dataUrl:dataUrl,format:'png'};
265
+ if(!dataUrl){_restoreCrossOrigin(saved);return null;}
266
+ var result={timestamp:Date.now(),type:type||'viewport',width:canvas.width,height:canvas.height,dataUrl:dataUrl,format:'png'};
267
+ if(selector)result.selector=selector;
268
+ log('Screenshot OK: '+(selector||'viewport')+' '+canvas.width+'x'+canvas.height);
269
+ return result;
270
+ }).catch(function(e){
271
+ _restoreCrossOrigin(saved);
272
+ err('html2canvas render failed',e);
273
+ return null;
237
274
  });
238
275
  }
276
+
239
277
  function captureScreenshot(){
240
- if(_ssFailing&&_ssAttempts>2&&Date.now()-_ssLastOk<300000)return Promise.resolve(null);
241
- _ssAttempts++;
242
278
  return new Promise(function(resolve){
243
- function attempt3(){
244
- log('Attempt 3: minimal capture without images/videos/iframes...');
245
- _doCapture({useCORS:false,allowTaint:false,foreignObjectRendering:false,ignoreElements:function(el){
246
- var t=el.tagName;return t==='IMG'||t==='VIDEO'||t==='IFRAME'||t==='CANVAS'||t==='SVG';
247
- }}).then(resolve).catch(function(e){
248
- _ssFailing=true;
249
- log('All screenshot attempts failed. Will retry in 5min.');
250
- resolve(null);
251
- });
252
- }
253
- function attempt2(){
254
- log('Attempt 2: without cross-origin images...');
255
- _doCapture({useCORS:false,allowTaint:false,foreignObjectRendering:false,ignoreElements:function(el){
256
- if(el.tagName==='IMG'){var s=el.src||'';if(s&&!s.startsWith(location.origin)&&!s.startsWith('data:'))return true;}
257
- if(el.tagName==='IFRAME'||el.tagName==='VIDEO')return true;
258
- return false;
259
- }}).then(resolve).catch(attempt3);
260
- }
261
- function attempt1(){
262
- _doCapture({useCORS:true,allowTaint:false,foreignObjectRendering:false}).then(resolve).catch(attempt2);
263
- }
264
- function run(){try{attempt1();}catch(e){resolve(null);}}
279
+ function run(){_renderScreenshot(document.body,'viewport').then(resolve);}
265
280
  try{
266
281
  if(typeof html2canvas==='function'){run();}
267
282
  else{
@@ -336,33 +351,12 @@ function captureElementScreenshot(selector){
336
351
  return new Promise(function(resolve){
337
352
  var el=document.querySelector(selector);
338
353
  if(!el){resolve(null);return;}
339
- function doCapture(){
340
- var rect=el.getBoundingClientRect();
341
- var opts={scale:1,logging:false,removeContainer:true,imageTimeout:5000,
342
- x:rect.left+window.scrollX,y:rect.top+window.scrollY,
343
- width:Math.ceil(rect.width),height:Math.ceil(rect.height),
344
- windowWidth:document.documentElement.scrollWidth,
345
- windowHeight:document.documentElement.scrollHeight,
346
- useCORS:true,allowTaint:false,foreignObjectRendering:false};
347
- html2canvas(el,{scale:1,logging:false,removeContainer:true,imageTimeout:5000,useCORS:true,allowTaint:false,foreignObjectRendering:false}).then(function(canvas){
348
- var dataUrl=_safeExport(canvas);
349
- if(dataUrl){
350
- log('Element screenshot OK: '+selector+' '+canvas.width+'x'+canvas.height);
351
- resolve({timestamp:Date.now(),type:'element',selector:selector,width:canvas.width,height:canvas.height,dataUrl:dataUrl,format:'png'});
352
- }else{
353
- html2canvas(el,{scale:1,logging:false,removeContainer:true,useCORS:false,allowTaint:false,foreignObjectRendering:false,ignoreElements:function(e){var t=e.tagName;return t==='IMG'||t==='VIDEO'||t==='IFRAME'||t==='CANVAS';}}).then(function(c2){
354
- var d2=_safeExport(c2);
355
- if(d2)resolve({timestamp:Date.now(),type:'element',selector:selector,width:c2.width,height:c2.height,dataUrl:d2,format:'png'});
356
- else resolve(null);
357
- }).catch(function(){resolve(null);});
358
- }
359
- }).catch(function(){resolve(null);});
360
- }
361
- if(typeof html2canvas==='function'){doCapture();}
354
+ function run(){_renderScreenshot(el,'element',selector).then(resolve);}
355
+ if(typeof html2canvas==='function'){run();}
362
356
  else{
363
357
  var s=document.createElement('script');
364
358
  s.src='https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js';
365
- s.onload=doCapture;s.onerror=function(){resolve(null);};
359
+ s.onload=run;s.onerror=function(){resolve(null);};
366
360
  document.head.appendChild(s);
367
361
  }
368
362
  });
@@ -1 +1 @@
1
- {"version":3,"file":"connector-script.js","sourceRoot":"","sources":["../../../src/transport/connector-script.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,MAAc;IACjE,OAAO;;;+BAGsB,MAAM;mCACF,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqatC,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"connector-script.js","sourceRoot":"","sources":["../../../src/transport/connector-script.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,MAAc;IACjE,OAAO;;;+BAGsB,MAAM;mCACF,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+ZtC,CAAC;AACN,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-lens-mcp",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "MCP server that connects to your browser for real-time DOM, CSS, layout inspection, screenshot capture, and Figma design comparison — your IDE's AI agent sees exactly what users see",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",