oswright
OSWright
面向 AI 代理的桌面自动化,无需为每一步截屏付费。
mcp-name: io.github.Ask-812/oswright
这是一个 MCP 服务器,让 LLM 能够驱动真实的桌面应用程序——相当于桌面版的 Playwright MCP。它在操作之间保留屏幕模型,只重新读取发生变化的部分,因此同样的工作所消耗的 token 数量减少一个数量级。

从发票上读取八个字段并输入费用表单,由应用程序本身验证。同样的任务、同样的结果,与每次操作后返回截图相比,上下文减少 7.4 倍。运行过程中的每一个屏幕数字都被测量——可使用 python benchmarks/record_demo.py 重新生成整个过程。
为什么会有这个项目
大多数 GUI 代理在每一步都会重新感知整个屏幕:截图、OCR、把图像交给模型,如此循环。在真实桌面上测量时,观察结果的中位数仅改变屏幕像素的 0.012%。全部重新读取所做的工作远超变化本身所需,而且无论是否发生变化,都要花费约 2,800 个图像 token。
OSWright 会询问合成器发生了什么变化,只重新扫描这些区域,并尽可能从最廉价的来源回答元素查找。下面的结论是在这台机器上测量得到的,并且可以通过 benchmarks/ 复现——包括那些对 OSWright 不利的结论。
主要特性
跨平台。 Windows(Win32 API)、Linux(pynput/X11)、macOS(pynput/Quartz)。
辅助功能树。 通过 Windows UI Automation 按角色和名称确定性地查找元素——100% 准确、即时,无需模型。
快速 OCR。 使用 Windows 内置 OCR(即时)并在 Linux/macOS 上以 EasyOCR 作为后备。结果会自动缓存。
Windows 上轻量。 无需下载 PyTorch——Windows 使用内置 OCR 引擎,因此完整安装只有几 MB,而不是几 GB。
图像匹配。 通过 OpenCV 按模板图像定位元素。
窗口管理。 列出、聚焦、最小化、关闭特定窗口并对其截图。
截图差异对比。 通过
wait_for_change检测屏幕变化。剪贴板访问。 读取和写入系统剪贴板以传输数据。
应用启动器。 启动应用程序并等待其加载完成。
自动快照。 每个操作都会返回截图,因此代理始终能看到当前状态。
43 个 MCP 工具。 涵盖屏幕、OCR、UIA、鼠标、键盘、窗口、剪贴板和复合操作。
增量感知。 只重新扫描屏幕中发生变化的部分,并且可以返回变化内容而非完整截图——每一步的 token 消耗减少约 21 倍。
屏幕记忆。 识别之前读取过的屏幕并复用它们,并通过像素验证——比重新读取便宜 89 倍。
推测式感知。 学习操作会产生什么结果,并确认预期结果而不是重新读取——成本降低 19–23 倍,当界面出现意外行为时会生成
surprise报告。自适应等待。 等待屏幕真正稳定下来,而不是固定等待 300 ms——在 50 步的任务中节省 11.9 秒。
分辨率级联。 元素查找会在最先奏效的最廉价方法处停止;重复查找约耗时 0.05 ms。
DPI 正确。 坐标到处都使用物理像素,因此点击在缩放显示上能准确定位。
测试套件。 237 个自动化测试;在没有显示环境时会自动跳过驱动桌面的测试。
环境要求
Python 3.10 或更高版本
VS Code、Cursor、Windsurf、Claude Desktop,或任何其他 MCP 客户端
快速开始
首先,随你的客户端安装 OSWright MCP 服务器。
标准配置 适用于大多数工具:
{
"mcpServers": {
"oswright": {
"command": "uvx",
"args": ["oswright"]
}
}
}注意: 如果你没有
uvx,可以使用pip install oswright,然后将"command"直接设为"oswright"。
按照 MCP 安装指南,使用上面的标准配置。
claude mcp add oswright uvx oswright在你的用户或工作区 settings.json 中的 mcp.servers 下添加:
{
"mcp": {
"servers": {
"oswright": {
"command": "uvx",
"args": ["oswright"]
}
}
}
}或者使用 VS Code CLI:
code --add-mcp '{"name":"oswright","command":"uvx","args":["oswright"]}'转到 Cursor Settings -> MCP -> Add new MCP Server。将其命名为 oswright,使用 command 类型,命令为 uvx oswright。
按照 Windsurf MCP 文档操作。使用上面的标准配置。
添加到你的 cline_mcp_settings.json:
{
"mcpServers": {
"oswright": {
"type": "stdio",
"command": "uvx",
"args": ["oswright"],
"disabled": false
}
}
}转到 Advanced settings -> Extensions -> Add custom extension。将其命名为 oswright,使用 STDIO 类型,并将 command 设置为 uvx oswright。
如果你更喜欢标准的 pip 安装:
pip install oswright然后使用此配置:
{
"mcpServers": {
"oswright": {
"command": "oswright"
}
}
}或者直接运行:
python -m oswrightRelated MCP server: screen-use
增量感知
大多数 GUI 代理在每一步都会重新感知整个屏幕:完整截图、完整 OCR,然后把新图像交给模型。在真实桌面上测量时,观察结果的中位数仅改变 0.012% 的像素——因此完整重新扫描所做的工作大约是变化本身所需的 240 倍,而且无论是否发生变化,它返回的截图都要花费约 2,800 个图像 token。
OSWright 在两次观察之间保留屏幕模型,只重新扫描实际移动过的区域。
observe() -> {"changed": true,
"added": [{"text": "Saved", "x": 812, "y": 447}],
"removed": ["Unsaved changes"],
"screen_fraction_scanned": 0.015}在这台机器上对一个 14 步代理循环进行测量:
v0.4.0(完整 OCR + 截图) | 增量 | |
每步中位延迟 | 212 ms | 33 ms |
每次观察的 token 数 | ~2,764 | ~49 |
14 步总 token 数 | 38,696 | 1,025 |
屏幕重新读取比例 | 100% | 16% |
屏幕越繁忙,差距越大:完整 OCR 的开销随屏幕上的文本量增长,而增量路径只随 变化量 增长。同样的对比在安静的桌面上测得 6.5 倍,在打开密集网页时测得 14.3 倍。请用 benchmarks/ 重新测量,而不是相信这些数字。
不过,成本只是一个代理指标,一条更便宜但悄悄降低准确性的感知路径比没有更糟。因此,我们以任务完成情况来检验:脚本化任务驱动四个应用程序中的真实工具界面,并根据每个应用程序自身的状态评分——计算器和文件资源管理器使用 UI Automation,Chrome 和 VS Code 使用窗口标题——绝不对照 OCR。
配置 | 计算器 | 文件资源管理器 | Chrome | token 数 |
v0.4 风格(完整截图) | 9/9 | 3/3 | 3/3 | 118,858 |
仅 delta | 9/9 | 3/3 | 3/3 | 5,252 |
delta + 记忆 | 9/9 | 3/3 | 3/3 | 5,099 |
delta + 记忆 + 预测 | 9/9 | 3/3 | 3/3 | 7,981 |
在所有配置下准确率完全相同,而 token 成本下降了 23 倍。 使用 python benchmarks/bench_tasks.py 运行。
为什么同时需要像素和辅助功能
这个设计押注的是,没有任何一种感知路径能包打天下。分别关闭其中一半来验证这一点,而不是凭空断言:
配置 | 计算器 | 文件资源管理器 | Chrome |
完整级联 | 9/9 | 3/3 | 3/3 |
仅辅助功能 | 9/9 | 0/3 | 0/3 |
仅像素 | 6/9 | 3/3 | 3/3 |
仅辅助功能——大多数 Windows GUI 代理采用的方式——在 XAML 上表现完美,但在 Win32 列表视图和网页内容上如同盲人。对 VS Code 进行探测时,它只能看到 18 个元素,整个 IDE 是名为 Chrome Legacy Window 的单一节点,而 OCR 能读取 94 个元素,包括每个文件名。
仅像素方案在计算器的按钮上失败,因为人类读作 7 的按钮 名为 Seven,而 Windows OCR 在计算器上根本返回不了任何数字。
级联是唯一在所有场景下都通过的配置。
分辨率级联
find_element 和 click_element 会在第一个能回答的方法处停止,因此成本取决于请求的 新颖程度,而不是屏幕的大小:
层级 | 方法 | 典型成本 |
0 | 已在屏幕模型中 | ~0.05 ms |
1 | 只重新扫描发生变化的部分 | ~70 ms |
2 | 辅助功能树(知道按钮 就是 按钮) | ~40 ms |
3 | 通过 UIA TextPattern 访问应用自身的文本缓冲区——精确字符 | ~400 ms |
4 | 全屏 OCR | ~250 ms |
查找模型已知的文本比 v0.4.0 路径便宜 约 5,000 倍(0.05 ms 对 244 ms)。响应会报告由哪一层回答,因此你可以看到任务实际消耗了什么。
第 3 层值得理解:UIA 的 TextRange.FindText 会搜索应用程序自己的文本缓冲区,并返回精确的边界矩形。它不受字体、DPI、抗锯齿和 OCR 错误的影响。它排在像素层级之下,仅仅是因为扫描窗口控件需要数百毫秒的跨进程 COM 开销——它是精确的一层,而不是快速的一层。
关于排序的说明。 这些层级是按 实测结果 排序的,而不是按理论。常见的建议是把辅助功能树作为首选,但在真实应用程序上它并不总是更便宜:在这里遍历 Chrome 的树花了 537 ms,比全屏 OCR 一遍还慢,而且 VS Code 只向它暴露了 18 个元素。无论是像素还是辅助功能,都无法在所有场景下胜出,这就是为什么这是一个级联而不是二选一。
询问合成器而不是自己看
在 Windows 上,桌面合成器已经知道哪些像素发生了变化,并通过 DXGI Desktop Duplication 暴露这些变化。询问它的成本为 0.14 ms,且不传输任何像素,而捕获一帧并发现它完全相同则需要几十毫秒——因此空闲观察会完全跳过捕获。
当确实有变化时,合成器会持有那一帧,因此可以直接从 GPU 读取其像素,而不是通过另一个 API 再次抓取——在本文的测量中比 mss 快 1.5–2.3 倍。
合成器仅用作变更检测的快速 否定。当它报告有变化时,脏区域仍然来自对捕获帧的哈希计算:两者的测量间隔略有不同,因此合成器矩形相对于实际捕获的像素可能少报,而少报的区域就是永远不会被重新读取的文本。在 Desktop Duplication 不可用的地方,它会静默降级为瓦片哈希和正常捕获。
使用 --observation-mode delta 为操作工具启用增量观察。默认值仍为 screenshot,以兼容现有客户端。
请自行完整复现所有这些: 参见 benchmarks/。
每个决策背后的理由(包括走过的弯路)都记录在 docs/ENGINEERING_LOG.md 中。
配置
OSWright MCP 服务器支持以下参数。它们可以在 JSON 配置中作为 "args" 列表的一部分提供:
选项 | 描述 | 环境变量 |
| SSE 传输的端口。若省略,则使用 stdio(默认)。 |
|
| HTTP/SSE 服务器绑定的主机。默认: |
|
| 传输协议: | |
| OCR 语言(默认: |
|
| 自动等待操作的默认超时(默认: |
|
| 对每次操作后返回的自动快照进行降采样。 |
|
| 操作工具返回的内容: |
|
| 不跨访问记忆屏幕。 |
|
| 不预测操作结果。 |
|
| 绑定非回环地址时需要。参见 安全。 | |
| 日志级别: |
|
显式命令行标志始终优先于相应的环境变量。
示例:多语言 OCR
{
"mcpServers": {
"oswright": {
"command": "uvx",
"args": ["oswright", "--ocr-languages", "en", "es", "fr"]
}
}
}独立 MCP 服务器(SSE)
当从工作进程或其他机器运行时,请使用 SSE 传输:
uvx oswright --port 8931然后在你的 MCP 客户端配置中:
{
"mcpServers": {
"oswright": {
"url": "http://127.0.0.1:8931/sse"
}
}
}安全
OSWright 没有任何身份验证。 任何能访问该端口的人都能完全控制机器的键盘、鼠标、屏幕和剪贴板——这相当于远程桌面接管,而不是沙箱 API。
因此,服务器默认绑定到 127.0.0.1,并且除非传入 --allow-remote,否则拒绝在非回环地址上启动。要从另一台机器访问它,建议使用 SSH 隧道而不是暴露端口:
ssh -L 8931:127.0.0.1:8931 user@desktop-hostStdio 传输(默认方式,上述所有 MCP 客户端配置都使用它)完全不暴露于网络,是运行 OSWright 的推荐方式。
可能破坏工作的工具会得到相应标注:close_window 被标记为破坏性操作,launch_app 可启动任意程序。截图工具拒绝覆盖已存在的 save_path。
平台说明
平台 | 输入后端 | OCR 后端 | 额外下载 |
Windows | Win32 API (SendInput) | Windows OCR(即时、内置) | 无。 不需要 PyTorch。包含 UI Automation。 |
Linux | pynput (X11) | EasyOCR | PyTorch(约 2.5 GB)。需要 X11;Wayland 支持有限。 |
macOS | pynput (Quartz) | EasyOCR | PyTorch(约 2.5 GB)。请在“系统设置”>“隐私与安全性”>“辅助功能”中授予辅助功能权限。 |
在 Windows 上,不安装 EasyOCR,因为内置的 Windows OCR 引擎更快,且无需下载模型。仅当你需要 Windows OCR 不支持的语言时才安装它:
pip install "oswright[easyocr]"坐标
OCR、图像匹配和 UI Automation 返回的所有坐标均为绝对物理屏幕像素,可直接传给 mouse_click。这同样适用于子区域以及虚拟桌面从负原点开始的多显示器设置。screenshot 还会报告 origin_x/origin_y,即图像左上角像素的绝对位置,方便你自行从图像上读取坐标。
工具
screenshot -- 截取屏幕或某个区域的截图。以原生 MCP 图像内容返回图像。也可以选择保存到文件路径。
只读:true
get_screen_info -- 获取屏幕尺寸和显示器数量。
只读
get_ui_tree -- 获取焦点窗口的无障碍树。返回所有交互元素及其名称、类型、位置。结果确定且即时。
参数:
window_title、max_depth只读:true
click_ui_element -- 使用无障碍树点击 UI 元素。比 OCR 更可靠。
参数:
name、control_type、automation_id、window_title
fill_ui_element -- 设置 UI 元素(例如文本框)的值。比基于 OCR 的填充更可靠。
参数:
value、name、automation_id、window_title
get_active_window -- 获取当前焦点窗口的信息。
只读:true
wait_for_change -- 等待屏幕发生视觉变化。截取基准截图,轮询直到画面不同。
参数:
timeout、poll_interval
Python 库
OSWright 也可以作为独立的 Python 库使用,提供 Playwright 风格的 API:
from oswright import OSWright
with OSWright() as ow:
screen = ow.screen()
screen.click(text="Start")
screen.type_text("Hello World")
screen.press("Ctrl+S")
screen.screenshot("desktop.png")更多示例请参阅 examples/ 目录。
架构
oswright/
__init__.py # Package entry point (single source of __version__)
core.py # OSWright class (= Browser)
screen.py # Screen class (= Page)
locator.py # Locator + Assertions (= Locator + expect)
capture.py # Screen capture (mss - cross-platform, thread-safe)
dirty.py # Change detection - which parts of the screen moved
screenmodel.py # Persistent screen model, updated incrementally
cascade.py # Resolution cascade - cheapest method that can answer
atlas.py # Remembers screens across visits and sessions
settle.py # Knowing when the screen has finished responding
speculate.py # Predicting what an action does, instead of looking
textprovider.py # Exact text from the app itself via UIA TextPattern
detect.py # OCR dispatcher with caching (auto-selects best backend)
_ocr_windows.py # Windows OCR backend (instant, built-in)
accessibility.py # Windows UI Automation (deterministic element finding)
cache.py # Screenshot diffing, image hashing, OCR result cache
_dpi.py # Process DPI awareness (keeps every API in physical pixels)
_dxgi_windows.py # Compositor dirty rectangles via DXGI Desktop Duplication
input.py # Platform dispatcher for input backends
_input_windows.py # Windows input backend (Win32 API)
_input_pynput.py # Linux/macOS input backend (pynput)
window.py # Window management (list, focus, close)
clipboard.py # Clipboard read/write (cross-platform)
mcp_server.py # MCP server (43 tools for AI agents)
tests/
conftest.py # Fixtures that skip when no display/OCR is available
test_core.py # Unit tests (no desktop required)
test_perception.py # Incremental perception (stubbed, runs headless)
test_atlas.py # Screen memory and its failure modes (headless)
test_speculate.py # Prediction, settling, and their limits (headless)
test_e2e.py # End-to-end tests against the real desktop (marked `e2e`)记住屏幕
应用是确定性的——同一个对话框每次都有相同的布局。OSWright 会记住它读取过的屏幕,并在下次访问时跨会话复用:125 ms 冷读取 → 1.4 ms 热召回(89×)。
被记住的屏幕绝不会仅凭识别结果就受到信任。在复用布局之前,会按像素抽查几个区域,因此发生变化的屏幕会被拒绝,而不是被操作。验证采用失败关闭原则:没有任何可检查内容的屏幕根本不会被记住。
可通过 --no-atlas 禁用。记住的屏幕存放在 ~/.oswright/atlas.json 中。
预测动作而非观察动作
应用是确定性的——点击保存每次都会产生相同的对话框——因此在第一次观察之后,动作的结果已经可知。OSWright 会学习动作的效果,并确认预期的屏幕,而不是重新读取:比观察便宜 19–23 倍(2.3 ms 对比 43–50 ms)。
一个预测必须被看到两次才会被信任,如果被证明是错的就会被弃用,并且会以与记住的屏幕相同的两种方式进行检查。失败的预测会以 surprise 的形式报告给代理——界面做了它通常不会做的事情,这值得知晓,而不是被默默吸收。
已确认的预测能保证什么: 布局——相同的控件位于相同的位置。而不是每个字符都完全相同。单个数字的变化所影响的像素比闪烁的光标还少,因此任何分辨率下的整屏检查都无法将它们区分开。当精确文本很重要时,请使用 observe(force_full=True)。
可通过 --no-speculate 禁用。
只等待必要的时间
动作工具过去会固定休眠 300 ms,这是为最慢的情况选择的,因此每个动作都按最坏情况付出代价。合成器知道屏幕何时停止变化,因此现在等待会在界面真正稳定时结束:
之前的固定休眠 | 300 ms |
实际等待中位数 | 61.5 ms |
50 步任务中节省的时间 | 11.9 s |
"稳定"表示最近没有大的变化,而不是没有变化:真实的桌面永远不会静止——光标和时钟每 ~18 ms 产生一次变化事件,覆盖约 32 个像素,而真正的 UI 变化覆盖数以万计的像素。
尚未完成
Wayland 输入注入,以及作为 TextPattern 等效物的 macOS
AXTextMarker。视觉模型层级,用于既不可访问又无法清晰读取文本的表面:游戏、画布、图像编辑器。
以不止前一个屏幕为键的转换,用于结果取决于不可见状态的动作。
测量了什么,以及没有测量什么
感知成本和任务成功率都在本机上进行了测量,并可通过 benchmarks/ 重现——在四个应用中,更便宜的感知并不会以准确性为代价,而且像素/无障碍的划分是测量出来的,而非争论出来的。
与 Windows-MCP 对比
相同的任务,四个场景,每个都由应用本身评分。两个工具都不自我评分,Windows-MCP 使用其默认设置运行:
计算器 | 资源管理器 | Chrome | Chrome,2 步 | 通过 | tokens | |
oswright | 5/5 | 4/5 | 5/5 | 5/5 | 19/20 | 832 |
Windows-MCP,每次动作快照 | 5/5 | 5/5 | 5/5 | 5/5 | 20/20 | 14,053 |
Windows-MCP,仅快照一次 | 5/5 | 5/5 | 5/5 | 5/5 | 20/20 | 8,214 |
坦白说:Windows-MCP 更可靠,而 oswright 便宜 16.9 倍。 oswright 每二十次点击丢掉一次,发生在一个刚刚打开的窗口上。
成本差异是结构性的,而不是调优的结果。Windows-MCP 将屏幕返回给代理——Snapshot 将无障碍树渲染为 (x,y) button "Seven" [action: click]——并取回坐标,因此屏幕描述会在每次动作时计入模型的上下文。oswright 接收文本并返回结果。
可靠性差距可能正是由速度造成的:oswright 在 ~100 ms 内完成解析并点击,有时在一个刚获得焦点的窗口准备好接收输入之前就完成了,而较慢的循环给了应用它从未需要主动索取的时间。这是一个假设,而非结论——在十次试验中,添加动作前的稳定等待没有产生可测量的差异,因此它被记录下来,而不是被修复。
Chrome, 2 steps 场景之所以存在,是因为这里的其他任务都足够短,工具可以读取一次屏幕并复用那些坐标。而在该场景中,第一次点击将控件向下移动 325 px,因此只快照一次的配置不得不重新读取屏幕——所以在界面会移动的任务中,它那个便宜的数字并不存在,其真实成本是每次动作的成本。
使用 python benchmarks/bench_head_to_head.py 重现(设置方法见文件中的 docstring)。
这并不能证明什么: 一台笔记本电脑上的四个短任务。不涉及长期多步骤工作、恢复或产品成熟度——Windows-MCP 拥有 OAuth、分析、看门狗和安装程序;oswright 这些都没有。它的无障碍遍历还会读取 Chrome 的页面内容,而 oswright 自己的无障碍层级则不会。"每次动作大幅更便宜,以很小的可靠性代价"是它的主张。"更好的产品"则不是。
开发
pip install -e ".[dev]"
pytest tests/ # everything available on this machine
pytest tests/ -m "not e2e" # unit tests only, no desktop needed
ruff check oswright tests # lint
python benchmarks/bench_pipeline.py # reproduce the performance numbers
python benchmarks/bench_tasks.py # task success (opens Calculator repeatedly)设计决策、测量结果和死胡同都记录在 docs/ENGINEERING_LOG.md 中。
许可证
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Connect ChatGPT, Claude, Cursor or VS Code to your Windows PC: files, terminal, browser, apps.
Cloud desktops for AI agents: create a Linux computer, see its screen, click, type and run tasks.
Connect AI assistants to your approved computer for files, commands, browser and desktop tasks.
Visual testing for coding agents: your agent sees every UI change it makes and triages each diff.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables low-cost agent models to control Windows applications through a compact, state-safe proxy over Open Computer Use, reducing model-visible context by up to 99.8% with support for record/replay and reusable UI component memory.5MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to see, locate UI elements, and operate any Windows desktop app through natural language, using accessibility-tree matching with optional vision-model fallback, plus an autonomous visual loop with introspection and meta-learning.13MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to safely and truthfully control local desktop applications via native accessibility trees, supporting element inspection and automation without proprietary binaries or fake success responses.Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables coding agents to drive any Windows desktop app through window-relative, token-efficient tools, with optional DeepSeek-powered vision.Apache 2.0