关于 pir-mcp
pir-mcp 是面向 Agent 的 MCP 服务,可检测屏幕区域变化或静止,而不向调用方返回图像。它仅提供粗网格分数和时间戳,避免工具结果暴露屏幕内容。
主要功能
- 01定义或选择屏幕区域及遮罩
- 02跟踪移动中的窗口
- 03用 RMSE 或峰值分数衡量变化
- 04等待变化或持续静止
- 05不输出图像或帧文件
适用场景
- 01在构建输出变化时唤醒 Agent
- 02发现状态栏停止更新
- 03用区域遮罩忽略时钟或光标
MCP 相关
它通过 MCP 工具提供区域选择、采样、变化检测、静止等待和区域管理。只有 Agent 调用工具时才会执行捕获。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y pir-mcpPIR_CAPTURE_CMDScreenshot command template writing binary PPM to stdout; {x} {y} {w} {h} substituted. Default: grim (wlroots).PIR_SELECT_CMDInteractive rectangle selector printing 'x,y wxh'. Default: slurp. Empty disables the pick tools.PIR_WINDOW_GEOMETRY_CMDPrints 'x,y wxh' for window {id}. Default: Hyprland via jq. Empty disables window regions.PIR_PICK_WINDOW_CMDInteractive window pick printing the window id. Default: Hyprland + slurp.PIR_MAX_WAIT_MSCap for blocking calls, ms (default 540000); keep under the host's MCP tool timeout.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
10收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| h | integer | 是 | 高度,像素 |
| w | integer | 是 | 宽度,像素 |
| x | integer | 是 | 左边缘,像素 |
| y | integer | 是 | 上边缘,像素 |
| name | string | 是 | |
| masks | array | 否 |
详细介绍
pir-mcp
面向 AI Agent 的运动传感器。
"让你的 LLM Agent 获得足够的信息,成为得力的“观察者”,又不会像 Windows Recall 那样成为隐私噩梦"
-Solteris-Dev
PIR 传感器会告诉你有东西动了,但绝不会告诉你是什么动了。屏幕也可以用同样的思路处理:MCP 服务监视指定矩形区域,并用一个数值、尺寸和时间戳回答“这里发生变化了吗?”以及“这里是否已经静止?”。其中没有任何工具会返回像素、图像文件,或任何能够还原成图像的内容。
这个项目的初衷是:操控桌面环境的 Agent 总需要同样两件事:构建输出发生变化时叫醒我,以及告诉我这个状态栏是否停止跳动。这都是关于运动的问题,都不需要截图。
功能
pir_pick_region请屏幕前的人画出矩形区域,就像使用区域截图工具一样(slurp、slop)。由人选择感应区域,Agent 获取区域坐标。有人在场时,请使用此工具。pir_pick_mask用同样的手势选择区域内要忽略的部分(时钟、加载动画、光标)。pir_define_region可编写脚本的方式:使用全局布局坐标定义矩形区域,并可选择添加遮罩。pir_pick_window/pir_define_window监视窗口,而不是固定矩形区域。每次捕获前都会重新查询窗口的位置和大小,因此区域会随窗口移动;窗口大小变化会被视为最大程度的变化。选择工具会将可见窗口显示为可点击的方框。pir_sample捕获一次,并与该区域的上一次采样进行比较。开销很低;也可用来检查捕获命令能否正常工作。pir_wait_for_change阻塞等待区域的显示内容偏离调用开始时的状态,或直到超时。就像门铃。pir_wait_for_stillness阻塞等待内容连续still_for_ms毫秒没有变化,或直到超时。较短的时间窗口表示“动画已稳定,可以安全操作”。如果某个本应持续变化的区域在较长时间内保持不变,就说明它已冻结,此时still=true会发出警报。pir_list_regions、pir_remove_region用于日常管理。
每次比较都会针对一个粗略网格上的平均颜色单元格报告两个数值(网格宽度最多 64 个单元格,每个单元格至少为 4 px)。完全相同的内容为 0,黑白对比则为 1:
rmse:整个网格的均方根误差。区域整体是否发生变化?光标边缘或抗锯齿光标的得分约为 0.02;弹出对话框的得分为 0.1 或更高。这是默认指标,阈值为 0.05。peak:变化最大的单个单元格。区域内是否有任何东西发生变化?在宽度为 1920 的状态栏中翻转一个时钟数字时,rmse得分为 0.018(默认指标无法检测到),但peak得分为 0.145。如果较大的区域内有较小的内容应该持续变化,请使用metric=peak。
正是这种平均处理让它成为传感器,而不是摄像头:64 个单元格无法被读取。
它刻意不做的事
- 它从不返回图像数据。没有快照工具,也没有计划添加。 如果 Agent 需要查看画面,请使用环境中已有的截图工具, 这样就由你明确决定是否使用。
- 它从不将帧写入磁盘。捕获内容只会在内存中保留处理成网格所需的 几毫秒,并且每个区域只保留上次采样的网格。
- 它不会自行捕获。每次采样都是 Agent 发起的工具调用,会显示在
对话记录中;在你绘制区域前,Agent 必须先填写
pir_pick_region中的purpose行。
它确实会透露以下信息,你可以据此判断是否能接受:某个矩形在某个 时间发生了某个幅度的变化。对于覆盖聊天窗口的区域,这属于存在信息。 请据此选择区域;服务不会对此作出判断。
捕获操作本身会交由你配置的命令执行,并使用你的权限运行。默认命令是
grim,因此这里没有任何组件能访问你未授予 grim 的屏幕权限。
安装
它已发布到 npm,包名为 pir-mcp,也已列入
官方 MCP Registry,
名称为 io.github.Solteris-Dev/pir-mcp,因此大多数客户端无需克隆仓库,
即可使用 npx -y pir-mcp 运行:
claude mcp add -s user pir -- npx -y pir-mcp
从源代码安装:
git clone https://github.com/Solteris-Dev/pir-mcp
cd pir-mcp && npm install && npm run build
需要 Node 20+,以及能够将二进制 PPM 写入 stdout 的截图工具。
捕获命令
PIR_CAPTURE_CMD 是一个模板;{x} {y} {w} {h} 会被替换,结果将在
sh -c 下运行。该命令必须将二进制 PPM(P6)输出到 stdout。
| 环境 | 命令 |
|---|---|
| wlroots / Hyprland / Sway(默认) | grim -g "{x},{y} {w}x{h}" -t ppm - |
| 使用 maim 的 X11 | maim -g {w}x{h}+{x}+{y} -f png | magick png:- ppm:- |
| 使用 ImageMagick 的 X11 | import -window root -crop {w}x{h}+{x}+{y} +repage ppm:- |
| macOS | screencapture -x -R{x},{y},{w},{h} -t png /dev/stdout | magick png:- ppm:- |
坐标取决于捕获工具。在 wlroots 布局中,坐标采用全局布局,因此放在主 显示器左侧的输出,其 x 坐标为负数。
选择器命令
Agent 调用 pir_pick_region 或 pir_pick_mask 时会运行
PIR_SELECT_CMD,且该命令必须输出 x,y wxh。将其设为空字符串即可
完全移除这些工具。
| 环境 | 命令 |
|---|---|
| wlroots / Hyprland / Sway(默认) | slurp -f "%x,%y %wx%h" |
| X11 | slop -f "%x,%y %wx%h" |
| macOS | 参见 contrib/macos(未经测试) |
窗口命令
PIR_WINDOW_GEOMETRY_CMD 中的 {id} 会被替换,且该命令必须输出窗口的
x,y wxh;PIR_PICK_WINDOW_CMD 必须输出用户所选窗口的 id。两者默认
使用 Hyprland(通过 jq 和 slurp -r)。将任一项设为空字符串,即可
移除对应的工具。窗口 id 在传递给 shell 前会限制为
[A-Za-z0-9_.:-]。
| 环境 | 几何信息 | 选择 |
|---|---|---|
| Hyprland(默认) | hyprctl -j clients | jq -r --arg id "{id}" '.[] | select(.address==$id) | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"' | 将可见窗口显示为 slurp 选择框,并输出地址 |
| Sway | swaymsg -t get_tree | jq -r '.. | select(.id? == {id}) | "\(.rect.x),\(.rect.y) \(.rect.width)x\(.rect.height)"' | swaymsg -t get_tree | jq -r '.. | select(.visible? == true) | "\(.rect.x),\(.rect.y) \(.rect.width)x\(.rect.height) \(.id)"' | slurp -r -f '%l' |
| X11 | xdotool getwindowgeometry --shell {id} | awk -F= '/^X/{x=$2}/^Y/{y=$2}/^WIDTH/{w=$2}/^HEIGHT/{h=$2}END{print x","y" "w"x"h}' | xdotool selectwindow |
目前只运行过 Hyprland 的命令组合;其他命令是根据对应工具的文档编写的。
Claude Code
claude mcp add -s user pir -- npx -y pir-mcp
# or, from a source checkout:
claude mcp add -s user pir -- node /path/to/pir-mcp/dist/stdio.js
阻塞调用默认等待 55 s,并受 PIR_MAX_WAIT_MS(540 s)限制。
请将上限设在宿主的 MCP 工具超时时间以内;需要监视更长时间的
Agent 只需再次调用。
其他设置
| 变量 | 默认值 | 含义 |
|---|---|---|
PIR_REGIONS | 未设置 | 启动时定义区域的 JSON 文件 |
PIR_THRESHOLD | 0.05 | 默认变化阈值 |
PIR_INTERVAL_MS | 500 | 默认采样周期 |
PIR_DEFAULT_WAIT_MS | 55000 | 阻塞调用的默认超时时间 |
PIR_MAX_WAIT_MS | 540000 | 阻塞调用的上限 |
PIR_CAPTURE_TIMEOUT_MS | 10000 | 单次捕获的最长耗时 |
PIR_SELECT_TIMEOUT_MS | 60000 | 用户绘制选区的时限 |
PIR_MAX_CELLS | 64 | 长边上的网格分辨率;数值越小,网格越粗,隐私性越高 |
区域文件示例如下:
[
{ "name": "bar", "x": 0, "y": 0, "w": 1920, "h": 26,
"masks": [{ "x": 1690, "y": 0, "w": 110, "h": 26 }] }
]
示例
导致这一问题的情况是:状态栏偶尔会冻结数小时,但其进程看起来运行正常。状态栏里的时钟每分钟都会变化,因此,若状态栏三分钟没有变化,就说明它冻结了。
pir_pick_region name=bar purpose="watch the status bar for a freeze"
pir_wait_for_stillness name=bar still_for_ms=180000 metric=peak timeout_ms=540000
只有在状态栏停止变化时才会返回 still=true;否则,调用会在超时后返回 still=false,Agent 随后再次调用。屏幕内容从未被查看过,矩形选区由用户自行绘制。
贡献入门
contrib/macos/ 中包含 AppKit 矩形选择器和捕获方案,这些内容是在无法实际测试的情况下编写的。如果你在真实 Mac 上运行它,请修复遇到的问题并反馈。
测试
npm test
许可证
MIT。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。