screenshot-vision-mcp

screenshot-vision-mcp

An MCP server that captures screenshots of URLs or local app windows and analyzes them with a local Ollama vision model, enabling Claude to visually inspect web pages and desktop applications without sending image data externally.

Category
访问服务器

README

screenshot-vision-mcp

An MCP server for Claude Code that takes screenshots and analyzes them with a local Ollama vision model — no image data ever leaves your machine, and it costs zero vision tokens.

Three tools are provided:

Tool When to use
analyze_screenshot Public or local URLs — opens a headless browser, no session
capture_window Any app window on screen — sees your real logged-in session
locate_element Find a UI element and return click coordinates — Claude never sees the image

Requirements

  • macOS (window capture uses screencapture and 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
    

Installation

git clone git@github.com:AVS845/screenshot-vision-mcp.git
cd screenshot-vision-mcp
npm install
npm run build

Claude 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_URL http://localhost:11434 Ollama host
OLLAMA_MODEL gemma4:e4b Default vision model for all tools
{
  "mcpServers": {
    "screenshot-vision": {
      "command": "node",
      "args": ["/absolute/path/to/screenshot-vision-mcp/dist/index.js"],
      "env": {
        "OLLAMA_URL": "http://192.168.1.10:11434",
        "OLLAMA_MODEL": "llava"
      }
    }
  }
}

Tools

analyze_screenshot

Takes a screenshot of a URL in a headless Playwright browser and analyzes it.

Parameter Type Default Description
url string — URL to screenshot
question string — What to analyze
model string gemma4:e4b Ollama vision model
viewport_width number 1280 Viewport width in px
viewport_height number 800 Viewport height in px
wait_ms number 2000 Wait after page load (ms)
full_page boolean false Capture the full page height, not just the visible viewport
max_slices number 8 Max slices when full_page is true (1–20)

When full_page: true, the tool captures the entire page as one tall PNG, then slices it into viewport_height-tall segments distributed evenly from top to bottom. Each slice is sent as a separate image in a single Ollama request, with a prompt that tells the model the slice order. This matters because Ollama caps Gemma 4's image token budget at 280 tokens — a single tall image gets crushed into noise, while N properly-proportioned slices each get full detail.

capture_window

Captures a specific app window currently on screen and analyzes it. Useful for testing local apps where you're already logged in.

Parameter Type Default Description
app_name string — Exact macOS app name, e.g. "Google Chrome"
question string — What to analyze
model string gemma4:e4b Ollama vision model
window_index number 1 Which window (1 = frontmost)
scale number 1 Upscale factor (2–3 helps with small text)
crop object — Crop to a sub-region before analysis

The crop parameter takes fractional values (0–1):

{ "x": 0, "y": 0.5, "width": 1, "height": 0.5 }

That example crops to the bottom half of the window.

locate_element

Finds a UI element in an app window and returns its click coordinates. Ollama does the visual work — Claude never sees the image.

Parameter Type Default Description
app_name string — Exact macOS app name, e.g. "Google Chrome"
element_description string — Natural language description of the element to find
model string gemma4:e4b Ollama vision model
window_index number 1 Which window (1 = frontmost)
zoom boolean false Two-pass refinement — first finds a rough bounding box, then crops and refines. Recommended for small targets like close buttons
viewport_bounds object — Screen-coordinate bounds of the region to capture (see Chrome usage below)

Returns { x, y, coordinate_mode } where coordinate_mode is "viewport" (when viewport_bounds is passed) or "screen".

Usage with Google Chrome

The Chrome computer tool uses viewport-relative coordinates. Pass viewport_bounds so the returned {x, y} can be used directly.

Prefer getBoundingClientRect for standard HTML elements — it's exact and requires no image:

// javascript_tool → 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) });

Use locate_element for elements that can't be DOM-queried (canvas, rendered images, visually-composed widgets).

When using locate_element with Chrome, measure viewport bounds immediately before the call — the Chrome automation InfoBar temporarily reduces innerHeight, causing ~40px y-offset errors if you use stale bounds:

// javascript_tool — run this right before locate_element, not once per session
JSON.stringify({
  screenX: window.screenX,
  screenY: window.screenY,
  outerHeight: window.outerHeight,
  innerWidth: window.innerWidth,
  innerHeight: window.innerHeight,
})

Then call locate_element:

locate_element(
  app_name: "Google Chrome",
  element_description: "the X close button in the top-right of the modal",
  zoom: true,
  viewport_bounds: {
    x: screenX,
    y: screenY + outerHeight - innerHeight,
    width: innerWidth,
    height: innerHeight,
  }
)
→ { x: 891, y: 267, coordinate_mode: "viewport" }

Pass x/y directly to the Chrome computer tool's click action.


How it works

  1. analyze_screenshot launches a headless Chromium browser via Playwright, navigates to the URL, waits for JS to settle, and captures a PNG.
  2. capture_window uses AppleScript to get the window bounds, screencapture -R to grab exactly that region, and optionally sips to crop and scale.
  3. locate_element captures the specified region (or full window), asks Ollama to return element coordinates as JSON fractions (0–1), then converts to pixel coordinates. With zoom: true, it does a two-pass crop for higher accuracy.
  4. All tools base64-encode the PNG and POST it to Ollama's /api/generate endpoint.
  5. If Ollama isn't running, the server spawns ollama serve and waits up to 30 seconds for it to become ready.

Rebuilding after changes

npm run build

Then restart Claude Code to reload the server.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选