This guide shows you how to add visual testing to your AI-assisted coding workflow using the Model Context Protocol (MCP). By the end, you’ll have an AI coding assistant that can capture screenshots, compare them against expected designs, and flag visual regressions automatically—all within your existing editor or CLI. You’ll need a basic understanding of MCP servers and clients, plus a project where visual checks matter.
What You’ll Need
- An MCP-compatible AI coding tool (e.g., Claude Desktop, Cursor, or a custom MCP client)
- Node.js (v18 or later) and npm installed
- A code repository with a web frontend (React, Vue, plain HTML, etc.)
- Playwright or Puppeteer installed in your project (we’ll use Playwright)
- Basic familiarity with JavaScript and terminal commands
Step-by-Step
- Set up a new MCP server project
Create a new directory for your visual testing MCP server. Run
npm init -yto generate a package.json, then install the MCP SDK and Playwright:npm install @modelcontextprotocol/sdk playwright npx playwright install chromiumThis gives you the tools to create an MCP server that can launch a browser.
- Define the server’s tools and resources
Create an
index.jsfile. Import the MCP SDK and set up a server instance. You’ll expose a tool calledcapture_screenshotthat takes a URL and an optional viewport size. Also expose acompare_screenshotstool that takes two image paths and returns a similarity score. Use Playwright to capture the screenshot and a pixel-diff library (likepixelmatch) for comparison. - Implement the screenshot capture logic
Inside the tool handler, launch a headless browser with Playwright, navigate to the given URL, wait for the page to load, and take a screenshot. Save it to a temporary file and return the file path. Make sure to handle dynamic content by waiting for network idle or specific selectors.
async function captureScreenshot(url, viewport) { const browser = await chromium.launch(); const page = await browser.newPage({ viewport }); await page.goto(url, { waitUntil: 'networkidle' }); const path = `screenshots/${Date.now()}.png`; await page.screenshot({ path }); await browser.close(); return path; } - Implement the comparison logic
For comparison, read both image files, use
pixelmatchto compare them, and return the percentage difference. A lower percentage means fewer visual changes. You can also generate a diff image to highlight differences.const diff = pixelmatch(img1, img2, output, width, height, { threshold: 0.1 }); const percentage = (diff / (width * height)) * 100; - Register the tools with the MCP server
Use the MCP SDK’s
Serverclass to register your tools. Define input schemas for each tool—for example,capture_screenshotexpectsurl(string) andviewport(object with width/height). Then start the server and listen for connections.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [{ name: 'capture_screenshot', inputSchema: {...} }] })); - Connect the server to your AI coding client
In your MCP client (e.g., Claude Desktop or Cursor), add a new MCP server configuration pointing to your local server. For Claude Desktop, edit
claude_desktop_config.jsonand add amcpServersentry with the command to run your server:node /path/to/your/index.js. Restart the client. - Test the integration
In your AI chat, ask the assistant to “Take a screenshot of http://localhost:3000” or “Compare current homepage with the baseline.” The AI should invoke your tool and return the screenshot path or diff percentage. Verify the output appears in the chat.
- Incorporate visual tests into your workflow
Create a baseline set of screenshots for key pages. Whenever you make UI changes, ask the AI to run a comparison against the baseline. The AI can then report whether any visual regression occurred. You can also set up a script that runs the MCP server in CI, but for now, focus on interactive use.
Common Mistakes
- Forgetting to install browser binaries – Playwright needs
npx playwright installto download Chromium. Without it, the browser won’t launch. - Hardcoding viewport sizes – Different devices render differently. Always pass viewport as a parameter.
- Not waiting for page load – If you screenshot too early, you’ll capture a blank or partially loaded page. Use
waitUntil: 'networkidle'or wait for specific elements. - Ignoring dynamic content – Animations, carousels, or lazy-loaded images can cause false positives. Consider pausing animations or fixing a test environment.
- Using absolute file paths – The MCP server may run from a different directory. Use relative paths or resolve them based on the project root.
Tips
- Store baseline screenshots in a
__visual_tests__folder and keep them in version control. This makes comparisons reproducible. - Use a threshold parameter in
pixelmatchto ignore minor anti-aliasing differences. A threshold of 0.1–0.2 works well. - Generate a diff image (with red highlighting) so you can visually see what changed. The AI can even describe the diff if you feed the image back.
- For responsive design, capture screenshots at multiple viewports (e.g., 375px, 768px, 1440px) in one go.
- Name your screenshots descriptively, like
home-desktop-baseline.png, so the AI can reference them easily. - If your app requires authentication, use Playwright’s storage state to save cookies and reuse them.
Troubleshooting
MCP client doesn’t show the tool – Check that your server is running and the client’s config points to the correct command. Look for errors in the client’s logs. Ensure the server is using the correct transport (stdio vs HTTP). For local development, stdio is typical.
Browser won’t launch – Run npx playwright install chromium again. If you’re in a restricted environment, you may need to install system dependencies with npx playwright install-deps.
Screenshots look different every time – This is often due to animations, fonts loading late, or dynamic content. Try disabling CSS animations via Playwright’s page.addStyleTag or wait for specific elements to be stable.
Comparison returns 100% difference even for identical pages – Check if the viewport size matches between captures. Also, ensure the page is fully loaded before each capture. Sometimes, a slight scroll position difference causes large diffs—scroll to top before capturing.
Server crashes when handling multiple requests – Make sure you’re not creating a new browser instance for every screenshot without closing it. Reuse a single browser instance and create new pages per request.
AI doesn’t pass the right arguments – If the AI sends the wrong format, your tool schema might be too vague. Provide clear descriptions and examples in the input schema.
Frequently Asked Questions
Can I use this with any MCP client? – Yes, as long as the client supports custom MCP servers. Most modern AI coding tools do.
How do I handle pages that require login? – Use Playwright’s storage state. Log in once, save the state to a file, and load it before each capture.
Is it possible to run this in CI/CD? – Yes, you can run the MCP server in a headless environment, but you’ll need to adapt the flow. Typically, you’d write a script that uses Playwright directly rather than an MCP server.
What if my app uses a lot of animations? – Disable CSS transitions and animations in your test environment. You can inject a style tag that sets * { transition: none !important; animation: none !important; }.
Can I compare screenshots from different browsers? – Yes, but expect some differences due to rendering engines. It’s best to stick to one browser for consistent baselines.
How do I update a baseline after an intentional design change? – Simply replace the baseline image with the new screenshot. You can ask the AI to “update baseline for homepage” and it will overwrite the file.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Campus Tech Innovation Hubs: What They Are
- Poco C51 Airtel Prepaid Locked Variant India?
- Jenkins vs GitHub Actions: Which CI/CD Fits Your Team?
- Turn Off Backup Encryption in iTunes?
- Shared VPS Hosting: Is It Better?
- Disk Defrag Pro: What It Does and Whether You Need It