screenshot-vision-mcp
Allows capturing screenshots of Google Chrome windows and analyzing them with a local vision model, including locating UI elements and returning click coordinates.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@screenshot-vision-mcpWhat does the example.com landing page look like?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
screenshot-vision-mcp
When reviewing a PR locally, you need to see if the UI looks right. Normally that means Claude takes a screenshot — which burns vision tokens and sends your screen contents to Anthropic. This MCP server routes screenshots through a local Ollama vision model instead: zero token cost, nothing leaves your machine.
Tool | When to use |
| Public or local URLs — headless browser, no session needed |
| Any app window on screen — sees your real logged-in session |
| Native macOS apps only — returns click coordinates without Claude seeing the image |
Chrome automation: for clicking elements in Chrome, prefer
javascript_tool + getBoundingClientRect— it's exact and requires no vision at all. See Clicking in Chrome.
Requirements
macOS (window capture uses
screencaptureand AppleScript)Node.js 22+
Ollama installed (the server auto-starts it if it isn't running)
A multimodal Ollama model — default is
gemma4:e4b:ollama pull gemma4:e4b
Related MCP server: Screen Vision MCP Server
Installation
git clone git@github.com:AVS845/screenshot-vision-mcp.git
cd screenshot-vision-mcp
npm install
npx playwright install chromium
npm run buildClaude Code configuration
Add this to your ~/.claude/settings.json under mcpServers:
{
"mcpServers": {
"screenshot-vision": {
"command": "node",
"args": ["/absolute/path/to/screenshot-vision-mcp/dist/index.js"]
}
}
}Replace /absolute/path/to/ with the actual path. Then restart Claude Code.
Two optional env vars let you configure the server without touching call sites:
Variable | Default | Description |
|
| Ollama host |
|
| Default vision model for all tools |
Tools
analyze_screenshot
Takes a screenshot of a URL in a headless Playwright browser and analyzes it with Ollama.
analyze_screenshot(
url: "http://localhost:3004/dashboard",
question: "Does the revenue chart render correctly? Are there any layout issues?"
)Parameter | Type | Default | Description |
| string | — | URL to screenshot |
| string | — | What to analyze |
| string |
| Ollama vision model |
| number |
| Viewport width in px |
| number |
| Viewport height in px |
| number |
| Wait after page load (ms) |
| boolean |
| Capture full page height, not just the visible viewport |
| number |
| Max slices when |
When full_page: true, the page is sliced into viewport_height-tall segments and sent as multiple images. This matters because Gemma 4's image token budget is ~280 tokens — a single tall screenshot gets crushed into noise, while properly-proportioned slices each get full detail.
capture_window
Captures an app window currently on screen and analyzes it. Use this when the page requires a login — it sees your real browser session.
capture_window(
app_name: "Google Chrome",
question: "Is the form validation error displaying correctly under the email field?"
)Parameter | Type | Default | Description |
| string | — | Exact macOS app name, e.g. |
| string | — | What to analyze |
| string |
| Ollama vision model |
| number |
| Which window (1 = frontmost) |
| number |
| Upscale factor (2–3 helps with small text) |
| object | — | Crop to a sub-region before analysis |
The crop parameter uses fractional values (0–1). To inspect just the bottom half of the window:
{ "x": 0, "y": 0.5, "width": 1, "height": 0.5 }locate_element
Finds a UI element in a native macOS app window and returns its click coordinates. Designed for apps where DOM access isn't available — Terminal, Figma, Xcode, etc.
Not recommended for Chrome. Chrome's DOM gives exact coordinates with no vision model involved. See Clicking in Chrome.
Parameter | Type | Default | Description |
| string | — | Exact macOS app name, e.g. |
| string | — | Natural language description of the element |
| string |
| Ollama vision model |
| number |
| Which window (1 = frontmost) |
| object | — | Screen-coordinate bounds of the region to capture |
Returns { x, y, coordinate_mode, clamped }. clamped: true means the model returned out-of-range coordinates that were corrected — treat as low confidence.
Accuracy note: gemma4:e4b has a ~280-token image budget, which limits spatial precision. Elements in the center of the screen locate reliably; elements near edges may have 50–150px errors. Use a larger model (e.g. gemma4:26b) if precision matters, at the cost of slower inference.
Clicking in Chrome
For Chrome browser automation, skip locate_element entirely. Use javascript_tool to get exact coordinates from the DOM:
// In javascript_tool — returns perfect viewport coordinates, no vision needed
const el = document.querySelector('button.submit');
const r = el.getBoundingClientRect();
JSON.stringify({ x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) });Only fall back to locate_element for elements that genuinely can't be DOM-queried (canvas content, rendered images, visually-composed widgets without CSS selectors). When you do, pass viewport_bounds so the returned coordinates are viewport-relative and work directly with the Chrome computer tool.
Measure viewport bounds immediately before the call — the Chrome automation InfoBar shifts innerHeight, causing ~40px errors with stale bounds:
// javascript_tool — run right before locate_element
JSON.stringify({
screenX: window.screenX,
screenY: window.screenY,
outerHeight: window.outerHeight,
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
})locate_element(
app_name: "Google Chrome",
element_description: "the close button on the confirmation modal",
viewport_bounds: {
x: screenX,
y: screenY + outerHeight - innerHeight,
width: innerWidth,
height: innerHeight,
}
)
→ { x: 891, y: 267, coordinate_mode: "viewport" }How it works
analyze_screenshotlaunches a headless Chromium browser via Playwright, navigates to the URL, waits for JS to settle, and captures a PNG.capture_windowuses AppleScript to get the window bounds,screencapture -Rto grab exactly that region, and optionallysipsto crop and scale.locate_elementcaptures the specified region, asks Ollama to return element coordinates as JSON fractions (0–1), then converts to pixel coordinates.All tools base64-encode the PNG and POST it to Ollama's
/api/generateendpoint.If Ollama isn't running, the server spawns
ollama serveand waits up to 30 seconds for it to become ready.
Rebuilding after changes
npm run buildThen restart Claude Code to reload the server.
Available Tools
3 toolsanalyze_screenshotA
Take a screenshot of a URL in a headless browser and analyze it with a local Ollama vision model. Good for public pages. For pages requiring login, use capture_window instead. Use full_page: true to capture content below the fold — the page is sliced into segments and sent as multiple images so no detail is lost.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | URL to screenshot (e.g. http://localhost:3004) | |
| model | No | Ollama vision model to use (defaults to OLLAMA_MODEL env var, or gemma4:e4b) | gemma4:e4b |
| wait_ms | No | Milliseconds to wait after page load for JS rendering | |
| question | Yes | What to analyze or look for in the screenshot | |
| full_page | No | Capture the full page height, not just the visible viewport. Long pages are sliced into segments sent as multiple images so detail is preserved at every scroll depth. | |
| max_slices | No | Maximum number of slices when full_page is true. Slices are distributed evenly across the page height. Default 8 covers most pages well. | |
| viewport_width | No | Viewport width in pixels | |
| viewport_height | No | Viewport height in pixels |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It reveals that the tool runs a headless browser, uses a local Ollama vision model, and explains the slicing mechanism for full-page captures to preserve detail. This goes beyond the schema and provides meaningful insight into how the tool behaves, though it omits return format and potential side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the primary purpose, followed by usage guidance and a key behavioral note. Every sentence earns its place with no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the main use case, login-page alternative, and full-page behavior, but it does not explicitly specify what the tool returns (e.g., analysis text, screenshot, or both). Given the absence of an output schema, this is a notable gap for a tool with 8 parameters and a potentially complex response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description reinforces the full_page parameter's behavior ('sliced into segments and sent as multiple images') but does not materially add meaning beyond what the schema already documents for other parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Take a screenshot of a URL in a headless browser and analyze it with a local Ollama vision model') and distinguishes the tool from siblings by explicitly contrasting with capture_window for login pages. This makes the tool's purpose unambiguous and clearly differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage context: 'Good for public pages' and directs users to 'use capture_window instead' for login-protected pages. It also advises on full_page usage for content below the fold, covering when to use this tool versus an alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
capture_windowA
Capture a specific app window currently visible on screen and analyze it with a local Ollama vision model. Unlike analyze_screenshot, this sees your real browser with your logged-in session and live state — ideal for testing local apps.
| Name | Required | Description | Default |
|---|---|---|---|
| crop | No | Crop to a sub-region before analysis. All values are fractions 0–1. E.g. bottom half: {x:0, y:0.5, width:1, height:0.5} | |
| model | No | Ollama vision model to use (defaults to OLLAMA_MODEL env var, or gemma4:e4b) | gemma4:e4b |
| scale | No | Upscale factor applied before sending to the vision model. Use 2 or 3 for small terminal text or dense UIs. | |
| app_name | Yes | Exact macOS app name, e.g. 'Google Chrome', 'Safari', 'Terminal', 'Cursor' | |
| question | Yes | What to analyze or look for in the screenshot | |
| window_index | No | Which window to capture if the app has multiple (1 = frontmost) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the full burden. It discloses that the tool captures a live, visible window and uses a local Ollama model, which implies real-state analysis and privacy considerations. However, it does not mention required permissions, whether it brings the window to front, or any side effects, leaving notable behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two efficient sentences with the core purpose front-loaded, followed by a single high-value comparison sentence. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
While the description covers purpose and differentiates from a sibling, the tool is complex (6 params, nested object, no output schema). It does not explain the return format (e.g., text from the vision model), prerequisites (e.g., screen recording permission), or the effect of crop/scale parameters. These gaps are significant for an agent unfamiliar with the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides 100% coverage with detailed descriptions for all six parameters, including the nested crop object and model default. The tool description adds no extra parameter semantics, so a baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's action ('Capture a specific app window currently visible on screen and analyze it with a local Ollama vision model'), specifies the resource (specific app window), and differentiates from the sibling tool analyze_screenshot. The verb is specific and the scope is explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly names an alternative (analyze_screenshot) and contrasts their behavior ('this sees your real browser with your logged-in session and live state'), providing a clear use case ('ideal for testing local apps'). It lacks an explicit 'when not to use' statement, but the contrast implies it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
locate_elementA
Find a UI element in an app window and return its click coordinates. Uses a local Ollama vision model — Claude never sees the image. For Google Chrome, pass viewport_bounds (computed from javascript_tool: {x: screenX, y: screenY + outerHeight - innerHeight, width: innerWidth, height: innerHeight}) to get viewport-relative coordinates usable directly with the Chrome computer tool. Without viewport_bounds, returns absolute screen coordinates.
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | Ollama vision model to use (defaults to OLLAMA_MODEL env var, or gemma4:e4b) | gemma4:e4b |
| app_name | Yes | Exact macOS app name, e.g. 'Google Chrome', 'Safari', 'Terminal', 'Cursor' | |
| window_index | No | Which window to capture if the app has multiple (1 = frontmost) | |
| viewport_bounds | No | Screen-coordinate bounds of the region to capture (e.g. Chrome's content area). For Chrome: compute as {x: screenX, y: screenY + outerHeight - innerHeight, width: innerWidth, height: innerHeight} using window.screenX/Y/outerWidth/outerHeight/innerWidth/innerHeight from javascript_tool. When provided, returned coordinates are relative to this region's (0,0) — viewport-relative for Chrome. | |
| element_description | Yes | Natural language description of the element to find, e.g. 'the X close button in the top-right of the modal' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since annotations are absent, the description carries the behavioral disclosure burden. It reveals key behaviors: the use of a local Ollama vision model ('Claude never sees the image'), privacy preservation, and the coordinate system semantics for viewport_bounds. It does not describe failure handling, permissions, or output format, but the disclosed traits are meaningful and non-obvious.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, each earning its place: core purpose, model/privacy, and coordinate behavior with a concrete example. The critical viewport_bounds guidance is front-loaded after the purpose, making the most actionable information easy to find. No filler words or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Considering the tool's complexity (nested viewport_bounds object, 5 params, no output schema, no annotations), the description covers the essential missing context: coordinate semantics and the crucial Chrome-specific computation. It omits edge cases like element-not-found behavior or return error structure, but for a coordinate-returning tool, the provided detail is sufficient for effective use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents all 5 parameters with 100% coverage, so the baseline is 3. The description adds significant value by explaining exactly how to compute viewport_bounds for Chrome and why it changes the returned coordinates. This provides meaning beyond the schema's static field definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with an explicit, specific verb+resource statement: 'Find a UI element in an app window and return its click coordinates.' This clearly differentiates the tool from siblings like analyze_screenshot (which analyzes an image) and capture_window (which captures a window). The returned artifact (click coordinates) is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides concrete guidance for the Chrome-specific case, including a detailed formula for viewport_bounds and the consequence of omitting it (absolute vs. viewport-relative coordinates). It does not explicitly name alternative tools or state when not to use this tool, but it offers clear contextual usage instructions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
analyze_screenshot and capture_window both perform capture-and-analyze, but their contexts are clearly differentiated (headless URL vs. live window). locate_element is distinct as it returns coordinates. Minor overlap exists for public pages that could be captured either way.
All three tools follow a consistent verb_noun pattern with snake_case: analyze_screenshot, capture_window, locate_element. Predictable and clear.
Three tools is a focused, appropriate scope for a screenshot-vision server—each serves a distinct purpose without redundancy.
The set covers the core workflows: capture from URL, capture from live window, and element location. A general 'analyze existing image' tool is missing, but the primary use cases are covered.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Screenshot and HTML render MCP server for AI agents
MCP server for Qwen Image 3 AI image generation
Augments MCP Server - A comprehensive framework documentation provider for Claude Code
Related MCP Servers
- AlicenseBqualityDmaintenanceA local vision-language MCP server that enables Claude Code to perform image analysis, OCR, and UI-to-code generation using the Qwen3 VL 4B model via LM Studio. It provides privacy-focused visual processing by running entirely on the user's local hardware without external API dependencies.3151MIT
- FlicenseAqualityBmaintenanceEnables Claude to capture screenshots, watch your screen in real-time, read text via OCR, and analyze video files, all running locally as an MCP server.14
- FlicenseNot gradedqualityBmaintenanceAn MCP server that gives Claude the ability to watch any desktop window, detecting changes and providing compact image bundles for Claude's vision, enabling real-time screen-watching without API costs.
- FlicenseAqualityDmaintenanceMCP server for vision capabilities, enabling screenshot, camera, and image analysis using Ollama vision models.41
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/AVS845/screenshot-vision-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server