Skip to main content
Glama

screencast-desktop

checks License: MIT Platform: Windows Python 3.10+

一个 Claude Code 插件,让智能体操作 Windows 应用程序,并将该会话转化为成品演示视频——其中镜头会在每次点击发生前半秒就开始向点击处推进。

  • 视觉闭环驱动桌面操作。 每个动作都会在同一回复中返回一张全新截图,因此智能体以"看→做→看"的方式工作,而不是盲目地编写脚本。控件通过 Windows UI Automation 按名称查找;不暴露控件树的 Electron 应用则回退到截图和坐标(或在调试端口开启时通过 CDP 访问其 DOM)。

  • 录制窗口,而非屏幕。 采集通过 Windows Graphics Capture 进行,绑定到窗口句柄,因此应用背后的桌面永远不会进入画面,窗口位于哪个显示器或 GPU 上也无关紧要。

  • 视频由事件日志构建,而非由录像构建。 每次点击、每段键入的字符串以及完整的光标路径都会在发生时被打上时间戳。镜头运动即根据该日志计算得出。

  • Screen Studio 级别的成片效果,自动生成: 缓动镜头推进与平移、带柔和阴影的绘制光标、点击波纹、运动模糊、渐变背景上的圆角、暗角与颗粒感——外加死寂片段移除,可压缩智能体自身的思考时间。

  • 旁白精准踩点。 可选的 ElevenLabs 配音,在运行之前生成,使点击恰好落在描述它的句子内部。

  • 更完整的蒙太奇层,只需一个脚本。 标题卡与片尾卡、字幕,以及完整的音效设计流程——点击音轨、镜头呼啸声、落地冲击声、结尾渐强、闪避音乐垫、响度归一化——都位于 cinematic.pysfx.pysfx_bank.py 中。它们由 server/make_showcase.py 驱动,而非 desktop_render 工具;参见已知限制

  • 免费重渲染。 渲染从不触碰应用程序:更改缩放上限、旁白或特效,想重做多少次同一镜头都可以。


为什么与众不同

点击时缩放与点击前缩放对比

每个做"自动缩放"的屏幕录制器——Screen Studio 及其 Windows 模仿者——工作方式都一样:先录制,然后回头通过鼠标钩子或录像本身来猜测有趣时刻在哪里。这种顺序有一个任何人都无法绕过的硬性后果:缩放无法在点击之前开始,因为在点击发生的瞬间,录制器才刚刚得知一次点击即将到来。 它最多只能在点击时开始移动,并在稍后到达。人类剪辑师则相反——他们引导观众提前进入,使眼睛在按钮被按下时已经停留在按钮上。

在这里,智能体生成动作,因此坐标和时间在合成任何一帧之前就已确定。镜头可以被赋予提前量(server/camera.py 中的 LEAD_IN = 0.55 s),因此当按钮被按下时,镜头已经到达并稳定下来。同样的预知能力还带来了事后工具无法拥有的三样东西:

  • 无泵动效应。 同一区域内的连续点击会合并为一个稳定的镜头,而不是镜头在每个列表项上反复推近拉远。

  • 恰到好处的旁白。 语音在运行之前生成(voice.plan()),其真实时长用 ffprobe 测量,智能体的停顿根据这些数字设定——因此点击落在描述它的句子内部,无需手动微调。先录制再配音,最终总是变成语音在 Save 已被点击一秒后才说"我点击 Save"。

  • 机器可读的事件记录。 desktop_describe_take 将一次拍摄读回为编号步骤("3. [12.4s] 点击 Multiply by")——这是比一堆截图更好的产物,也足以据此编写可复用的技能。

在同类项目中的位置

谁在行动,以及是否产出视频

这个想法并不冷门——只是在 Windows 上难以实现。四个实现"从动作日志编辑"的浏览器端项目在 2026 年 3 月的两周内相继出现(argo、testreel、pagecast、playwright-recast),因为 Playwright 免费提供了日志。而在 Windows 上,日志必须与输入驱动一起构建,在同样的五个月内没有任何项目出现:录制器没有智能体,智能体不产出画面。


Related MCP server: windows-gui-mcp

系统要求

操作系统

Windows 11(在此开发和测试)。Windows 10 2004+ 具备插件所依赖的两项操作系统功能——Windows Graphics Capture 和内置 WinRT OCR——但未经测试。

Python

3.10 或更高版本(mcp SDK 需要);在 3.13 上开发。必须存在 tkinter——它随标准 python.org 安装程序一起提供。

ffmpeg

完整构建版本,位于 PATH 上,且 ffprobe 与其并列。winget install Gyan.FFmpeg。精简版缺少音频混音所需的滤镜。

GPU

带 NVENC 的 NVIDIA 显卡。采集写入器和合成器目前都默认要求 h264_nvenclibx264 代码路径存在,但还没有任何东西自动选择它——参见已知限制

Claude Code

任何支持插件的近期版本。

ElevenLabs API 密钥

可选。没有它一切照常工作,视频只是静音而已。

Python 包

取自 server/ 中每个模块的导入:

pip install mcp pillow opencv-python numpy windows-capture uiautomation

使用位置

用途

mcp

desktop_server.py

MCP 服务器本身(FastMCP)

pillow

desktop_server.pycinematic.py

截图、标题卡和字幕(Unicode 文本——OpenCV 的 putText 完全无法绘制西里尔字母)

opencv-python

composer.pycinematic.pyprivacy.py

帧合成、镜头扭曲、运动模糊

numpy

合成器、sfx.pywgc.py

帧和音频缓冲区

windows-capture

wgc.pydoctor.py

Windows Graphics Capture 绑定

uiautomation

desktop_server.pyui.py

desktop_snapshot 控件树

websocket-client

electron.py

可选——仅用于 desktop_dom*,它通过 CDP 与 Electron 应用通信

隐私扫描不需要任何包:它使用 Windows 自带的 OCR 读取屏幕,通过 PowerShell 驱动。


安装

1. 获取插件

git clone https://github.com/JHamidun/screencast-desktop.git

2. 在 Claude Code 中注册

该仓库本身就是自己的市场(.claude-plugin/marketplace.json),因此将 Claude Code 指向克隆位置并从那里安装:

/plugin marketplace add <path-to-clone>
/plugin install screencast-desktop

.mcp.json 使用 ${CLAUDE_PLUGIN_ROOT} 相对路径注册两个服务器,因此无需全局安装,克隆可以放在任何位置。

3. 运行设置

/screencast-desktop:setup

这会运行 server/doctor.py,它检查那些会静默出问题的事项:

  • DPI 感知——未声明 DPI 感知的进程被告知屏幕是 2560×1440,而实际是 3840×2160,每次点击都会按缩放因子偏移。

  • 显示器布局——坐标在所有屏幕间共享,在副显示器上会变为负数。

  • ffmpeg 和可用的编码器。

  • 窗口采集,真实测试——它采集约 25 帧并检查它们并非全部相同。

  • 旁白——密钥是否存在,以及配置的语音 ID 在账户上是否仍然有效(已删除的语音否则只会以裸 404 失败)。

它将发现的结果写入 machine.json

4. 获取 UI Automation 二进制文件

windows-ui 服务器是一个外部二进制文件——sbroenne/mcp-windows(MIT)。它刻意被捆绑进本仓库:它约 60 MB,是别人的项目,在这里固定一份副本只会发布过时的版本。按需下载:

python server/fetch_ui_binary.py          # --force to re-download

该脚本解析最新的 GitHub release,将归档文件与随其发布的 SHA256SUMS.txt 进行校验,任何不匹配都会拒绝安装。它落在 bin/ 中,这正是 .mcp.json 期望的位置。

5. 确认两个服务器都已启动

claude mcp list      # expect: screencast, windows-ui

快速开始

录制 Windows 计算器的演示。/screencast-desktop:record 命令会引导智能体完成此过程,但以下是它实际做的事情,使用真实的工具名称。

1 — 摆放窗口。 如果有副显示器,将其放在副显示器上,这样它就不会覆盖你的工作内容:

desktop_monitors()
desktop_place_window(window="Calculator", monitor=1, fit=0.7)

阅读回复。应用程序没有义务变成被告知的大小——这里一个 UWP 窗口被要求 2380×1490,结果返回 3967×2426 并超出屏幕。desktop_place_window 会测量结果、进行修正,并明确说明窗口是否适合。

2 — 检查画面中是否有任何隐私内容。

desktop_screenshot(window="Calculator")
desktop_privacy_check(window="Calculator")

检查只报告,不阻止:它对画面进行 OCR 并标记卡号、API 密钥、电子邮件地址、电话号码和个人姓名。录制前请开启勿扰模式。

3 — 排练。 使用真实工具走一遍路线,并从返回的截图中确认你点击的正是你以为要点击的内容。此时尚未录制任何内容:

ui_snapshot(windowHandle=…)          # windows-ui: controls by name — try this first
desktop_snapshot(window="Calculator")# or the built-in UIA walk, which returns e1, e2, … refs
desktop_click(ref="e7")

4 — 重置应用。 排练时留下的搜索框最终会出现在拍摄中。

5 — 录制正式内容。

desktop_record_start(window="Calculator")
desktop_click(ref="e12")                 # every click from here is logged for the camera
desktop_type("128")
desktop_click(ref="e19")
desktop_record_stop()

desktop_record_stop 报告时长、帧数以及有多少次点击进入了日志,然后告诉你用于渲染的 out_dir

6 — 渲染,然后查看。

desktop_render(out_dir="%USERPROFILE%/screencasts/take-143502", max_zoom=2.0)
desktop_render_status(out_dir="…")       # rendering runs in a child process

打开文件并亲眼检查:镜头是否到达了应在的位置、任何边缘是否有黑边、光标是否可见。错误的坐标会产生一个技术上有效、但镜头什么都没对准的文件。如果不对,就用不同的设置重新运行 desktop_render —— 不会再次启动应用程序,也不会重新录制屏幕。

工具参考

screencast 服务器desktop_monitorsdesktop_windowsdesktop_screenshotdesktop_snapshotdesktop_domdesktop_dom_launchdesktop_clickdesktop_typedesktop_keydesktop_move_mousedesktop_scrolldesktop_focusdesktop_launchdesktop_place_windowdesktop_privacy_checkdesktop_record_startdesktop_record_stopdesktop_renderdesktop_render_statusdesktop_describe_take

desktop_clickdesktop_typedesktop_keydesktop_scrolldesktop_focusdesktop_launch 都接受 see="shot"(默认)或 see="none" —— 后者在你已经知道屏幕内容时节省上下文。

windows-ui 服务器(公开的子集)— ui_snapshotui_findui_clickui_typeui_selectui_readui_waitwindow_managementapp


工作原理

日志是唯一的事实来源

用文字描述同样的事情,给任何在终端里阅读本文的人:

  AGENT                                                   server/
  ─────                                                   ───────
  desktop_click / desktop_type / …                        desktop_server.py
        │                                                 (MCP, FastMCP)
        ├──► real SendInput: cursor eased to the target,  driver.py
        │    clicked, keys sent                           ── moves + clicks
        │                                                    the real desktop
        │
        ├──► EVENT LOG  t, kind, x, y, label, dur         driver.py → events.json
        │    + the sampled cursor path (track)               ◄── the ground truth
        │
        └──► screenshot back to the agent in the same reply

  desktop_record_start                                    recorder_proc.py (child process)
        └──► Windows Graphics Capture, bound to the HWND  wgc.py
             ├─ frames arrive only when the picture       ── writer thread re-sends
             │  changes …                                    the last frame on a
             └─ … so a writer thread feeds ffmpeg at a       fixed clock
                constant rate, logging the true
                wall-clock time of every frame
                                                          → raw.mp4 + frame_times.json

  desktop_render                                          render_proc.py (child process)
        │
        ├─ 1. TIMELINE   collapse the dead air            timeline.py
        │      keep 1.1 s before and 1.5 s after every
        │      action, squeeze the gaps to 0.55 s
        │
        ├─ 2. CAMERA     event log → keyframes            camera.py
        │      lead-in 0.55 s BEFORE each click,
        │      nearby clicks merged into one shot,
        │      pan instead of pumping in and out
        │
        ├─ 3. COMPOSITOR one affine matrix per frame      composer.py
        │      recording on a gradient backdrop, rounded     + cinematic.py
        │      corners, drop shadow, drawn cursor, click     (vignette, grain;
        │      ripples, motion blur, breathing idle,          title cards and
        │      vignette, grain                                captions available)
        │                                                 → silent.mp4
        │
        └─ 4. SOUND      optional narration               voice.py
               ElevenLabs TTS mixed onto the cut          → demo.mp4

  make_showcase.py — the fuller montage, run as a script rather than a tool:
        the same four stages plus title/outro cards, captions, and the whole
        sound design pass (clicks, whooshes, impacts, riser, ducked music bed,
        loudness normalisation)                           sfx.py + sfx_bank.py

文件布局绝大部分可以通过两个设计决策来解释:

捕获和渲染在子进程中运行。 在 MCP 服务器进程内导入捕获库或 OpenCV 会使其卡死,而一次渲染需要数分钟,任何工具调用都不应一直占用这么长时间。recorder_proc.pyrender_proc.py 的存在完全是为了这个原因。它们通过文件(started.jsonstoprender.log)通信,并且两者都以 stdin=DEVNULL 启动——继承了服务器 stdin 的子进程会开始吞噬本应发给服务器的 JSON-RPC 请求。

帧按时间戳匹配,而不是按索引匹配。 如果机器跟不上,源帧 N 并不在 N/fps 处。frame_times.json 携带每一帧的真实捕获时间,合成器通过它来查找帧——这正是机器卡顿时镜头仍能跟随点击的原因。


配置

渲染

desktop_render(out_dir, name="demo.mp4", max_zoom=2.0, narration="")narration 接受一个 JSON 列表,格式为 {"text": …, "at": 秒}

其他一切都是模块常量,直接就地修改:

常量

文件

默认值

作用

LEAD_IN

camera.py

0.55

事件前镜头开始移动的秒数

MAX_ZOOM / MIN_ZOOM

camera.py

2.0 / 1.0

缩放范围;超过 2× 后 4K 源开始升采样

ZOOM_IN_DUR / ZOOM_OUT_DUR

camera.py

0.85 / 0.7

推近和拉远的持续时间

HOLD_AFTER

camera.py

1.05

对包含信息的镜头的最短保持时间

MERGE_GAP / MIN_GROUP_ZOOM

camera.py

3.6 / 1.7

邻近点击聚合为一个镜头的激进程度

KEEP_BEFORE / KEEP_AFTER

timeline.py

1.1 / 1.5

每个动作前后以全速保留的秒数

IDLE_KEEP / MIN_GAP

timeline.py

0.55 / 1.4

折叠后的停顿被缩短到的值

OUT_W × OUT_H

composer.py

1920×1080

输出分辨率

PADDING

composer.py

0.90

未缩放录制内容占画面的比例

CORNER_R, CURSOR_PX, SHADOW_DROP

composer.py

22, 58, 26

圆角、光标高度、阴影偏移(输出像素)

SHUTTER_ANGLE

composer.py

200.0

运动模糊;360 = 快门在整个帧期间打开

vignette_strength / grain_amount

composer.compose()

0.20 / 0.045

胶片质感

breathe

composer.compose()

True

长时间静态镜头上的亚像素漂移,使保持的帧不会显得冻结

desktop_record_start(window, out_dir="", fps=30) 默认路径为 ~/screencasts/take-HHMMSS

如果没有给出 max_zoomcamera.build() 会自行选择一个上限,使窗口高度的至少 70% 保持在画面内——一个高窄窗口放进 16:9 画面时本来就很小,再强制 2× 会裁掉承载动作意义的部分。(在计算器上,它截掉了显示结果的那部分屏幕。)

旁白

在环境变量中,或在插件根目录的 .env 文件中设置 ELEVENLABS_API_KEYKEY=value,每行一个——该文件被 git 忽略)。可选地通过 ELEVENLABS_VOICE_ID 固定一个声音;如果未设置,则使用账户上的第一个声音。模型:eleven_multilingual_v2。如果你的密钥放在其他位置,请将 SCREENCAST_ENV_FILE 指向别处。

voice.resolve_voice() 在使用某个声音前,会对照账户的实际声音列表检查配置的 id,因为已删除的声音否则会以无法解释的 404 失败。

没有密钥也不会出问题。doctor.py 会将其报告为警告而不是错误,并且 desktop_render 会生成一个无声视频——这也是在提供密钥但未传入 narration 参数时它生成的结果。

声音设计层在没有密钥时会降级而不是失效:sfx_bank.build() 需要 ElevenLabs 来生成音色库,但 sfx_bank.build_synthetic() 可以用 numpy 在离线状态下合成同样的声音家族(*_syn1.wav / *_syn2.wav 文件),而 sfx.click_samples() 在找不到采样资源时会回退到 synth_click()。因此,离线的机器仍然能获得点击声、嗖嗖声和撞击声——只是失去了人声。


已知限制

这是一份诚实的清单。这些问题真实存在、目前仍然成立,而且大多是在开发过程中遇到的。关于解决这些问题的计划(按优先级排序,并附有每项背后的测量数据)见 ROADMAP.md

  • desktop_render 工具渲染的内容少于代码库所能渲染的。 它调用 composer.compose() 时没有 introoutrocaptions,并且只混入旁白——没有点击音轨、没有嗖嗖声、没有音乐底垫。其他一切都已实现并可正常工作,但目前只能通过 server/make_showcase.py 访问,那是一个带有自己硬编码拍摄路径和节拍列表的脚本。把这些参数接入工具是本仓库中最明显的待办任务。

  • 没有拖拽。 没有拖拽或拖放工具。鼠标按下和鼠标抬起总是在同一位置发出,因此任何需要按下-移动-释放手势的操作——滑块、重新排序、画布绘制、通过抓手调整大小——都无法实现。

  • 按键不会写入事件日志。 desktop_key 发送击键但不会记录,因此镜头永远不会对纯键盘步骤做出反应,它们也不会出现在 desktop_describe_take 中。点击和键入的文本(desktop_type)会被记录;单独的按键不会。

  • UWP 窗口必须通过其框架窗口来寻址。 Windows 图形捕获要求一个顶级窗口句柄。对于 UWP/商店应用,那就是可见的 ApplicationFrameWindow——内部的 CoreWindow 不是可用的捕获目标。实际操作中:通过可见的窗口标题来解析应用(这正是工具所做的),不要试图越过它。

  • desktop_screenshot 是屏幕的裁剪,而不是窗口捕获。 它抓取窗口所占的屏幕区域。任何与窗口重叠的内容——另一个窗口、通知 toast、工具提示——都会出现在截图中。(录制没有这个问题:WGC 捕获的是窗口本身。)在信任截图之前,请确保目标窗口位于最上层。

  • Electron 应用几乎不会向 UI Automation 暴露任何东西。 在 Windows 11 上实测:一个典型的 Electron 应用返回 2 到 6 个命名元素——是窗口包装器,而不是界面。回退到截图和坐标,或者在调试端口可用时使用 desktop_domdesktop_dom_launch 会打开应用的第二个副本,使用独立的配置文件,该副本未登录。

  • NVENC 实际上不可或缺。 wgc.WindowRecordercomposer.compose() 都默认使用 h264_nvenclibx264 路径已实现,doctor.py 会检测正确的编码器并写入 machine.json,但目前还没有任何东西自动接通这一选择。在没有 NVENC 的机器上,你必须自己传入编码器。

  • 文件很大。 胶片颗粒是逐帧应用的,这会破坏帧间压缩——一个演示短片会比同样无颗粒的素材更重。如果文件大小比观感更重要,请设置 grain_amount=0

  • 一次拍摄最长 15 分钟。 recorder_proc.py 会自行停止,因此忘记停止的录制不会永远运行下去。

  • 仅限 Windows,且仅限交互式桌面。 SendInput、UI Automation、WGC 和 WinRT OCR 都是 Windows API;这些在无人值守会话、服务中或锁屏状态下都无法工作。

  • 窗口是一个实时应用程序。 状态会跨拍摄保留——彩排时留下的搜索框把一个键入的词变成了 "githubgithub"。在正式拍摄前重置应用。

  • 隐私检查只报告,不阻止。 匹配是字面匹配;菜单中的名称不算泄露,OCR 也会漏掉东西。在发布前亲自查看画面。


致谢与许可

  • sbroenne/mcp-windows(MIT)——执行 UI Automation 的 windows-ui MCP 服务器。此处不随附;由 server/fetch_ui_binary.py 按需下载,并对照该发布版自带的 SHA256SUMS.txt 进行校验和验证。

  • ffmpeg——捕获编码、音频混音和 ffprobe 时长测量。以外部二进制方式调用;不捆绑。许可取决于你安装的构建版本(LGPL 或 GPL)。

  • 声音库。 server/sfx_bank/ 下的 .wav 文件是生成的,不是采样server/sfx_bank.py 通过 ElevenLabs 声音生成 API 根据提示配方一次性构建它们并缓存,而且每个候选都会经过测量筛选(一个峰值出现在 200 ms 处的“点击声”,无论听起来多好都会被拒绝)。第二组文件——*_syn1.wav*_syn2.wav——完全在 sfx_bank.build_synthetic() 中使用 numpy 离线合成,因此没有 API 密钥的机器仍然能获得声音设计。这里不重新分发任何第三方采样库。将 SCREENCAST_SFX_DIR 指向你自己的采样文件夹,sfx.py 就会优先使用这些点击声和音乐底垫,而不是随附的声音库;如果未设置,它会使用 server/sfx_bank/;如果没找到任何内容,它就会合成。无论哪种方式都没有硬性依赖。

  • ElevenLabs——可选的,用于旁白和构建声音库。请自带密钥;该插件不附带任何由某人声音生成的音频。

  • 字体——标题和字幕使用随 Windows 附带的 Segoe UI,以 Arial 作为后备。不重新分发任何字体文件。

  • Model Context Protocol Python SDK(MIT)——服务器框架。

该插件自身的代码以 MIT 许可证发布。参见 LICENSE


参与贡献

欢迎提交 Issue 和 Pull Request。以下几点可以加快审查速度:

  • 仅限 Windows。 请在真实桌面上测试;没有 CI 能替你点击按钮。

  • 先运行 doctorpython server/doctor.py),并将其输出粘贴到 bug 报告中——这里的大多数问题都是环境性的(DPI 缩放、显示器布局、缺少编码器),doctor 会直接指出它们。

  • 如果它静默失败了,请在评论中说明。 这个代码库中满是解释某行代码为何如此的注释,因为几乎每一行都曾是一次看似成功实则失败的教训:相同的帧被当作有效录制、摄像头漂移出画面边缘、空的事件日志生成了完全没有缩放的视频。保留这些注释是刻意为之。

  • 对摄像头或时间轴常量的修改需要提供前后对比片段。 这些是对结果观感的判断,任何测试都无法定论。

A
license - permissive license
Not graded
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables comprehensive Windows desktop automation including screen capture, OCR text extraction, mouse/keyboard control, window management, process control, and clipboard operations through 25+ tools for AI agents.
    4
    MIT
  • A
    license
    Not graded
    quality
    A
    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

View all related MCP servers

Related MCP Connectors

  • AI-powered browser automation — navigate, click, fill forms, and extract data from any website.

  • Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.

  • Turns any agent into a full agentic application — branded, interactive screens generated at runtime.

View all MCP Connectors

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/JHamidun/screencast-desktop'

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