Skip to main content
Glama

OSWright

PyPI Tests Python License

面向 AI 代理的桌面自动化,无需为每一步截屏付费。

mcp-name: io.github.Ask-812/oswright

这是一个 MCP 服务器,让 LLM 能够驱动真实的桌面应用程序——相当于桌面版的 Playwright MCP。它在操作之间保留屏幕模型,只重新读取发生变化的部分,因此同样的工作所消耗的 token 数量减少一个数量级。

OSWright 正在将发票转录到费用表单

从发票上读取八个字段并输入费用表单,由应用程序本身验证。同样的任务、同样的结果,与每次操作后返回截图相比,上下文减少 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 oswright

Related MCP server: AutoFlow

增量感知

大多数 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_elementclick_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 再次抓取——在本文的测量中比 mss1.5–2.3 倍

合成器仅用作变更检测的快速 否定。当它报告有变化时,脏区域仍然来自对捕获帧的哈希计算:两者的测量间隔略有不同,因此合成器矩形相对于实际捕获的像素可能少报,而少报的区域就是永远不会被重新读取的文本。在 Desktop Duplication 不可用的地方,它会静默降级为瓦片哈希和正常捕获。

使用 --observation-mode delta 为操作工具启用增量观察。默认值仍为 screenshot,以兼容现有客户端。

请自行完整复现所有这些: 参见 benchmarks/。 每个决策背后的理由(包括走过的弯路)都记录在 docs/ENGINEERING_LOG.md 中。

配置

OSWright MCP 服务器支持以下参数。它们可以在 JSON 配置中作为 "args" 列表的一部分提供:

选项

描述

环境变量

--port <port>

SSE 传输的端口。若省略,则使用 stdio(默认)。

FASTMCP_PORT

--host <host>

HTTP/SSE 服务器绑定的主机。默认:127.0.0.1

FASTMCP_HOST

--transport <mode>

传输协议:stdiossestreamable-http。根据 --port 自动检测。

--ocr-languages <langs>

OCR 语言(默认:en)。示例:--ocr-languages en es fr

OSWRIGHT_OCR_LANGUAGES

--timeout <seconds>

自动等待操作的默认超时(默认:10)。

OSWRIGHT_TIMEOUT

--snapshot-max-width <px>

对每次操作后返回的自动快照进行降采样。0(默认)保持完整分辨率。较低的值可显著降低 token 成本。

OSWRIGHT_SNAPSHOT_MAX_WIDTH

--observation-mode <mode>

操作工具返回的内容:screenshot(默认)、delta(仅返回变化部分,token 数约为原来的 1/30)或 both

OSWRIGHT_OBSERVATION_MODE

--no-atlas

不跨访问记忆屏幕。

OSWRIGHT_NO_ATLAS

--no-speculate

不预测操作结果。

OSWRIGHT_NO_SPECULATE

--allow-remote

绑定非回环地址时需要。参见 安全

--log-level <level>

日志级别:DEBUGINFOWARNINGERROR。默认:INFO

OSWRIGHT_LOG_LEVEL

显式命令行标志始终优先于相应的环境变量。

示例:多语言 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-host

Stdio 传输(默认方式,上述所有 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_titlemax_depth

    • 只读:true

  • click_ui_element -- 使用无障碍树点击 UI 元素。比 OCR 更可靠。

    • 参数:namecontrol_typeautomation_idwindow_title

  • fill_ui_element -- 设置 UI 元素(例如文本框)的值。比基于 OCR 的填充更可靠。

    • 参数:valuenameautomation_idwindow_title

  • get_active_window -- 获取当前焦点窗口的信息。

    • 只读:true

  • wait_for_change -- 等待屏幕发生视觉变化。截取基准截图,轮询直到画面不同。

    • 参数:timeoutpoll_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

Maintenance

ActivityMaintained
ResponsivenessSyncing

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

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI coding agents to automate Windows desktop applications through semantic UI Automation instead of brittle coordinate clicks, with tools for discovering windows, finding controls by stable identifiers, and verifying actions.
    1
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    AutoFlow enables AI agents to automate Windows desktop tasks by visually recognizing screen elements and simulating keyboard and mouse actions, with 18 MCP tools for workflow control.
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to query Windows process, window, and console information via structured JSON instead of screenshots, reducing token usage by 94-98%.
    20
    51
    1
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables 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.
    5
    MIT

Latest Blog Posts

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/Ask-812/oswright'

If you have feedback or need assistance with the MCP directory API, please join our Discord server