关于 Screen Control
Screen Control 是面向 AI Agent 的本地电脑控制服务,提供屏幕读取以及鼠标、键盘和窗口操作。它结合 OCR 与图像查看,并在服务端执行安全检查,所有操作均在本机运行。
主要功能
- 01通过 OCR 和图像帧读取屏幕
- 02实时传输屏幕画面
- 03控制鼠标和键盘
- 04管理窗口与虚拟桌面
- 05执行令牌认证和安全防护
- 06通过 HTTP 或 MCP 操作
适用场景
- 01让 Agent 查看并操作桌面应用
- 02自动执行需要鼠标或键盘输入的任务
- 03为支持图像或仅支持文本的模型读取屏幕内容
- 04使用本地控制服务,避免数据发送到云端
MCP 相关
Screen Control 除 HTTP API 外,还通过 MCP 接口提供电脑感知与控制能力。它支持 Claude Desktop、Cursor 和 VS Code 等 MCP 客户端。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
🖥️ 让所有 Agent 都能操作电脑
面向 AI Agent 的本地远程控制系统:实时查看电脑屏幕,并向电脑发送鼠标/键盘命令。所有操作都在你自己的设备上运行——数据绝不会离开设备,也不经过云端中间服务。
此 GIF 中的每次按键和每张屏幕截图都通过 API 完成——Agent 从未触碰实体键盘。
致 AI Agent
请先阅读 AGENT_GUIDE.md——此文档专为你编写,包含端点、安全防护和实用操作示例。本 README 是面向人类用户的参考文档。
首先询问服务端的信息——GET /api/capabilities → platform。
Windows: 按照指南全文操作。Linux: 检查
echo $XDG_SESSION_TYPE——支持 X11(参阅指南 →
Linux(X11)使用说明);不支持 Wayland:服务端会拒绝启动,并返回 HTTP 501
UNSUPPORTED_DISPLAY_SERVER(请切换到 X11 会话)。完整的环境路由说明见 AGENT_GUIDE.md → 先确认你的环境。
为什么选择屏幕控制?
如今的 AI Agent 可以编写代码、调用 API,却无法 看到 或 操作 你的桌面。屏幕控制通过简洁且具备安全防护的 HTTP/MCP 接口,让任何 Agent 都能通用地操作电脑:
- 感知——通过 OCR 识别文本;获取单帧画面或实时 MJPEG 流,供具备视觉能力的模型使用;还可通过纯文本差异端点,为完全无法处理图像的模型提供信息。
- 操作——支持绝对和相对鼠标操作、Unicode 安全键盘输入、窗口管理、后台(无需聚焦)控制和虚拟桌面。
- 保障安全——服务端始终强制执行令牌身份验证、危险快捷键屏蔽、焦点保护、输入卡死监控和紧急故障保护,无论 Agent 多么混乱都不例外。
只需一个进程,无需配置,任何支持 HTTP 的语言均可使用;也可通过 MCP 原生接入 Claude Desktop、Cursor、VS Code 和云端 Agent。
性能受限于 Agent
Screen Control 是感知与执行层——也就是眼睛和双手。 使用它的任何 Agent 的实际速度和能力,都受该 Agent 本身及其运行环境的限制:
- 思考速度 — 每个 Agent“回合”执行一个动作:感知 → 规划 → 执行 → 验证的循环由 Agent 完成,因此模型推理延迟和推理深度会直接决定节奏。API 本身每次调用只增加几毫秒延迟。
- 上下文容量 — 屏幕读取内容(OCR 文本、帧、差异)会占用 Agent 的上下文窗口;窗口越大,在验证效果下降前就能掌握更多情境。
- 运行环境 — 网络延迟、MCP/HTTP 往返开销、工具调用限制和托管约束都会叠加到循环中。
实际情况是:同一个 repo,能让推理速度快的模型表现得又快又强,也会让慢模型表现得很慢——工具链并非瓶颈。 实时或操作密集型任务需要推理速度快、工具循环延迟低的 Agent;速度较慢的 Agent 则应优先处理需要深思熟虑、频繁验证的任务。
目录
- 如果你是 AI Agent
- 为什么选择 Screen Control?
- 功能
- 架构
- 安装
- Linux(X11)
- 快速开始
- API 参考
- 🤖 面向 AI Agent
- MCP 支持(一键式云端 Agent)
- 安全模型
- 游戏模式指南
- 视觉访问指南
- 故障排除
- 测试
- 贡献
- 许可证
功能
| 功能 | 描述 |
|---|---|
| 🖼️ 实时屏幕画面 | 浏览器中持续刷新的屏幕截图 |
| 🖱️ 鼠标控制 | 通过实时屏幕截图执行单击、右键单击、双击、滚动、拖放 |
| ⌨️ 键盘控制 | 输入文本(支持 Unicode/Turkish,不受键盘布局影响)、按键和快捷键(Ctrl+C、Alt+Tab…) |
| 👁️ OCR | 将屏幕上的文本转换为机器可读格式 |
| 📷 视觉访问 | 面向具备图像处理能力的模型的原始像素路径:单帧、MJPEG 流、基于文本的动作检测 |
| 🪟 窗口管理 | 列出、聚焦、安全关闭(WM_CLOSE)、强制结束(类似任务管理器) |
| 🖥️ 免焦点控制 | 通过 PostMessage 读取/写入后台窗口,且不会抢占焦点 |
| 🎮 游戏模式 | 通过相对鼠标移动控制视角,按住按键持续移动 |
| 🔐 令牌身份验证 | 每个请求都需要 X-Auth-Token(CSRF 防护) |
| 🦺 输入卡住监视器 | 闲置 30 s 后自动释放按住的按键 |
| 🛟 故障保护 | 将光标移至左上角即可中止所有命令(游戏模式下禁用) |
架构
┌─────────────────────────────────────────────────────────┐
│ Browser (Web UI) │
│ ┌──────────┐ ┌──────────┐ ┌────────────────────────┐ │
│ │ Live │ │ Control │ │ Windows / Game Mode │ │
│ │ View │ │ Panel │ │ Panel │ │
│ └────┬─────┘ └────┬─────┘ └───────────┬────────────┘ │
│ │ │ │ │
└───────┼──────────────┼─────────────────────┼──────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ HTTP API (Flask) │
│ 127.0.0.1:8745 │
│ │
│ /api/screenshot /api/mouse /api/key │
│ /api/vision/* /api/ocr /api/window │
│ /api/game /api/held /api/release_all │
│ /api/windows /api/desktops /api/desktop │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Auth Layer │ │ Watchdog │ │ OCR Engine │ │
│ │ (token) │ │ (30s auto) │ │ (RapidOCR) │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ control.py (Core) │
│ │
│ Screen: mss (fast capture), PIL (processing) │
│ Mouse: pyautogui (absolute), SendInput (relative) │
│ Keyboard: pyautogui + SendInput+KEYEVENTF_UNICODE │
│ Windows: Win32 API (EnumWindows, SetForegroundWindow) │
│ Background: PrintWindow (capture), PostMessage (input) │
│ Virtual Desktops: pyvda │
│ Game Mode: ClipCursor + MOUSE_MOVE_RELATIVE │
└─────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ backends/ (pluggable) │
│ WindowsBackend │ LinuxBackend │ MacOSBackend│
│ (full) │ (X11) │ (stub) │
└──────────────────────────────────────────────┘
坐标与并发
逐显示器 DPI 感知。 control.py 在导入时调用
SetProcessDpiAwarenessContext(PER_MONITOR_AWARE_V2) ——
早于导入 pyautogui,因为 pyautogui 在导入期间会访问坐标 API,
否则会将进程锁定为解释器清单的默认设置(系统感知)。启用 PMv2 后,系统中的每个坐标
从头到尾都是物理像素:mss 截屏、OCR 边界框、
pyautogui/SendInput 点击、ClipCursor。在高 DPI 显示器(125%/150%
缩放)上,OCR 报告的位置与鼠标点击的位置之间不会出现偏移。
锁架构。 服务使用两个独立的锁,而非一个 全局锁:
| 锁 | 保护对象 | 端点 |
|---|---|---|
_input_lock | 鼠标、键盘、游戏模式、窗口操作 | /api/mouse、/api/key、/api/game、/api/window/post、... |
_read_lock | 截屏、OCR、视觉、枚举 | /api/screenshot、/api/ocr、/api/vision/*、/api/windows、... |
缓慢的 OCR(繁忙屏幕上需要 3–5 s)不再会阻塞并发的截屏或 视觉读取 —— 读取排在读取之后,输入排在输入之后。
实时循环工作原理
本系统专为实时感知-行动循环设计,而非预先编写的 命令链:
- 读取 — 每次操作前后都通过 OCR 或视觉读取屏幕
- 单次操作 — 每轮只发送一条命令
- 验证 — 验收标准是“内容出现在屏幕上”,而不是“我已发送命令”
- 调整 — 如果验证失败,下一步会根据实际看到的内容进行调整
这一机制由 expect_hwnd 守卫强制执行:如果前台窗口与目标不匹配,
则会拒绝输入(409)。
安装
根据 Agent 的工作方式选择合适的版本:
| 你是…… | 版本 | 安装 |
|---|---|---|
| AI Agent 用户(Claude Code、Cursor、支持技能的 Agent) | Skill | Skill 版本 — 将 skills/computer-use/ 复制到 Agent 的技能文件夹中 |
| 支持 MCP 的应用(Claude Desktop、VS Code、云端 Agent) | MCP | MCP 支持 — 通过 stdio 或 streamable-HTTP 运行 mcp_server.py |
| 开发者 / API 客户端 | REST | 本页面 — pip install -r requirements.txt + python server.py |
Skill 版本
可移植的 Agent 技能位于 skills/computer-use/
(SKILL.md 加完整的 API 参考)。它会教会任何支持技能的 Agent
感知-行动-验证循环、安全规则和端点目录 —
然后由 Agent 驱动正在运行的服务。
# Claude Code — user-level (available in every project)
cp -r skills/computer-use ~/.claude/skills/
# Claude Code — this project only
mkdir -p .claude/skills && cp -r skills/computer-use .claude/skills/
对于其他支持技能的 Agent,请将该文件夹复制到该 Agent 自己的技能
目录中。无论采用哪种方式,服务都必须正在运行(python server.py)—
技能提供的是操作说明,而非后端。
REST 服务
cd screen-control
pip install -r requirements.txt
要求
| 软件包 | 用途 | 是否必需? |
|---|---|---|
mss | 快速截屏 | ✅ 是 |
pyautogui | 鼠标/键盘控制 | ✅ 是 |
pyvda | 虚拟桌面管理 | ✅ 是 |
flask | HTTP 服务 | ✅ 是 |
Pillow | 图像处理 | ✅ 是 |
rapidocr-onnxruntime | OCR(屏幕文字读取) | ⚠️ 可选 |
注意: OCR 软件包体积较大,安装可能需要一些时间。如果安装 失败,其他功能仍可正常使用 — 只有 OCR 功能不可用。
系统要求
- 操作系统: Windows 10/11(x64),或 Linux(Ubuntu/Mint 系列,X11 会话 — 参见 Linux(X11))
- Python: 3.10+
- 显示器: 任意分辨率;系统会自动适配
Linux(X11)
Linux 支持但有限制(路线图第 5 阶段)— 已在 X11 会话下的 Linux Mint Cinnamon 桌面环境中测试;预计其他 X11 桌面环境也能正常工作。Windows 仍是参考后端。
系统要求
- 操作系统: Ubuntu / Linux Mint 系列(基于 apt)
- 会话: X11——先检查:
echo $XDG_SESSION_TYPE # must print: x11
- Wayland? 不支持——服务会快速失败,而不是半工作状态 (请参见已知限制)。
- 系统软件包(由下方的安装脚本安装):
sudo apt install -y xdotool wmctrl imagemagick python3-venv python3-tk python3-dev
xdotool 用于驱动输入和窗口焦点,wmctrl 用于窗口管理,ImageMagick 的
import 用于捕获窗口像素(可选——也提供 mss 区域回退方案),
python3-venv 用于创建虚拟环境,python3-dev 允许 evdev
(游戏模式)从源代码编译。
一条命令完成设置
cd screen-control
./install-linux.sh
该脚本可重复运行,并按顺序检查:Wayland(清晰提示后退出)、DISPLAY、apt 软件包、.venv 虚拟环境、pip install -r requirements.txt,最后报告游戏模式是否可用。
uinput 权限(游戏模式)
游戏模式会写入 /dev/uinput。使用以下命令验证访问权限:
[ -w /dev/uinput ] && echo "game mode: OK" || echo "game mode: unavailable"
如果无法访问,可采用以下任一修复方式(规范 §5.4):
sudo usermod -aG input $USER # then log out and back in
# — or a udev rule:
echo 'KERNEL=="uinput", MODE="0660", GROUP="input"' | sudo tee /etc/udev/rules.d/99-uinput.rules
sudo udevadm control --reload && sudo udevadm trigger
除游戏模式外,其他功能均不需要此访问权限。
运行
./start-server.sh
# → same API as Windows: http://127.0.0.1:8745 (X-Auth-Token from .token)
已知限制(Linux X11)
| 限制 | 详情 |
|---|---|
| 仅支持 X11 | 在 Wayland 下,后端会快速失败:ApiError("UNSUPPORTED_DISPLAY_SERVER")(HTTP 501),并且 server.py 会打印该消息并退出,而不会启动服务。修复方法:注销 → 在登录屏幕选择会话 → 选择“Cinnamon on Xorg”。Wayland 支持属于 ROADMAP Phase 6。 |
| 后台输入 = 先获取焦点 | 每个 /api/window/post 操作都会先聚焦目标窗口,然后全局发送输入(X11 没有可靠的已投递消息路径)——也就是说会抢占焦点。capabilities.background_input 为 false。 |
| 游戏模式下不限制光标 | X11 无法限制光标;游戏必须自行捕获指针。紧急停止方式:按实体键盘上的 Esc/Alt+Tab,或调用 POST /api/release_all。 |
| 不支持虚拟桌面 | capabilities.virtual_desktops 为 false;GET /api/desktops 和 POST /api/desktop 返回 503。 |
| 尚未测试小数缩放 | 验证显示器的缩放比例为 1.0;小数缩放下的坐标尚未验证。 |
capture_window(窗口捕获) | 对 client=0 和 client=1 均仅捕获客户区——不会捕获装饰(在 Windows 上,client=0 会包含边框)。安装了 ImageMagick 时使用 import(即使窗口被遮挡,通常也能获取窗口自身的像素);否则回退到使用 mss 截取窗口矩形区域,因此被遮挡的窗口会显示上层窗口的内容。失败时返回 HTTP 409。 |
| 窗口几何信息来源 | rect 来自 xwininfo -root -tree 的绝对边界——即外框/窗口边界(与 Windows GetWindowRect 一致);client_to_screen 使用 xwininfo 的“Absolute upper-left”。 |
window_hotkey 响应 | 返回 {"ok","vk","vks"};对于热键操作,vk(X11 keysym)仅在 Linux 上存在(Windows 返回 {"ok","vks"})——跨平台代码必须读取 vks。 |
Agent 提示: OCR 是最慢的读取方式(全屏测得约 5–6 s)。 重复读取时优先使用
/api/vision/frame或/api/stream,使用区域 OCR,并在操作之间批量读取——请参见 AGENT_GUIDE.md → Linux (X11) Usage。
快速入门
# 1. Start the server
cd screen-control
python server.py
# 2. Open in browser
# http://127.0.0.1:8745
# 3. Or control via API
TOKEN=$(cat .token)
curl -H "X-Auth-Token: $TOKEN" http://127.0.0.1:8745/api/screenshot -o screen.jpg
API 参考
功能特性
返回当前后端名称及其支持的功能。Agent 应先调用此接口(多平台计划请参见 ROADMAP.md)。
GET /api/capabilities
→ {"ok": true, "backend": "windows",
"capabilities": {"screen_capture": true, "game_mode": true, ...}}
功能值:true(支持)、false(不支持)、null(未知——存根后端)、"optional"(取决于可选依赖)。
平台支持矩阵
| 能力 | Windows | Linux X11 | Linux Wayland† | macOS |
|---|---|---|---|---|
| 屏幕捕获 | 完整 | 完整 | 取决于 Portal | 需要权限 |
| OCR | 完整/可选 | 完整/可选 | 完整/可选 | 完整/可选 |
| 鼠标控制 | 完整 | 完整 | 受限 | 需要辅助功能权限 |
| 键盘控制 | 完整 | 完整 | 受限 | 需要辅助功能权限 |
| 窗口枚举 | 完整 | 取决于 WM | 有限 | 取决于辅助功能/API |
| 后台输入 | 强 | 优先聚焦(会抢占焦点) | 通常不可用 | 有限 |
| 虚拟桌面 | 支持 | 不支持(503) | 取决于 DE/WM | 特定于 Spaces |
| 游戏模式 | 支持 | 实验性 | 有限 | 实验性 |
Linux X11 已实现并受支持,但存在限制——设置、要求和完整的限制列表见 Linux (X11)。Wayland 会快速失败并返回
UNSUPPORTED_DISPLAY_SERVER(501),而 macOS 仍是默认拒绝的存根:在 ROADMAP 第 7 阶段之前,每项操作都会返回BACKEND_UNAVAILABLE(501)。Windows 是参考后端。† Wayland 列仅用于假设性的能力规划——服务不会在 Wayland 上启动(参见上面的说明),因此目前无法使用任何 Wayland 单元格。
身份验证
每个请求都必须包含 X-Auth-Token 标头。令牌会在每次服务启动时生成,并写入 .token。
TOKEN=$(cat .token)
| 代码 | 含义 |
|---|---|
| 401 | 缺少令牌或令牌无效 |
| 415 | POST 请求缺少 Content-Type: application/json |
令牌引导(用于捆绑的 Web UI):
GET /token
→ {"ok": true, "token": "abc123..."}
/token端点是安全的:同源策略会阻止外部页面读取它。
屏幕捕获
GET /api/screenshot
返回 JPEG 屏幕截图。
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
monitor | int | 1 | 显示器索引 |
region | string | — | x,y,w,h 子区域 |
curl -H "X-Auth-Token: $TOKEN" -o screen.jpg http://127.0.0.1:8745/api/screenshot
curl -H "X-Auth-Token: $TOKEN" "http://127.0.0.1:8745/api/screenshot?region=0,0,800,600"
GET /api/info
返回屏幕尺寸和系统状态。
{"ok": true, "width": 1920, "height": 1080, "ocr_available": true,
"failsafe": true, "game_mode": false}
鼠标控制
POST /api/mouse
| action | 必需参数 | 可选参数 | 描述 |
|---|---|---|---|
move | x、y | duration(默认值为 0.15) | 将光标移动到绝对位置 |
click | x、y | button(left/right)、clicks(默认值为 1) | 单击指定位置 |
scroll | clicks | x、y | 滚动滚轮(正数=向上) |
drag | x1、y1、x、y | duration、button | 在两点之间拖动 |
down | button(默认值为 "left") | — | 按住鼠标按钮 |
up | button(默认值为 "left") | — | 松开鼠标按钮 |
# Click at center of screen
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"click","x":960,"y":540,"button":"left"}'
# Right-click
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"click","button":"right","x":960,"y":540}'
# Scroll down
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"scroll","clicks":-3}'
键盘控制
POST /api/key
| action | 必需参数 | 描述 |
|---|---|---|
press | key | 按下并释放按键 |
down | key | 按住按键(由看门狗跟踪) |
up | key | 释放按住的按键 |
hotkey | keys(数组) | 按键组合(例如 ["ctrl","c"]) |
type | text | 输入文本(Unicode,与键盘布局无关) |
| 可选参数 | 默认值 | 描述 |
|---|---|---|
expect_hwnd | — | 用于验证焦点的窗口句柄(不匹配时返回 409) |
interval | 0.03 | type 输入字符之间的延迟 |
# Press Enter
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"press","key":"enter"}'
# Ctrl+C
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"hotkey","keys":["ctrl","c"]}'
# Type text (Turkish characters supported)
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"type","text":"Merhaba dünya"}'
# Hold W key down (for walking in games)
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"down","key":"w"}'
OCR(屏幕读取)
POST /api/ocr
将屏幕上的文本转换为机器可读格式。
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
region | array | — | [x, y, w, h] 子区域(速度更快) |
{
"ok": true,
"text": "Hello World\nFile Edit View",
"lines": ["Hello World", "File Edit View"],
"items": [
{"text": "Hello World", "x": 960, "y": 40},
{"text": "File Edit View", "x": 100, "y": 15}
]
}
# Full screen OCR
curl -X POST http://127.0.0.1:8745/api/ocr -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{}'
# Region-only (faster, ~10x for small regions)
curl -X POST http://127.0.0.1:8745/api/ocr -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"region":[0,0,800,100]}'
视觉访问(图像模型)
为能够处理图像的模型提供三个端点:
| 端点 | 描述 |
|---|---|
GET /api/vision/frame | 单帧 JPEG(原始格式或 base64) |
GET /api/stream | MJPEG 实时流 |
POST /api/vision/diff | 基于文本的运动检测(无需视觉处理) |
GET /api/vision/frame
| 参数 | 默认值 | 描述 |
|---|---|---|
scale | 1.0 | 缩小比例(0.5 = 一半大小) |
gray | 0 | 设为 1 时转为灰度图 |
quality | 80 | JPEG 质量(20-95) |
format | — | 返回 JSON 时设为 base64 |
region | — | x,y,w,h 子区域 |
# Half-size greyscale frame as base64 (for text-only models)
curl "http://127.0.0.1:8745/api/vision/frame?scale=0.5&gray=1&format=base64" \
-H "X-Auth-Token: $TOKEN"
GET /api/stream
MJPEG 实时流。可放入 <img src>,也可逐帧读取。
| 参数 | 默认值 | 描述 |
|---|---|---|
fps | 10 | 每秒帧数(1-30) |
quality | 70 | JPEG 质量 |
scale | 1.0 | 缩小比例 |
region | — | x,y,w,h 子区域 |
POST /api/vision/diff
基于文本的运动检测——无需视觉模型。
| 请求体 | 描述 |
|---|---|
{} | 与上次存储的帧进行比较 |
{"grab":"gray"} | 存储当前帧以供下次比较 |
{"b64_prev":"..."} | 与提供的上一帧进行比较 |
{
"ok": true,
"changed": true,
"changed_pct": 12.5,
"bbox": [100, 200, 400, 350],
"tiles": [
{"row": 2, "col": 4, "pct": 35.2, "center": [1000, 390]}
]
}
窗口管理
GET /api/windows
列出所有可见窗口。
{
"ok": true,
"windows": [
{
"hwnd": 123456,
"title": "My Application",
"process": "app.exe",
"pid": 7890,
"focused": true,
"rect": [0, 0, 1920, 1080],
"desktop": 1
}
]
}
POST /api/window
| 操作 | 必填 | 可选 | 描述 |
|---|---|---|---|
focus | hwnd | — | 将窗口置于前台 |
close | hwnd | expect_title、expect_process | 通过 WM_CLOSE 安全关闭 |
kill | hwnd、pid | — | 强制终止(类似任务管理器) |
topmost | hwnd | — | 设为始终置顶 |
untopmost | hwnd | — | 取消始终置顶 |
maximize | hwnd | — | 最大化窗口 |
# Focus a window
curl -X POST http://127.0.0.1:8745/api/window -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"hwnd":12345,"action":"focus"}'
# Safe close (with title verification)
curl -X POST http://127.0.0.1:8745/api/window -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"close","hwnd":12345,"expect_title":"Notepad"}'
# Kill process
curl -X POST http://127.0.0.1:8745/api/window -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"kill","hwnd":12345,"pid":7890}'
POST /api/launch
启动应用、打开 URL 或打开本地文件。app、url、file 三者必须且只能指定一个。绝不会通过 shell 运行:app 是在 PATH 上解析的普通命令名称([A-Za-z0-9._+-]+),url/file 则通过 xdg-open 打开。
| 字段 | 类型 | 描述 |
|---|---|---|
app | string | 命令名称;必须存在于 PATH 中(否则返回 400) |
url | string | scheme://...(例如 https://、steam://) |
file | string | 现有文件的绝对路径 |
args | list | 仅用于 app 的参数 |
expect_title | string | 同时等待标题包含此内容的窗口 |
timeout | number | 等待 expect_title:默认 10,最长 30 秒 |
{"ok": true, "pid": 4321, "window": {"hwnd": ..., "title": "..."}}
设置 expect_title 后,window 为匹配到的窗口或 null(启动成功,但窗口尚未出现)——无论哪种情况,HTTP 状态码均为 200。
curl -X POST http://127.0.0.1:8745/api/launch -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"app":"firefox","expect_title":"Mozilla Firefox","timeout":15}'
GET /api/window/wait
阻塞等待标题包含 title(不区分大小写的子字符串)的窗口出现,然后返回该窗口。timeout 默认 10 秒,最长 30 秒;找到窗口时返回 200,超时则返回 408 OPERATION_TIMEOUT。
curl -H "X-Auth-Token: $TOKEN" \
"http://127.0.0.1:8745/api/window/wait?title=Notepad&timeout=10"
无需切换焦点(后台)控制
无需窃取焦点即可读取和控制窗口——用户可以继续在主桌面上工作。
Linux(X11)说明:后台控制采用先切换焦点的方式——先聚焦目标窗口,再向全局发送输入(会窃取焦点)。 只有后台捕获真正无需切换焦点。请参阅 已知限制。
GET /api/window/capture
通过 PrintWindow 捕获窗口(即使窗口位于其他虚拟桌面也有效)。
| 参数 | 描述 |
|---|---|
hwnd(必填) | 窗口句柄 |
client | 1 = 仅捕获客户区 |
ocr | 1 = 返回 OCR 文本而非图像 |
# Capture window as PNG
curl "http://127.0.0.1:8745/api/window/capture?hwnd=12345" \
-H "X-Auth-Token: $TOKEN" -o window.png
# Capture + OCR in one call
curl "http://127.0.0.1:8745/api/window/capture?hwnd=12345&ocr=1" \
-H "X-Auth-Token: $TOKEN"
POST /api/window/post
向窗口发送输入,并自动选择传递路径。
| action | Description |
|---|---|
type | 输入文本(支持 Unicode) |
key | 发送按键 |
hotkey | 发送组合键 |
click | 在客户端坐标处单击 |
scroll | 滚动窗口 |
drag | 在窗口内拖动 |
可选的 mode 参数控制路由:
| mode | Behavior |
|---|---|
auto(默认) | 由输入模式探测决定(见下文) |
background | 强制使用 PostMessage 路径(窗口保持焦点和 Z 序) |
focused | 强制使用聚焦 + SendInput 路径 |
# Type into a background Notepad
curl -X POST http://127.0.0.1:8745/api/window/post -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"hwnd":12345,"action":"type","text":"Hello from background!"}'
路由规则(mode=auto):
postmessage— 传统 Win32 应用:在后台使用 PostMessage,不改变焦点。uia— WinUI/UWP/XAML 界面(单个 DirectX 画布,没有 Win32 子控件):投递的消息会被静默丢弃,因此窗口会获得焦点,并通过 SendInput 重放操作(将客户端坐标转换为屏幕坐标)。这是现代应用中有文档说明的回退方式。focused— 窗口已处于前台:使用聚焦的 SendInput 路径。invalid— HTTP 409;不是可访问的顶层窗口。
GET /api/window/input-mode
在向窗口发送输入前,判断窗口接收输入的方式。返回以下值之一:
focused | postmessage | uia | invalid。
curl "http://127.0.0.1:8745/api/window/input-mode?hwnd=12345" \
-H "X-Auth-Token: $TOKEN"
**WinUI 说明:**新版记事本(以及其他由 XAML 承载的应用)没有可供发送消息的传统子级 Edit 控件——整个 UI 是一个 DirectX 界面。 对于这些应用,
input-mode会返回uia;随后/api/window/post会自动使用聚焦的 SendInput 路径。对于具有真实子控件的传统应用,/api/window/children仍然很有用。
GET /api/window/children
列出窗口的子控件(类名 + 标题 + hwnd)。
curl "http://127.0.0.1:8745/api/window/children?hwnd=12345" -H "X-Auth-Token: $TOKEN"
虚拟桌面
GET /api/desktops
列出所有虚拟桌面。
POST /api/desktop
| action | Params | Description |
|---|---|---|
switch | number | 切换到桌面 N |
create | — | 创建新的桌面 |
curl http://127.0.0.1:8745/api/desktops -H "X-Auth-Token: $TOKEN"
curl -X POST http://127.0.0.1:8745/api/desktop -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"switch","number":2}'
游戏模式
| action | Params | Description |
|---|---|---|
start | sensitivity(默认 12) | 将光标锁定在中心,启用游戏输入 |
move | dx、dy、sensitivity | 旋转摄像机(相对鼠标) |
stop | — | 释放光标 + 所有按住的输入 |
heartbeat | — | 长时间按住时保持连接 |
# Start game mode
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"start","sensitivity":12}'
# Look right
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"move","dx":50,"dy":0}'
# Hold W to walk forward
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"down","key":"w"}'
# ... later ...
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"up","key":"w"}'
# Stop game mode
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"stop"}'
安全端点
GET /api/held
返回当前按住的按键/按钮以及看门狗状态。
{
"ok": true,
"keys": ["w", "shift"],
"buttons": ["left"],
"game_mode": true,
"idle_seconds": 5.2,
"watchdog_count": 0,
"last_watchdog": null
}
POST /api/release_all
紧急操作:释放所有内容(按住的按键、鼠标按钮、游戏模式光标锁定)。
curl -X POST http://127.0.0.1:8745/api/release_all -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{}'
🤖 面向 AI Agent
为 AI Agent(大模型、视觉模型、自动化框架)提供的专用综合指南见 AGENT_GUIDE.md。
更愿意将其作为技能加载,而不是浏览文档?请安装技能版本。
内容包括:
- 环境路由——先识别 Windows 还是 Linux(X11/Wayland)
- 感知-行动循环(读取 → 规划 → 执行 → 验证)
- 焦点保护(
expect_hwnd),防止误操作错误窗口 - 应用自动化和游戏控制工作流
- Linux(X11)用法:慢速 OCR 批处理、捕获语义、游戏模式注意事项
- 面向支持图像的模型提供视觉访问
- 基于文本的运动检测
- 带宽优化
- 完整的 curl 示例
MCP 支持(一键式云端 Agent)
Model Context Protocol(MCP) 将此项目变为即插即用的工具箱,适用于任何支持 MCP 的 Agent:Claude Desktop、Claude Code、Cursor、VS Code Copilot Agent 模式、自定义云端 Agent——无需自定义粘合代码,也无需 curl 脚本。Agent 可原生发现并调用这些工具。
工作原理
MCP agent (cloud or desktop)
│ MCP protocol (stdio or streamable-HTTP)
▼
mcp_server.py ← thin wrapper: tools → HTTP calls, token auto-read
│ REST + X-Auth-Token (localhost only)
▼
server.py ← the single source of truth:
auth, locks, watchdog, focus guard, all safety rules
mcp_server.py 不会增加任何新功能——所有安全机制(身份验证令牌、输入/读取锁、看门狗、Alt+F4 拦截、焦点保护、故障保护)仍由 server.py 强制执行。
设置
pip install mcp # optional dependency (see requirements.txt)
python server.py # start the REST server first (it writes .token)
MCP 服务会自动从 .token(或 SCREEN_CONTROL_TOKEN 环境变量)读取令牌——无需任何配置。
桌面 Agent(stdio 传输)
Claude Desktop — claude_desktop_config.json:
{
"mcpServers": {
"screen-control": {
"command": "python",
"args": ["C:/path/to/screen-control/mcp_server.py"]
}
}
}
Claude Code:claude mcp add screen-control -- python C:/path/to/screen-control/mcp_server.py
Cursor / VS Code:将相同条目添加到其 MCP 配置文件中。
远程 / 云端 Agent(streamable-HTTP 传输)
python mcp_server.py --http --port 8751
# MCP endpoint: http://127.0.0.1:8751/mcp
HTTP 传输受令牌保护:每个请求都必须携带
X-Auth-Token 请求头(与 REST 服务使用相同的令牌)。查询字符串令牌
(?token=...)会被有意拒绝——URL 会泄露到代理 / 隧道
日志、浏览器历史记录和共享链接中,而且此令牌授予完整的桌面控制权限。
无法发送自定义请求头的客户端应改为运行本地 stdio
mcp_server.py。只有 GET /health 是开放的,用于存活探测。
此传输有意禁用了 DNS 重绑定防护——隧道请求会携带外部的 Host 请求头,
而令牌防护已足以应对重绑定威胁。
对于云端 Agent,可通过隧道公开服务:
cloudflared tunnel --url http://127.0.0.1:8751
# → prints a https://<random>.trycloudflare.com URL
然后,将 Agent 的 MCP 连接配置为 <tunnel-url>/mcp,并将
.token 中的令牌作为请求头(X-Auth-Token)传入。
无请求头的连接器(受限密钥)
对于无法发送自定义请求头的客户端(例如只能填写端点 URL 的 Web 连接器),请创建一个受限 API 密钥——一种持久且可设置时限的凭据——并将其嵌入 URL 路径中:
# Create a 24-hour scoped key (requires the server to be running)
curl -X POST http://127.0.0.1:8745/api/keys -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"create","name":"spark","expires_in_hours":24}'
# Connector endpoint becomes:
# https://<tunnel-url>/mcp/<scoped-key>
设计保证(SC-06):
- 主会话令牌不得用于 URL(403)——只有受限密钥 可以放在 URL 中
- 受限密钥会自动过期;过期的密钥无法通过任何身份验证
- 可随时通过
POST /api/keys({"action":"revoke","name":"spark"}) 按名称撤销受限密钥——撤销会 立即在所有端点生效 .apikeys文件只存储 SHA-256 哈希,绝不存储原始密钥
⚠️ 隧道会将 PC 控制权限暴露给互联网。请妥善保管令牌, 对于无请求头的连接器,优先使用短时隧道和受限密钥, 并在不使用时停止服务。
一键启动(启动器 + 自动隧道)
start-server.bat 会自动完成整个云端配置,并打印云端 Agent 所需的所有内容,可直接复制粘贴:
- 如果缺少
cloudflared.exe,则下载该文件(便携版,无需管理员权限) - 停止上次运行遗留的实例
- 启动 REST 服务(端口 8745)和 MCP HTTP 服务(端口 8751)
- 等待两个服务均健康运行(探测
/token和/health) - 启动 cloudflared 快速隧道,从
tunnel.log中提取其公共 URL,并打印摘要:
============================================================
ALL SYSTEMS RUNNING
============================================================
Local REST API : http://127.0.0.1:8745
Local MCP : http://127.0.0.1:8751/mcp
Public MCP URL : https://<random>.trycloudflare.com/mcp
------------------------------------------------------------
PASTE INTO YOUR CLOUD AGENT (MCP connector settings)
------------------------------------------------------------
Endpoint : https://<random>.trycloudflare.com/mcp
Header : X-Auth-Token: <token>
URL form : https://<random>.trycloudflare.com/mcp?token=<token>
(only if the connector cannot send headers)
------------------------------------------------------------
stop-server.bat 会一次性停止所有三个服务(REST、MCP、隧道)。
可用工具(16 个)
| 类别 | 工具 |
|---|---|
| 感知 | get_info、ocr_screen、screenshot(为视觉模型提供真实图像块)、motion_diff |
| 鼠标 / 键盘 | mouse、keyboard(带 expect_hwnd)、get_held、release_all |
| Windows | list_windows、focus_window、window_children、window_input_mode、window_post、window_capture_ocr、close_window |
| 游戏模式 | game(启动 / 移动 / 停止 / 心跳) |
适用传输方式
| 使用方 | 传输方式 | 命令 |
|---|---|---|
| Claude Desktop / Cursor / VS Code(本地) | stdio | python mcp_server.py |
| Claude Code | stdio | claude mcp add ...(如上) |
| 云端 / 远程 Agent | streamable-HTTP | start-server.bat(推荐),或 python mcp_server.py --http --port 8751 + cloudflared tunnel --url http://127.0.0.1:8751 |
注意: 此项目面向 MCP Python SDK 2.x(
MCPServerAPI)。 使用 SDK 1.x 时,将导入语句替换为from mcp.server.fastmcp import FastMCP, Image, 并将MCPServer替换为FastMCP。
安全模型
威胁:恶意网页(CSRF)
即使绑定到 127.0.0.1,浏览器中的恶意页面仍可向本地主机发送无需预检的请求(text/plain fetch、HTML 表单 POST)。
浏览器会阻止响应,但不会阻止请求——服务器仍会执行命令。
**缓解措施:**每个请求都必须包含 X-Auth-Token。外部网页无法读取此令牌(同源策略),因此无法通过身份验证。
其他防护层:
- POST 请求必须使用
Content-Type: application/json(否则返回 415) - 即使令牌泄露,也能阻止表单编码和 text/plain POST 请求
- **Host 标头信任(DNS 重绑定):**绑定到环回地址时,会拒绝带有非环回
Host标头的请求,并返回421——将域名解析到127.0.0.1的重绑定网页无法读取/token或调用 API /token和/的响应带有Cache-Control: no-store,因此浏览器或代理不会持久保存凭据
威胁:按键卡住/游戏模式锁定
在游戏模式下,ClipCursor 会将光标固定在 2×2 的区域内——经典的 pyautogui 故障保护(将光标移到左上角)不起作用。
缓解措施:
- 实体
Esc/Alt+Tab——真实硬件输入;此 API 无法阻止,且始终有效 POST /api/release_all——立即释放所有输入- 看门狗(自动)——服务器端检测到输入按住期间 30 s 无活动时,会触发自动释放
威胁:在错误窗口中输入
缓解措施:
/api/key上的expect_hwnd防护——如果前台窗口不匹配,则拒绝输入并返回 409/api/window/post的聚焦路径会在切换焦点之后、发送任何模拟输入之前验证焦点(不匹配时返回 409)——绝不会将输入重放到恰好处于前台的窗口focus_window()失败时会引发错误,而不是静默返回
威胁:危险按键组合
缓解措施:在 API 层通过所有输入路径进行拦截(403)——直接的 /api/key 路由、后台 /api/window/post 路由(PostMessage)以及聚焦回退路径共用同一套安全策略(control._assert_allowed):
Alt+F4——唯一禁止的 Alt 组合(Alt+Tab、Alt+菜单键均为合法操作)- Win 键——防止打开“开始”菜单和切换任务
Ctrl+Alt+Del——系统安全屏幕- 类似
Shift+Delete的组合——防止永久删除
威胁:终止系统进程
缓解措施:
- 直接根据 PID 确定进程名称(Win32 toolhelp 快照),而不是从可见窗口列表中查找——无窗口/后台系统进程也能获得与可见进程同等的保护
- 将关键系统进程列入黑名单(对未知 PID 默认拒绝):
winlogon.exe、csrss.exe、smss.exe、services.exe、lsass.exe、svchost.exe、system、registry、dwm.exe - 可选的
expect_process确认:不匹配时会中止终止操作并返回409——防止误杀刚被重新分配的 PID
威胁:资源耗尽(恶意 Agent/DoS)
持有令牌但行为异常的客户端不应能够耗尽内存或占用输入锁。
缓解措施:
MAX_CONTENT_LENGTH= 1 MB——拒绝过大的请求正文(413)- 限制
region的宽度、高度和面积以及scale(否则返回 400) - 每次输入调用的
text载荷上限为 10,000 个字符 - MJPEG 流最多允许 10 个并发客户端(超过时返回 429)
- 为客户端提供的图像设置 Pillow 解压缩炸弹限制
网络访问
服务器默认绑定到 127.0.0.1。要将其开放到网络:
python server.py --host 0.0.0.0 # ⚠️ anyone on the network can control this machine
游戏模式指南
设置
# 1. Focus the game window
curl -X POST http://127.0.0.1:8745/api/window -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"hwnd":GAME_HWND,"action":"focus"}'
# 2. Start game mode
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"start","sensitivity":12}'
摄像机视角
# Look right
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"move","dx":50,"dy":0}'
# Look down
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"move","dx":0,"dy":30}'
移动
# Walk forward (hold W)
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"down","key":"w"}'
# ... walk for a while ...
# Release W
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"up","key":"w"}'
Minecraft 专用
# Place block (right-click)
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"click","button":"right","x":960,"y":540}'
# Break block (hold left-click)
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"down","button":"left"}'
# ... after breaking ...
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"up","button":"left"}'
# Select hotbar slot
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"press","key":"1"}'
# Open inventory
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"press","key":"e"}'
适用性
| 游戏类型 | 适用? | 备注 |
|---|---|---|
| Minecraft(建造) | ✅ 是 | 放置方块、行走、挖掘 |
| Minecraft(PvP) | ❌ 否 | 对快速战斗来说太慢 |
| 回合制游戏 | ✅ 是 | 有充足时间进行读取→行动→验证 |
| RPG / 冒险游戏 | ✅ 是 | 物品栏、对话、探索 |
| 快节奏 FPS | ❌ 否 | 反应速度不足 |
| 解谜游戏 | ✅ 是 | 基于点击,阅读内容较多 |
视觉访问指南
适用于支持图像的模型
如果使用的模型可以处理图像,请直接使用视觉端点:
GET /api/vision/frame?scale=0.5&gray=1&quality=70
此端点会返回单张 JPEG,供模型分析以下内容:
- 游戏 HUD 元素(生命值、法力值、物品栏)
- 屏幕上的文字(菜单、聊天、工具提示)
- 视觉场景理解(方块、实体、地形)
适用于纯文本模型
使用差异端点进行动作检测,无需视觉能力:
POST /api/vision/diff {"grab":"gray"} → first call: stores frame
POST /api/vision/diff → subsequent calls: returns diff
响应会告知你哪些位置发生了变化(图块坐标)以及变化了多少(百分比),足以用于:
- 检测某项操作是否产生了效果
- 定位屏幕上移动的元素
- 跟踪动画状态变化
带宽优化
| 方式 | 负载 | 使用场景 |
|---|---|---|
scale=1.0, gray=0 | ~500 KB | 完整细节 |
scale=0.5, gray=1 | ~50 KB | 适用于大多数视觉模型 |
scale=0.25, gray=1 | ~10 KB | 最大程度压缩 |
diff(文本) | ~1 KB | 纯文本 Agent |
region=... | 不定 | 聚焦特定区域 |
故障排查
“未安装 OCR 引擎”
pip install rapidocr-onnxruntime
服务无法启动(端口已被占用)
# Find the process using port 8745
netstat -ano | findstr ":8745"
# Kill it
taskkill /PID <pid> /F
输入时出现“焦点不匹配”(409)
在调用焦点接口和输入接口之间,前台窗口发生了变化。
解决方法:始终传入 expect_hwnd,并在输入前验证焦点。
未找到窗口
窗口可能已关闭,也可能是 EnumWindows 不会公开的系统窗口。尝试:
curl http://127.0.0.1:8745/api/windows -H "X-Auth-Token: $TOKEN"
游戏模式下光标卡住
使用 POST /api/release_all,或在实体键盘上按 Esc / Alt+Tab。
OCR 延迟过高
对完整的 1920×1080 屏幕进行 OCR 可能需要几秒到约 30 秒,具体取决于 CPU 和屏幕内容的复杂程度。请使用区域截图——小范围裁剪通常快 10 倍:
{"region": [0, 0, 800, 100]}
土耳其语字符未显示
系统使用 SendInput + KEYEVENTF_UNICODE,与键盘布局无关。
如果字符仍未显示,目标应用可能不支持 Unicode 输入——请改用 POST /api/window/post,并将 action: "type" 作为操作。
Linux:服务立即退出,并提示“检测到 Wayland 显示服务器”
在 Wayland 会话中这是预期行为——后端会快速失败并返回 UNSUPPORTED_DISPLAY_SERVER(501),而不是进入半可用状态。请注销,在登录屏幕选择 X11 会话(“Cinnamon on Xorg”),然后重新启动服务。参见 Linux(X11)。
Linux:“未安装 xdotool 或其不在 PATH 中”(501)
缺少 X11 辅助工具。请安装这些工具(或重新运行安装程序):
sudo apt install xdotool wmctrl
项目结构
screen-control/
├── server.py # Flask HTTP server + all API endpoints
├── core/ # PlatformBackend interface + standardized errors
│ ├── backends.py # Abstract backend + lazy discovery
│ └── errors.py # ApiError envelope + error codes
├── backends/ # OS implementations behind PlatformBackend
│ ├── windows.py # Reference backend (moved from control.py)
│ ├── linux.py # X11 backend: xdotool/wmctrl + mss + uinput (Phase 5)
│ ├── imageops.py # Shared PIL helpers (frame diff, JPEG, scaling)
│ ├── uinput.py # Virtual input device for Linux game mode
│ ├── macos.py # Fail-closed stub (ROADMAP Phase 7)
│ ├── fake.py # In-memory backend for tests
│ └── forbidden.py # Shared blocked-key policy
├── control.py # Compatibility shim re-exporting backends.windows
├── tests/unit/ # Offline unit + integration tests (no real input)
├── mcp_server.py # MCP server (stdio + streamable-HTTP) — thin wrapper over the API
├── sdk/
│ └── screen_control.py # Python SDK client (pip-installable style)
├── index.html # Bundled web UI (live view + control panels)
├── docs/images/ # README assets (demo GIF captured by the API itself)
├── requirements.txt # Python dependencies
├── start-server.bat # One command: REST + MCP + cloud tunnel (Windows)
├── stop-server.bat # Stop all three processes
├── install-linux.sh # One-command Linux setup (apt, venv, uinput check)
├── start-server.sh # Linux launcher (.venv/bin/python server.py)
├── test-security.py # Security + game-mode test suite (34 checks)
├── test-linux.py # Live Linux X11 acceptance suite (7 items)
├── test-game.py # Live game-mechanics test (app launch → draw → safe close)
├── test-endtoend.py # End-to-end test: open Notepad → type → save → verify
├── .github/workflows/ # CI: runs the security suite on every push
├── AGENT_GUIDE.md # AI agent integration guide (separate from this file)
├── README.md # This file
└── .token # Auto-generated auth token (gitignored)
测试
前置条件
服务必须处于运行状态:
cd screen-control
python server.py
安全测试套件
测试身份验证、被阻止的按键组合、窗口管理、安全关闭、关键进程保护和游戏模式;所有测试均不会造成破坏。
cd screen-control
python test-security.py
预期输出:
== Token Authentication ==
✓ Missing token -> 401
✓ Wrong token -> 401
✓ Correct token -> 200
✓ Non-JSON POST -> 415
== Blocked Key Combos ==
✓ Alt+F4 blocked (403)
✓ Win key blocked (403)
✓ Win+D blocked (403)
✓ Delete blocked (403)
== Window List ==
✓ Windows list requires GET
✓ Window list is non-empty — 8 windows
✓ Exactly one focused window
== Safe Close Verification ==
✓ Wrong title aborts close
== Critical Process Protection ==
✓ System process (pid 4) rejected (403)
✓ pid 0 rejected (403)
== Game Mode ==
✓ Game mode started
✓ Relative camera look
✓ Game mode stopped
== Watchdog (dry run) ==
✓ Held state returns ok
✓ Watchdog count reported
========================================
RESULT: 19 passed, 0 failed
实时游戏机制测试
启动一个真实应用(mspaint 或 notepad),执行按住绘制的游戏机制,通过像素分析进行验证,然后安全关闭应用,并处理“不要保存”对话框。
cd screen-control
python test-game.py
**注意:**此测试会启动一个真实应用。它会自动清理(发送 WM_CLOSE,并在出现对话框时点击“不要保存”)。
Linux 实时验收测试(仅限 Linux X11)
对 Linux 后端进行七项实时检查:鼠标移动/点击、输入文字 + 热键、屏幕截图、OCR、窗口列表/焦点、游戏模式(uinput),以及原生游戏项目(显示为 SKIP——未安装 Linux 游戏)。需要正在运行的服务和真实的 X11 会话;每个辅助窗口都有唯一的 pid,且只会聚焦或点击这些窗口。
cd screen-control
./start-server.sh & # server must be running
.venv/bin/python test-linux.py # → "RESULT: 6 passed, 0 failed"; item 7 prints SKIP
贡献
- Fork 此仓库
- 创建功能分支
- 进行更改
- 在 Windows 机器上测试
- 提交拉取请求
代码风格
- Python: 遵循 PEP 8,使用类型提示,为所有公共函数编写文档字符串
- 文档字符串: 使用英文,遵循 Google 风格
- 错误消息: 使用英文,描述清晰
- 注释: 使用英文,解释为什么,而不是是什么
许可证
MIT 许可证。详情请参阅 LICENSE。
为本地自动化和 AI Agent 研究倾心打造。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。