cvm-vnc
通过 agent-browser 对 Web VNC 页面进行程序化控制的 Python 工具,支持屏幕截图、文本输入、图片 OCR 和页面状态检测,并提供 MCP (Model Context Protocol) Server 供 AI Agent 集成。
功能特性
- VNC 页面控制 — 打开并操作 Web VNC 界面,兼容腾讯云临时 VNC URL 和 Workbench VNC 页面
- 屏幕截图 — 将 VNC Canvas 捕获为 PNG 图片
- 智能文本输入 — 自动识别输入方式(远程命令对话框 / noVNC 键盘 / Canvas 直接输入等)
- LLM OCR — 通过
cvm-vnc ocr-read调用 OpenAI 兼容视觉模型,从本地图片提取文本 - MCP Server — 以 stdio 模式运行,供 AI Agent 调用
- 登录检测 — 自动识别 VNC 页面跳转至登录页的场景
- 终端网格估算 — 根据 Canvas 尺寸启发式推算终端行列数
安装
从 PyPI 安装
# 基础安装(CLI 功能:open / capture / type / close / ocr-read 等)
pip install cvm-vnc
# 安装 MCP Server 支持(AI Agent 集成必需)
pip install cvm-vnc[mcp]
# 安装全部可选依赖
pip install cvm-vnc[mcp,dotenv]
从源码安装(开发模式)
git clone <repo-url>
cd cvm-vnc
pip install -e '.[mcp]'
-e(editable)模式会将当前源码目录链接为已安装包,修改代码后无需重新安装即可生效。
可选依赖说明
| Extra | 包 | 说明 |
|---|---|---|
mcp |
mcp[cli]>=1.0.0 |
MCP Server 功能(cvm-vnc mcp / cvm-vnc-mcp 命令必需) |
dotenv |
python-dotenv |
本地开发时加载可选的 .env 配置 |
注意:不安装
mcpextra 时,CLI 基础命令(open、capture、type、type-sequence、close、ocr-read)仍可正常使用,无需任何第三方依赖。
前置依赖
需要系统中安装支持 --init-script 的 agent-browser;本轮验证使用 0.41.0:
npm install -g agent-browser
# 首次使用且尚未下载浏览器时
agent-browser install
使用方式
CLI 命令
# 打开 VNC 页面
cvm-vnc open <url> [--wait-ms MS] [--session NAME] [--headed]
# 截取 VNC 屏幕
cvm-vnc capture [output] [--session NAME] [--headed]
# 发送文本输入
cvm-vnc type <text> [--enter] [--mode stable|fast] [--session NAME] [--headed]
# 批量顺序输入(避免 AI 思考间隙导致登录超时)
cvm-vnc type-sequence --steps-json '<JSON>' [--mode MODE] [--session NAME]
# 关闭浏览器会话
cvm-vnc close [--session NAME]
# 从本地图片读取文本(OpenAI 兼容视觉模型)
cvm-vnc ocr-read <image>
# 仅检查 OCR 配置是否齐全,不输出配置值或发起网络请求
cvm-vnc ocr-check
# 启动 MCP Server
cvm-vnc mcp [--session-default NAME] [--mode-default MODE] [--headed]
open 只有在 VNC 连接就绪后才成功;连接失败、地址过期或页面没有可用 Canvas 时返回非零退出码,type 和 capture 也会拒绝操作断开的连接。
配合 tccli 打开 CVM
腾讯云 DescribeInstanceVncUrl 返回的是编码后的连接参数,需要拼接网页地址。官方文档说明临时地址仅有效 15 秒且只能使用一次;重连时必须重新获取。以下示例先启动浏览器,再获取地址并立即打开:
agent-browser --session vnc-test open about:blank
python3 - <<'PY'
import json
import subprocess
response = subprocess.check_output([
"tccli", "cvm", "DescribeInstanceVncUrl",
"--region", "ap-guangzhou", "--InstanceId", "ins-xxxxxxxx",
], text=True)
url = "https://img.qcloud.com/qcloud/app/active_vnc/index.html?InstanceVncUrl=" + json.loads(response)["InstanceVncUrl"]
subprocess.run(["cvm-vnc", "open", url, "--session", "vnc-test"], check=True)
PY
VNC 连接就绪与系统登录是两步:看到系统 login: 后,再使用 type-sequence 登录。腾讯云传统页面会跟踪实际粘贴队列,发送完最后一个字符后才按 Enter;其他页面保留随字符数增加的等待时间。fast 模式也会等待发送完成。若发送中断,先检查终端中已输入的内容,再决定是否重试。
传统页面的连续粘贴会限制按键速率,避免丢字或残留 Shift 状态:fast 最少间隔 50 ms,stable 最少间隔 75 ms。因此数千字符的脚本需要数分钟,请为调用设置足够的超时时间。
默认使用无界面浏览器,无需图形桌面。cvm-vnc open 会在临时 /active_vnc/ 页面和 Workbench /vnc 页面创建 RFB 连接前安装键盘补丁:大写字母显式发送 Shift,粘贴前释放残留修饰键,避免服务端反复用 Caps Lock 补偿大小写、切换 Linux 控制台后发生大小写反转。补丁仅在工具打开的浏览器页面内生效;旧会话需要用当前版本重新打开。vnc_status 的 keyboardInput.uppercaseShift 可确认补丁是否生效。Workbench 创建 Canvas 不代表连接成功,工具会继续等待连接状态。
Workbench 的 CLI 输入默认通过 Canvas 逐键发送;实测原生批量粘贴在锁键恢复后仍存在兼容性异常,因此不作为默认路径。已打开的粘贴对话框会先关闭。临时 VNC 页面继续使用粘贴队列;诊断原生粘贴可用测试脚本的 --remote-dialog 选项。
此补丁预防上述状态漂移,但重新连接不会自动清除已存在的异常。确认当前 Linux 控制台大小写反转后,可以直接通过 VNC 恢复,不需要登录、SSH 或重启实例:
cvm-vnc repair-keyboard --case-inverted --session vnc-test
大小写恢复是对已确认异常的校正动作,会改变锁键状态差;在正常输入时执行或恢复后盲目重复执行,会再次造成反转。它只作用于当前活动控制台,不会逐一切换或修改其他 VT。先确认输入回显,修复后再验证一次;响应中的 status=applied 表示序列已发送,verified=false 表示工具未自动识别客户机最终回显。uppercaseShift=true 也只表示发送补丁已安装,不表示客户机状态已经校准。
如果只有 Shift、Ctrl、Alt 等修饰键卡住,可省略 --case-inverted;默认操作只释放修饰键,不修改大小写锁定状态,可重复执行:
cvm-vnc repair-keyboard --session vnc-test
对应 MCP 工具为 vnc_repair_keyboard(case_inverted=true, session="vnc-test")。该恢复方法针对腾讯云临时 VNC 页面、Workbench VNC 页面与 QEMU/Linux 控制台组合;工具不会在每次连接时盲目翻转状态。keyboardInput.repairAvailable 表示已支持恢复操作。使用旧版本打开的会话先关闭再用当前版本打开;临时 URL 需要重新获取。Workbench 需要保留同一 session 完成网页登录;更新浏览器启动参数可能重建浏览器并需要再次登录。
源码更新后,已有的长驻 MCP 服务需要重启,再重新打开 VNC 页面。
OCR 识图命令
Agent 可先执行 cvm-vnc ocr-check,该命令只输出配置状态 JSON,例如 {"configured":true,"missing":[]}。配置齐全时退出码为 0,否则为 1;缺少项以 endpoint、credential、model 类别表示。不输出服务地址、模型名、密钥或其片段,也不验证网络连通性。Agent 无需直接读取环境变量或配置文件。
ocr-read 和 ocr-check 优先使用进程环境中的配置。生产环境可由容器、服务管理器或部署平台直接注入以下变量,无需创建配置文件:
LLM_OCR_BASE_URLLLM_OCR_API_KEYLLM_OCR_MODEL
若缺少任意一项,ocr-read 会在发起请求前报错;ocr-check 只返回缺少项和非零退出码。
本地开发也支持可选的当前目录 .env,仅补充尚未设置的变量,不覆盖已有环境变量。
# 运行环境注入(此处用 shell 导出示意)
export LLM_OCR_BASE_URL="https://api.example.com"
export LLM_OCR_API_KEY="<your-key>"
export LLM_OCR_MODEL="gpt-4.1-mini"
cvm-vnc ocr-read ./invoice.png
# 本地开发可选:通过 .env 补充未设置的变量
cat > .env <<'EOF'
LLM_OCR_BASE_URL=https://api.example.com
LLM_OCR_API_KEY=<your-key>
LLM_OCR_MODEL=gpt-4.1-mini
EOF
cvm-vnc ocr-read ./screenshot.png
成功时只会在 stdout 输出 OCR 文本,便于管道串联;失败时会在 stderr 输出简洁错误信息。
OCR 失败、结果不清或与预期不符时,可检查原始截图;ocr-read 本身不调用宿主模型做读图回退。
也可通过独立入口直接启动 MCP Server:
cvm-vnc-mcp
MCP Server Tools
MCP Server 对外暴露以下工具:
| 工具 | 说明 |
|---|---|
vnc_open(url, wait_ms, session) |
打开 VNC 页面 |
vnc_status(session) |
检查页面状态(Canvas 元数据、登录检测等) |
vnc_capture(output_path, session) |
截取 Canvas 为 PNG |
vnc_type(text, press_enter, session, mode) |
发送文本输入 |
vnc_type_sequence(steps, session, mode) |
批量顺序输入(适合系统登录等需要连续输入的场景) |
vnc_close(session) |
关闭浏览器会话,释放资源 |
vnc_ocr_read(image_path) |
读取本地图片文字,返回 OCR 文本 |
示例
# 打开 VNC 并等待页面加载
cvm-vnc open https://vnc.example.com --wait-ms 3000
# 截图保存到文件
cvm-vnc capture /tmp/screen.png
# 执行命令
cvm-vnc type "ls -la" --enter
# 一次性完成系统登录(用户名 + 密码)
cvm-vnc type-sequence --steps-json '[{"text":"root","press_enter":true,"wait_ms":500},{"text":"password","press_enter":true}]'
# 关闭浏览器会话
cvm-vnc close
# 从图片中提取文本
export LLM_OCR_BASE_URL="https://api.example.com"
export LLM_OCR_API_KEY="<your-key>"
export LLM_OCR_MODEL="gpt-4.1-mini"
cvm-vnc ocr-read ./receipt.png
项目结构
src/cvm_vnc/
├── __init__.py # 版本信息
├── __main__.py # CLI 入口
├── llm_ocr.py # OCR 核心实现(配置解析、图片编码、兼容接口调用)
└── vnc_browser.py # 核心实现(浏览器控制、CLI 分发、MCP Server、JS 注入脚本)
MCP Server 配置
使用 MCP 功能前,请确保已安装 mcp extra:pip install cvm-vnc[mcp]
安装完成后,可将 cvm-vnc 作为 MCP Server 接入 AI 客户端。
Claude Code
claude mcp add cvm-vnc -- cvm-vnc-mcp
添加后可通过以下命令验证:
claude mcp list
Codebuddy
codebuddy mcp add cvm-vnc -- cvm-vnc-mcp
或手动编辑 ~/.codebuddy/settings.json:
{
"mcpServers": {
"cvm-vnc": {
"command": "cvm-vnc-mcp"
}
}
}
提示:如果
cvm-vnc-mcp不在 PATH 中,需使用完整路径,例如/path/to/venv/bin/cvm-vnc-mcp。
配置
| 环境变量 | 说明 | 默认值 |
|---|---|---|
AGENT_BROWSER_BIN |
agent-browser 可执行文件路径 | 自动查找 |
VNC_SESSION_LOCK_TIMEOUT_SECONDS |
等待其他命令释放会话锁的超时时间(秒);不限制当前命令的执行时长 | 120 |
LLM_OCR_BASE_URL |
ocr-read 使用的 OpenAI 兼容接口地址 |
无 |
LLM_OCR_API_KEY |
ocr-read 使用的 API Key |
无 |
LLM_OCR_MODEL |
ocr-read 使用的视觉模型名 |
无 |
开发验证
以下命令在 Git 源码仓库目录执行。
# 不依赖云实例的单元测试
python3 -m unittest discover -s tests -p 'test_*.py'
# 真实浏览器 + 本地 HTML,验证粘贴入口和对话框提交
python3 tests/browser_dom_regression.py
# 大小写反转、控制台切换、修饰键释放及 Canvas 键盘事件回归
python3 tests/browser_case_regression.py
# 已登录的真实 VNC 会话:CPU、内存、磁盘、网络、日志管道、长脚本、特殊字符
python3 tests/live_scenarios.py --session vnc-test --mode fast --output-dir /tmp/vnc-results
# 已登录控制台且有 SSH 密钥访问:反复获取新 URL,通过 VNC 写脚本,SSH 只读核对源码哈希
python3 tests/live_roundtrip.py --session vnc-test --instance-id ins-xxxxxxxx \
--region ap-guangzhou --ssh-host root@<instance-ip> --rounds 2
# 实机专项:需要 root SSH、Node.js 22+ 和两个未分配的 Linux VT(默认 48、49)
# 原生网页复现;结果记录中 reproduced_case_flip=true 表示成功复现
python3 tests/live_case_regression.py --instance-id ins-xxxxxxxx \
--ssh-host root@<instance-ip> --native --rounds 2
# 相同场景验证修复;也可加 --canvas 验证回退路径
python3 tests/live_case_regression.py --instance-id ins-xxxxxxxx \
--ssh-host root@<instance-ip> --rounds 5
# 已完成网页登录的 Workbench 会话:保留认证,在当前页面连接中核验
python3 tests/live_case_regression.py --instance-id ins-xxxxxxxx \
--ssh-host root@<instance-ip> --session vnc-task \
--workbench-url 'https://workbench.cloud.tencent.com/vnc?regionId=<region-id>&instanceId=ins-xxxxxxxx&source=cvm' \
--rounds 2
live_scenarios.py 在独立 /tmp/cvm-vnc-validation.* 目录创建日志,并在最后清理;输出截图和 run.json 供核验。命令发送成功不等于远端执行成功,需要检查截图中的结果标记。长脚本包含 4320 字节特殊字符文本的 SHA-256 校验,完整输入约 7 KB,执行需要数分钟。真实 LLM OCR 测试另需配置 LLM_OCR_*。
live_roundtrip.py 默认交替使用 fast/stable 模式,每轮创建独立的 /tmp/cvm-vnc-roundtrip-<uuid>.py 及退出码标记,并在测试结束清理;完整脚本约 7 KB,通过 results.json 记录本地和远端源码 SHA-256、退出码。SSH 只读取哈希和完成状态(失败时保存文件用于比较),命令输入和脚本执行均通过 VNC 完成。测试会等待执行完成后再截图,避免将发送完成误认为执行完成。
live_case_regression.py 在未分配的空闲控制台中直接读取 TTY 输入字节,不依赖 OCR 或 shell 回显;结束后恢复原控制台、原始服务端锁定状态并释放测试 VT。原生网页可复现 AaAbBzZ → aAaBbZz,修复后的相同输入应逐字节一致。脚本不会使用已有的登录控制台作为测试接收器。
Changelog
v0.4.1
- 更新安装与使用文档。
v0.4.0
- 新增
repair-keyboard和 MCPvnc_repair_keyboard,释放残留修饰键,并按需校正已确认的 Linux 控制台大小写反转。 - 为腾讯云临时 VNC 与 Workbench 页面加载共用键盘补丁,大写输入显式发送 Shift;Workbench CLI 默认采用已验证的 Canvas 逐键输入路径,规避原生批量粘贴的已知异常。
- 跟踪临时页面的实际粘贴队列并限制按键速率,改进连接就绪判断、失败处理和会话锁,避免部分输入后自动重发命令。
- 新增
ocr-check,仅输出本地配置状态;明确环境变量注入优先,可选.env不覆盖已有变量。
v0.3.0
- 兼容 Workbench VNC 页面 — 同时支持腾讯云临时 VNC URL(
img.qcloud.com)和 Workbench VNC 页面(workbench.cloud.tencent.com),两种模式均支持粘贴(快速)输入 - 修复粘贴模式选择器 — 远程命令对话框启动链接选择器从硬编码
a.copyBtn改为通用选择器,适配不同页面变体 - 修复 Shift 符号字符输入 — Canvas 键盘输入路径中
!@#$%^&*()等 Shift 组合符号不再丢失 - 重构粘贴命令模式 — 解决 canvas 渲染未完成就返回的问题,通过 canvas 指纹轮询等待稳定
- 新增 LLM OCR — 通过
cvm-vnc ocr-read调用 OpenAI 兼容视觉模型从图片提取文本
License
MIT
Metadata
Release files for cvm-vnc 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cvm_vnc-0.4.1.tar.gz | 53.5 kB | Without provenance | Details for cvm_vnc-0.4.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cvm_vnc-0.4.1-py3-none-any.whl | Python 3 | none | any | Details for cvm_vnc-0.4.1-py3-none-any.whl |
Total release size: 87.4 kB
Release files / cvm_vnc-0.4.1.tar.gz
| Download URL | cvm_vnc-0.4.1.tar.gz |
|---|---|
| Size | 53.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9951a445441439a32d56f4997a5f87efc09feabb465f8af784381b9aabc8fb63
|
|
BLAKE2b-256 checksum How to use checksums |
307c731d4105278336ea94fd1a6dd27dcc3ee73c9459d0557acafbfd23894bab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.10
|
Release files / cvm_vnc-0.4.1-py3-none-any.whl
| Download URL | cvm_vnc-0.4.1-py3-none-any.whl |
|---|---|
| Size | 33.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0beeccca0e57728c86baf12fb2e41d178a55bb5175c3449c22974eebbc55e131
|
|
BLAKE2b-256 checksum How to use checksums |
e05b177c049948d22a4f6515a91756c7a603badea77253ee816cfb0c11e50c1f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.10
|
Security for cvm-vnc 0.4.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.