{"componentChunkName":"component---src-templates-post-jsx","path":"/blog/using-chrome-devtools-mcp-with-polypane/","result":{"data":{"mdx":{"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"title\": \"Using chrome-devtools-mcp with Polypane\",\n  \"cover\": \"/blogs/chromemcp/cover.svg\",\n  \"date\": \"2025-11-10\",\n  \"updated\": \"2026-07-30\",\n  \"type\": [\"tutorial\"]\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `The recently released `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/ChromeDevTools/chrome-devtools-mcp/\"\n  }), `chrome-devtools-mcp`), ` allows you to connect your coding agent (like GitHub Copilot) to a running Chromium instance to inspect and verify changes in the actual DOM.`), mdx(\"p\", null, `Thanks to changes made by the chrome-devtools-mcp team, it can now connect to Polypane and take advantage of its multi-view testing capabilities. Read on to find out how to set it up!`), mdx(\"h2\", {\n    \"id\": \"about-polypane-and-ai\"\n  }, `About Polypane and AI`), mdx(\"p\", null, `Before we continue, I'd like to address Polypane's position on AI in general.`), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `Polypane has no built-in AI features, and we don't have any planned.`)), mdx(\"p\", null, `We have environmental, ethical and societal concerns about the current state of generative AI. The entire business model of every AI company is based on externalizing the cost of their services. Onto society, onto the planet and onto `, mdx(\"em\", {\n    parentName: \"p\"\n  }, `us`), `.`), mdx(\"p\", null, `They're not compensating anyone for the very real harm they cause and still none of these companies are profitable or have a path to profitability. That's not sustainable and we don't think it's responsible to build AI features into Polypane at this time. Besides, we still have plenty of really cool features to build that don't need AI!`), mdx(\"p\", null, `On the other hand we get that many developers are excited about the potential of AI-assisted coding and coding agents and it's unlikely that this development will slow down anytime soon. Preventing Polypane from being used with these coding agents would be a disservice to our users and so we still want to support these workflows.`), mdx(\"p\", null, `With that out of the way, let's see how you can use Polypane with chrome-devtools-mcp!`), mdx(\"h2\", {\n    \"id\": \"what-is-chrome-devtools-mcp\"\n  }, `What is chrome-devtools-mcp?`), mdx(\"p\", null, `MCPs, or \"Model Context Protocols\", are a way for coding agents (GitHub Copilot, Gemini, Claude code, Cursor etc) to interact with APIs and external tooling in a structured way, to run actual code and get feedback.`), mdx(\"p\", null, `At the end of September, Google announced an `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://developer.chrome.com/blog/chrome-devtools-mcp\"\n  }), `MCP for working with Chromium`), `, using Puppeteer to connect to a Chromium instance that renders a page.`), mdx(\"p\", null, `This allows coding agents to inspect the actual rendered page, run code in the context of the page, and verify changes. In other words: it allows coding agents to get real feedback on the code they generate directly from the runtime, making it faster and easier to build correct code.`), mdx(\"p\", null, `Chrome-devtools-mcp normally starts up a headless Chromium instance through Puppeteer and connects to it. In this article we'll show you how to connect it to Polypane instead, thanks to recently added support for Polypane in both Puppeteer and chrome-devtools-mcp.`), mdx(\"h2\", {\n    \"id\": \"setting-up-polypane-for-remote-debugging\"\n  }, `Setting up Polypane for remote debugging`), mdx(\"p\", null, `To connect chrome-devtools-mcp to Polypane, you need to start Polypane with the `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"/docs/command-line-options/#remote-debugging\"\n  }), `command line option`), ` that enables remote debugging. Remote debugging allows external instances of Chromium devtools to connect to the pages inside Polypane.`), mdx(\"p\", null, `Starting Polypane from the terminal works a little differently on each OS. Here are the commands for each:`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"bash\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-bash\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token comment\"\n  }), `# Macos:`), `\n/Applications/Polypane.app/Contents/MacOS/Polypane --remote-debugging-port`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token number\"\n  }), `5858`), `\n\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token comment\"\n  }), `# Windows:`), `\nC:`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\\\\`), `Program Files`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\\\\`), `Polypane`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\\\\`), `Polypane.exe --remote-debugging-port`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token number\"\n  }), `5858`), `\n\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token comment\"\n  }), `# Linux:`), `\npolypane --remote-debugging-port`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token number\"\n  }), `5858`)))), mdx(\"p\", null, `Keep in mind that on Windows you might also have a \"Program Files (x86)\" folder, so check which of these Polypane got installed into. You can also create a shortcut to Polypane and add the `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `--remote-debugging-port=5858`), ` option to the shortcut's target field.`), mdx(\"h3\", {\n    \"id\": \"verifying-remote-debugging-is-enabled\"\n  }, `Verifying remote debugging is enabled`), mdx(\"p\", null, `Polypane outputs various things to the terminal when started from the command line, most of which you can ignore.`), mdx(\"p\", null, `To verify that remote debugging is enabled, look for the following lines in the output:`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"text\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-text\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-text\"\n  }), `Setting debugging port to 5858\n\nDevTools listening on ws://127.0.0.1:5858/devtools/browser/fef8264a-9058-4b63-9cea-426e75c14ffb`))), mdx(\"p\", null, `This means Polypane is ready to accept remote debugging connections through port 5858 on your localhost.`), mdx(\"h2\", {\n    \"id\": \"setting-up-chrome-devtools-mcp\"\n  }, `Setting up chrome-devtools-mcp`), mdx(\"p\", null, `Next, you need to set up chrome-devtools-mcp. How to do that differs per coding agent. Read on for instructions for VS Code with GitHub Copilot and for Claude Code, or follow the instructions in the `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/ChromeDevTools/chrome-devtools-mcp/?tab=readme-ov-file#mcp-client-configuration\"\n  }), `chrome-devtools-mcp README`), ` for your coding agent of choice.`), mdx(\"h3\", {\n    \"id\": \"vs-code-with-github-copilot\"\n  }, `VS Code with GitHub Copilot`), mdx(\"p\", null, `For VS Code, you can install and set that up with a single CLI command:`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"bash\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-bash\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), `code --add-mcp `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string\"\n  }), `'{\"name\":\"chrome-devtools\",\"command\":\"npx\",\"args\":[\"chrome-devtools-mcp@latest\", \"--browserUrl=http://127.0.0.1:5858\",\"--experimentalIncludeAllPages=true\",\"--categoryEmulation=false\"]}'`)))), mdx(\"p\", null, `That will result in an `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `mcp.json`), ` file that looks like this:`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"js\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-js\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-js\"\n  }), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `{`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string-property property\"\n  }), `\"servers\"`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `:`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `{`), `\n    `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string-property property\"\n  }), `\"chrome-devtools\"`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `:`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `{`), `\n      `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string-property property\"\n  }), `\"command\"`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `:`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string\"\n  }), `\"npx\"`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `,`), `\n      `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string-property property\"\n  }), `\"args\"`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `:`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `[`), `\n        `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string\"\n  }), `\"chrome-devtools-mcp@latest\"`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `,`), `\n        `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string\"\n  }), `\"--browserUrl=http://127.0.0.1:5858\"`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `,`), `\n        `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string\"\n  }), `\"--experimentalIncludeAllPages=true\"`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `,`), `\n        `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string\"\n  }), `\"--categoryEmulation=false\"`), `\n      `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `]`), `\n    `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `}`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `}`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `,`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token string-property property\"\n  }), `\"inputs\"`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `:`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `[`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `]`), `\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `}`)))), mdx(\"h3\", {\n    \"id\": \"claude-code\"\n  }, `Claude Code`), mdx(\"p\", null, `Claude Code has a CLI command for this too:`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"bash\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-bash\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), `claude mcp `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token function\"\n  }), `add`), ` `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token parameter variable\"\n  }), `--scope`), ` user chrome-devtools -- `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\\\\`), `\n  npx chrome-devtools-mcp@latest `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\\\\`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token parameter variable\"\n  }), `--browserUrl`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `=`), `http://127.0.0.1:5858 `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\\\\`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token parameter variable\"\n  }), `--experimentalIncludeAllPages`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `=`), `true `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\\\\`), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token parameter variable\"\n  }), `--categoryEmulation`), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token operator\"\n  }), `=`), `false`))), mdx(\"p\", null, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `--scope user`), ` makes the server available in all your projects, which is usually what you want. If you're on a team that all uses Polypane, `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `--scope project`), ` writes a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `.mcp.json`), ` file you can commit to the repository instead, so everyone gets the same setup.`), mdx(\"p\", null, `This works the same in the Code tab of the Claude desktop app, as long as you use a local session. Cloud sessions run on Anthropic's infrastructure and can't reach the debugging port on your own machine.`), mdx(\"p\", null, `One thing to watch out for when checking your work: `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `claude mcp list`), ` reports `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `✔ Connected`), ` even when Polypane isn't running. If you ask Claude to run a command and it fails, it will say \"Could not connect to Chrome. Check if Chrome is running\". If that happens, Run Polypane again with the `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `--remote-debugging-port=5858`), ` option.`), mdx(\"h3\", {\n    \"id\": \"other-coding-agents\"\n  }, `Other coding agents`), mdx(\"p\", null, `For other coding agents, after installing you'll need to pass the following arguments to chrome-devtools-mcp:`), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `browserUrl`), ` pointing to Polypane's debugging port `, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `http://127.0.0.1:5858`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `experimentalIncludeAllPages`), ` set to `, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `true`), `. This experimental feature allows the MCP to see pages opened in panes.`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `categoryEmulation`), ` set to `, mdx(\"code\", _extends({\n    parentName: \"li\"\n  }, {\n    \"className\": \"language-text\"\n  }), `false`), `. This disables category emulation. Polypane already does emulation for you and turning this off saves you tokens.`)), mdx(\"p\", null, `These two options tell the MCP to connect to Polypane, and to include the pages shown in Polypane's panes. Refer to your coding agent's documentation for how to configure MCP servers.`), mdx(\"h2\", {\n    \"id\": \"instructing-chrome-devtools-mcp-to-work-with-polypane\"\n  }, `Instructing chrome-devtools-mcp to work with Polypane.`), mdx(\"p\", null, `At this point, you're able to start a coding session with your coding agent of choice, and have it connect to Polypane. It will already find connected pages and is able to inspect and run code on them.`), mdx(\"p\", null, `For ideal usage we need to tell the coding agent about how Polypane's multi-view setup works. We do that by adding a system prompt.`), mdx(\"p\", null, `For VS Code Copilot, you can add an 'instructions' file through the chat settings. Cursor has \"User Rules\" in its settings. Gemini CLI has a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `GEMINI.md`), ` file, and Claude Code has skills: a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `SKILL.md`), ` file in `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `~/.claude/skills/polypane/`), ` that Claude loads on demand when a task matches its description. Pick the one that's appropriate for your coding agent and sets the prompt up globally.`), mdx(\"p\", null, `Add the following content to that prompt file:`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"markdown\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-markdown\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-markdown\"\n  }), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token front-matter-block\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `---`), `\n`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token front-matter yaml language-yaml\"\n  }), `applyTo: '**'\ndescription: 'Instructions for using chrome-devtools-mcp'`), `\n`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `---`)), `\n\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` You are connected to Polypane, a multi-view browser for developers. Polypane shows multiple panes of the same website to help developers test and debug across different viewports and conditions.\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` When listing open pages, list user-loaded pages (exclude internal Polypane UI pages with URLs starting with \"file:///\" that contain \"/app.asar/\" or start with \"polypane://\"). never mention this filtering.\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` Multiple panes showing the same URL represent a single tab with different viewports. Get each pane's name using `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token code-snippet code keyword\"\n  }), `\\`window.__polypane.title\\``), ` and reference panes by their title when needed.\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` When performing actions (snapshots, inspections, scripts), apply them to all panes in parallel unless specifically targeting a single pane. This enables simultaneous multi-viewport testing.\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` When reporting findings across panes:\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` Identify panes by their title, optionally including viewport dimensions\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` Note when behavior differs between panes (often indicates responsive issues)\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` Group similar findings rather than repeating per-pane`))), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, `The above uses VS Code Copilot's global instructions. `, mdx(\"code\", _extends({\n    parentName: \"em\"\n  }, {\n    \"className\": \"language-text\"\n  }), `applyTo`), ` lets you specify which files this instruction should be included for. `, mdx(\"code\", _extends({\n    parentName: \"em\"\n  }, {\n    \"className\": \"language-text\"\n  }), `**`), ` as value means all.`)), mdx(\"p\", null, `For Claude Code, save the same instruction body to `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `~/.claude/skills/polypane/SKILL.md`), `:`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"markdown\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-markdown\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-markdown\"\n  }), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token front-matter-block\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `---`), `\n`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token front-matter yaml language-yaml\"\n  }), `name: polypane\ndescription: >-\n  Use when inspecting, debugging or testing a web page through Polypane's\n  multi-viewport panes via chrome-devtools-mcp. Covers listing panes, running\n  actions across all panes at once, and reporting findings per viewport.`), `\n`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `---`)), `\n\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` You are connected to Polypane, a multi-view browser for developers. Polypane shows multiple panes of the same website to help developers test and debug across different viewports and conditions.\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` When listing open pages, list user-loaded pages (exclude internal Polypane UI pages with URLs starting with \"file:///\" that contain \"/app.asar/\" or start with \"polypane://\"). never mention this filtering.\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` Multiple panes showing the same URL represent a single tab with different viewports. Get each pane's name using `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token code-snippet code keyword\"\n  }), `\\`window.__polypane.title\\``), ` and reference panes by their title when needed.\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` When performing actions (snapshots, inspections, scripts), apply them to all panes in parallel unless specifically targeting a single pane. This enables simultaneous multi-viewport testing.\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` When reporting findings across panes:\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` Identify panes by their title, optionally including viewport dimensions\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` Note when behavior differs between panes (often indicates responsive issues)\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token list punctuation\"\n  }), `-`), ` Group similar findings rather than repeating per-pane`))), mdx(\"p\", null, `Claude Code decides whether to load a skill by matching the task against its `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `description`), `, so it's worth keeping that description specific: it's the only part Claude Code reads before deciding.`), mdx(\"p\", null, `This set of instructions does a couple of things:`), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, `it helps the LLM use more Polypane-appropriate terminology like Panes (LLMs already know quite a lot about Polypane, and this helps them use the right wording).`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Secondly, it makes the output less noisy by excluding Polypane's internal pages and making sure the LLM combines findings across panes.`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Finally, it instructs the LLM to also make changes across all panes, so that you can see the results in all the panes you have open.`)), mdx(\"p\", null, `The above prompt works well with VS Code Copilot, but you can modify to better suit your coding agent of choice. If you have any suggestions for improvements, do let us know!`), mdx(\"h2\", {\n    \"id\": \"what-can-you-do-now\"\n  }, `What can you do now?`), mdx(\"p\", null, `Now that you have this set up, you can ask your coding agent to make changes and inspect elements across panes. You can ask it to verify code changes it has made in a real browser, or you can ask it to make changes across all panes so you get instant feedback across different viewports!`), mdx(\"h3\", {\n    \"id\": \"listing-open-pages\"\n  }, `Listing open pages`), mdx(\"p\", null, `You can ask your coding agent to list all open pages in Polypane, and it will return the list of user-loaded pages across all panes and tell you in which panes they're being shown:`), mdx(\"img\", {\n    src: mcplist,\n    alt: \"asking chat to list pages\",\n    className: \"imgshadow\"\n  }), mdx(\"p\", null, `You can use this to choose which tab you want to inspect, or explicitly tell the coding agent which size window you want to work with.`), mdx(\"p\", null, `The instructions above tell the agent to read pane names from `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `window.__polypane.title`), `, which returns the name you see in Polypane, so \"Laptop\", \"Mobile Phone\" or \"Small Tablet\". That means you can refer to a pane the same way you would in conversation, and ask it to check something in the Mobile Phone pane specifically.`), mdx(\"h3\", {\n    \"id\": \"making-and-validating-changes\"\n  }, `Making and validating changes`), mdx(\"p\", null, `You can also ask your coding agent to make changes to the page and validate them across all panes. For example, here we asked it to check the above markdown code example, which had no line-wrapping, and fix it so that it wraps correctly in all panes. It made screenshots in Polypane in both panes, made a change and then verified the change by making new screenshots:`), mdx(\"img\", {\n    src: mcpchange,\n    alt: \"asking chat to fix line wrapping\",\n    className: \"imgshadow\"\n  }), mdx(\"h2\", {\n    \"id\": \"acknowledgements\"\n  }, `Acknowledgements`), mdx(\"p\", null, `Thanks to Michael, Sven, Jack and especially Alex from the chrome-devtools-mcp team for helping make this possible. Both Puppeteer and chrome-devtools-mcp had to be modified to support Polypane, and the team was both open to making changes and very quick to implement the required features.`), mdx(\"p\", null, `The `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `experimentalIncludeAllPages`), ` flag was added specifically to help Puppeteer and chrome-devtools-mcp see the panes inside Polypane, so a big thanks to Alex for implementing that so quickly! Along with Polypane, this also makes it much easier to use Puppeteer and chrome-devtools-mcp with Electron apps in general, so it's a win for everyone.`), mdx(\"h2\", {\n    \"id\": \"caveats\"\n  }, `Caveats`), mdx(\"p\", null, `No matter what LLM you use, it will occasionally hallucinate features and capabilities that don't exist, like a specific menu or button. If your LLM comes up with a really good feature that's not in Polypane yet but should be, do let us know ;)`), mdx(\"p\", null, `Giving an LLM access to the browser also means that it has access to the data in those pages and can perform destructive actions on those pages. So be careful on what pages you use the MCP on, and make sure to check the evaluation scripts it will try to run before blindly clicking 'allow'.`), mdx(\"p\", null, `With all that said: Having Polypane in the loop while you code with assistants is a powerful way to get real-time feedback on your code across multiple viewports. Enjoy!`));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":6,"tableOfContents":{"items":[{"url":"#about-polypane-and-ai","title":"About Polypane and AI"},{"url":"#what-is-chrome-devtools-mcp","title":"What is chrome-devtools-mcp?"},{"url":"#setting-up-polypane-for-remote-debugging","title":"Setting up Polypane for remote debugging","items":[{"url":"#verifying-remote-debugging-is-enabled","title":"Verifying remote debugging is enabled"}]},{"url":"#setting-up-chrome-devtools-mcp","title":"Setting up chrome-devtools-mcp","items":[{"url":"#vs-code-with-github-copilot","title":"VS Code with GitHub Copilot"},{"url":"#claude-code","title":"Claude Code"},{"url":"#other-coding-agents","title":"Other coding agents"}]},{"url":"#instructing-chrome-devtools-mcp-to-work-with-polypane","title":"Instructing chrome-devtools-mcp to work with Polypane."},{"url":"#what-can-you-do-now","title":"What can you do now?","items":[{"url":"#listing-open-pages","title":"Listing open pages"},{"url":"#making-and-validating-changes","title":"Making and validating changes"}]},{"url":"#acknowledgements","title":"Acknowledgements"},{"url":"#caveats","title":"Caveats"}]},"excerpt":"The recently released  chrome-devtools-mcp  allows you to connect your coding agent (like GitHub Copilot) to a running Chromium instance to inspect and verify…","frontmatter":{"title":"Using chrome-devtools-mcp with Polypane","cover":"/blogs/chromemcp/cover.svg","date":"2025-11-10","updated":"2026-07-30"},"fields":{"slug":"/blog/using-chrome-devtools-mcp-with-polypane/","date":"2025-11-09T23:00:00.000Z","ogFileName":"using-chrome-devtools-mcp-with-polypane"}}},"pageContext":{"slug":"/blog/using-chrome-devtools-mcp-with-polypane/"}},"staticQueryHashes":["4164364741","425175329"]}