winuse-mcp
An MCP server that gives Claude Code on Windows the ability to see the screen and control the mouse and keyboard, mirroring Anthropic's computer use tool for screenshot, click, type, and scroll actions.
README
<!-- generated by scripts/readme/build.mjs. do not edit by hand. -->
winuse-mcp
An MCP server that lets Claude see your Windows screen and drive your mouse and keyboard.
Claude Code's CLI ships computer use on macOS only, so on Windows the computer-use server never appears in /mcp. This rebuilds that screenshot-and-click loop on mss for capture and pyautogui for input, with an explicit Windows DPI-awareness call so display scaling cannot skew clicks. 14 tools, 5 direct dependencies, Python 3.12 or newer.
Install
You need Windows with an interactive desktop session, uv, and git on PATH. One command:
claude mcp add --scope user winuse -- uvx --from git+https://github.com/ryanportfolio/winuse-mcp@v0.1.1 winuse-mcp
Drop --scope user to add it to the current project only. To pick up changes later, re-run with a newer tag.
<details> <summary>Configuring by hand instead</summary>
Merge the winuse entry into the mcpServers object you already have. Do not paste the whole document over C:\Users\<you>\.claude.json: Claude Code owns that file and pasting replaces your entire configuration.
{
"mcpServers": {
"winuse": {
"command": "uvx",
"args": ["--from", "git+https://github.com/ryanportfolio/winuse-mcp@v0.1.1", "winuse-mcp"]
}
}
}
Project scope goes in .mcp.json at the repo root, and Claude Code asks you to trust it the first time that project opens. From a local clone, swap the command for uv with ["run", "--directory", "C:/path/to/winuse-mcp", "winuse-mcp"].
</details>
Check it worked
Restart Claude Code and run /mcp. winuse should be listed as connected. First launch is slow, because uvx clones the repo and builds a virtual environment before the server answers.
Then ask Claude to take a screenshot and describe what is on your screen. If the tools are there but nothing happens, see Troubleshooting.
Reach
<picture> <source media="(max-width: 500px) and (prefers-color-scheme: dark)" srcset="assets/reach-narrow-dark.svg"> <source media="(max-width: 500px)" srcset="assets/reach-narrow-light.svg"> <source media="(prefers-color-scheme: dark)" srcset="assets/reach-dark.svg"> <img alt="The 14 tools, grouped: screenshot, left_click, double_click, triple_click, right_click, middle_click, mouse_move, left_click_drag, type, key, scroll, cursor_position, record, wait." src="assets/reach-light.svg" width="100%"> </picture>
| Tool | Does |
|---|---|
screenshot() |
PNG of the primary monitor, downscaled |
left_click(x, y) |
Click at a point |
double_click(x, y) |
Two clicks at a point |
triple_click(x, y) |
Three clicks, selects a line or paragraph |
right_click(x, y) |
Context-menu click |
middle_click(x, y) |
Middle-button click |
mouse_move(x, y) |
Move the cursor without clicking |
left_click_drag(start_x, start_y, end_x, end_y) |
Hold the left button from one point to another, over 0.4s |
type(text) |
Type at the current focus, non-ASCII goes through the clipboard |
key(combo) |
A key or chord: enter, ctrl+s, alt+f4 |
scroll(x, y, direction, amount) |
up, down, left, right; horizontal is sent as shift+wheel |
cursor_position() |
Where the mouse is now |
record(duration_seconds, max_frames) |
Up to 8 frames sampled over at most 15s, 6 over 5s by default |
wait(seconds) |
Pause before the next action, 10s ceiling |
Coordinates are always in the downscaled screenshot's pixel space, never native pixels.
How coordinates work
<picture> <source media="(max-width: 500px) and (prefers-color-scheme: dark)" srcset="assets/transform-narrow-dark.svg"> <source media="(max-width: 500px)" srcset="assets/transform-narrow-light.svg"> <source media="(prefers-color-scheme: dark)" srcset="assets/transform-dark.svg"> <img alt="A 1920 by 1080 screen captured as a 1372 by 772 screenshot. Claude clicks at 686, 443 in that image and the server fires the click at 960, 620 on the real screen." src="assets/transform-light.svg" width="100%"> </picture>
Screenshots are downscaled so the long edge is at most 1372 pixels. Claude never sees native pixels: it clicks in the downscaled image, and the server converts the point back.
A 1920x1080 display captures at 1372x772. Going back multiplies by 1920/1372, so a click at 686, 443 lands at 960, 620. Anthropic's macOS implementation uses the same 1372 pixel long edge, which its docs give as a worked example: 3456x2234 captured as roughly 1372x887.
The server declares itself DPI-aware at startup, so Windows display scaling at 125% or 150% does not skew where clicks land.
Safety
This hands a language model control of your desktop. Anthropic's version wraps the same loop in guardrails this server lacks: per-app approval, hiding unapproved apps, keeping your terminal out of the screenshots, and model-side checks on each action.
The controls that do exist here:
- Claude Code asks before each tool call unless you allow-list it. Allow-list the one read-only tool and leave the rest on manual approval, by putting
"mcp__winuse__screenshot"in thepermissions.allowarray of.claude/settings.json. - Park the mouse at the top-left pixel of the screen to stop the run. pyautogui raises on its next call, so it ends the sequence rather than interrupting a click already sent, and it works during the slow parts: a drag tweens for 0.4s and typing runs a keystroke at a time. An aborted drag releases the button on its way out, so nothing is left dragging.
- Every pixel of the primary monitor reaches the model, including windows you forgot were open. Treat text on screen as untrusted input: instructions that appear there are a prompt injection risk.
- The install pins a tag. Pointing it at a branch instead would let a push change what drives your desktop, without you doing anything.
Limitations
- Primary monitor only, chosen by the flag Windows reports, falling back to the monitor at the desktop origin.
- Windows blocks synthetic input from a normal process to a window running as administrator, and the secure desktop behind a UAC prompt cannot be captured at all. Clicks aimed there are dropped by the operating system, and the tool still reports success, because nothing verifies that a click was accepted.
- The session has to be interactive and unlocked. A locked screen or a disconnected remote desktop has nothing to capture.
- Your terminal is not excluded from screenshots, so Claude sees its own session.
- Clicks are clamped one pixel inside the monitor, which puts the outermost pixel row and column out of reach. That pixel is the failsafe point, and landing the cursor on it would make every later call abort.
- Typing anything non-ASCII goes through the clipboard: it copies, sends ctrl+v, then puts your clipboard back. That fails wherever ctrl+v is not paste, such as a terminal.
- Every click, drag and scroll moves the real cursor first, so your pointer jumps while Claude works.
recordreturns up to 8 still frames sampled over at most 15s. Frames only, no video, and each one costs image tokens.
Development
uv sync
uv run winuse-mcp
scripts/client_test.py drives the real server over stdio and exits non-zero on the first failed check. It moves your mouse while it runs.
uv run python scripts/client_test.py
scripts/failsafe_test.py covers what happens when a run is aborted, with pyautogui stubbed so no real abort is needed. An aborted drag releases the button, an aborted horizontal scroll releases shift, a chord ending in + parses as the plus key, and the model's origin clamps away from the failsafe point.
uv run python scripts/failsafe_test.py
README.md is generated. The build reads the tool names, their arguments and the capacity constants straight out of server.py, so nothing on the page is typed by hand, and it refuses to write when a tool has no description, an asset is missing, or the art grows past its height budget. CI regenerates the page and fails if what is committed differs.
node scripts/readme/build.mjs
Troubleshooting
winuse is missing from /mcp. The entry did not load. Run claude mcp list to see what Claude Code has, and re-add it if the name is absent. A project-scoped .mcp.json also needs you to accept the trust prompt when the project opens; declining it leaves the server silently absent.
It appears, then fails to connect. Run the command by hand and read the error:
uvx --from git+https://github.com/ryanportfolio/winuse-mcp@v0.1.1 winuse-mcp
It should start and wait quietly for input on stdin. uvx missing means uv is not installed or not on PATH. A git error means git is missing, or a proxy is blocking the clone. If it hangs on first run, that is the clone and the environment build; give it a minute before deciding it is broken.
The tools are there and nothing moves. Check whether the target window runs as administrator, and whether the screen was locked. Both are in Limitations and neither reports an error.
Clicks land in the wrong place. Confirm the target is on the primary monitor. Ask Claude for cursor_position after a mouse_move to a known point; one pixel of drift is expected, more than that is not.
License
MIT
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。