A motion sensor for AI agents: MCP server that reports when a screen region changes or goes still. Scores, never pixels.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add pir-mcp -- npx -y pir-mcp{
"mcpServers": {
"pir-mcp": {
"command": "npx",
"args": ["-y", "pir-mcp"]
}
}
}Resumen de MCP Servers
# pir-mcp
A motion sensor for AI agents.
__*"Gives your LLM agents enough info to be a helpful "watcher" without being a privacy nightmare like Windows Recall"*__
*-Solteris-Dev*
A PIR sensor tells you *that* something moved, never *what*. This is the same
idea for a screen: an MCP server that watches named rectangles and answers
"did this change?" and "has this gone still?" with a number, a size and a
timestamp. No tool in it returns pixels, image files, or anything that could
be turned back into a picture.
It exists because an agent driving a desktop keeps needing the same two
things: *wake me when the build output moves* and *tell me if this status bar
has stopped ticking*. Both are motion questions. Neither needs a screenshot.
## What it does
- **`pir_pick_region`** ask the person at the screen to draw the rectangle,
the way a regional screenshot works (slurp, slop). The human chooses what
is sensed; the agent gets the geometry. Use this whenever someone is there.
- **`pir_pick_mask`** the same gesture for a patch inside a region to ignore
(a clock, a spinner, a caret).
- **`pir_define_region`** the scriptable path: name a rectangle by global
layout coordinates, with optional masks.
- **`pir_pick_window`** / **`pir_define_window`** watch a window instead of a
fixed rectangle. Its geometry is looked up again before every capture, so
the region follows the window when it moves; a resize counts as maximal
change. The pick offers your visible windows as boxes to click.
- **`pir_sample`** capture once, score against the previous sample of that
region. Cheap; also the way to check the capture command works.
- **`pir_wait_for_change`** block until the region departs from how it looked
when the call began, or time out. A doorbell.
- **`pir_wait_for_stillness`** block until nothing has changed for
`still_for_ms`, or time out. A short window means "the animation settled,
safe to act". A long window on something that should keep changing means
it is frozen, and `still=true` is the alarm.
- **`pir_list_regions`**, **`pir_remove_region`** housekeeping.
Every comparison reports two numbers over a coarse grid of averaged colour
cells (at most 64 across, each at least 4 px), both 0 for identical and 1 for
black against white:
- **`rmse`** over the whole grid: did the region as a whole move? A cursor
edge or an antialiased caret scores about 0.02; a dialog opening 0.1 or
more. This is the default metric, threshold 0.05.
- **`peak`** the single most-changed cell: did *anything* in it move? A clock
digit flipping inside a 1920-wide status bar scores rmse 0.018 (invisible
to the default) but peak 0.145. Use `metric=peak` for a small thing that
should tick inside a larger region.
Averaging is what makes this a sensor rather than a camera: 64 cells cannot
be read.
## What it deliberately does not do
- It never returns image data. There is no snapshot tool and none is planned.
If an agent needs to *see*, use the screenshot tool your environment already
has, so that choice stays explicit and yours.
- It never writes frames to disk. A capture lives in memory for the
milliseconds it takes to reduce it to a grid, and only the grid of the last
sample is kept per region.
- It does not capture on its own. Every sample is a tool call the agent made,
visible in the transcript, and `pir_pick_region` carries a `purpose` line
the agent has to write down before you draw.
What it *does* reveal, so you can decide whether that is acceptable: that a
given rectangle changed, at a given time, by a given magnitude. On a region
covering a chat window that is presence information. Choose regions
accordingly; the server has no opinion.
The capture itself is delegated to a command you configure, run with your
privileges. The default is `grim`, so nothing here has screen access that you
did not already give to grim.
## Install
It is on npm as [`pir-mcp`](https://www.npmjs.com/package/pir-mcp) and in
the [official MCP Registry](https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.Solteris-Dev/pir-mcp)
as `io.github.Solteris-Dev/pir-mcp`, so most clients can run it with
`npx -y pir-mcp` and no clone:
```sh
claude mcp add -s user pir -- npx -y pir-mcp
```
From source:
```sh
git clone https://github.com/Solteris-Dev/pir-mcp
cd pir-mcp && npm install && npm run build
```
Requires Node 20+ and a screenshot tool that can write binary PPM to stdout.
### Capture command
`PIR_CAPTURE_CMD` is a template; `{x} {y} {w} {h}` are substituted and the
result runs under `sh -c`. It must print a binary PPM (`P6`) to stdout.
| environment | command |
|---|---|
| wlroots / Hyprland / Sway (default) | `grim -g "{x},{y} {w}x{h}" -t ppm -` |
| X11 with maim | `maim -g {w}x{h}+{x}+{y} -f png \| magick png:- ppm:-` |
| X11 with ImageMagick | `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:-` |
Coordinates are whatever the capture tool uses. On a wlroots layout that is
the global layout, so an output placed left of the primary has negative x.
### Selector command
`PIR_SELECT_CMD` runs when an agent calls `pir_pick_region` or
`pir_pick_mask` and must print `x,y wxh`. Set it to an empty string to remove
those tools entirely.
| environment | command |
|---|---|
| wlroots / Hyprland / Sway (default) | `slurp -f "%x,%y %wx%h"` |
| X11 | `slop -f "%x,%y %wx%h"` |
| macOS | see [contrib/macos](contrib/macos/README.md) (untested) |
### Window commands
`PIR_WINDOW_GEOMETRY_CMD` gets `{id}` substituted and must print `x,y wxh`
for that window; `PIR_PICK_WINDOW_CMD` must print the id of the window the
person chose. Both default to Hyprland (via `jq` and `slurp -r`). Set either
to an empty string to remove the corresponding tools. Window ids are limited
to `[A-Za-z0-9_.:-]` before they reach a shell.
| environment | geometry | pick |
|---|---|---|
| Hyprland (default) | `hyprctl -j clients \| jq -r --arg id "{id}" '.[] \| select(.address==$id) \| "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"'` | visible windows as slurp boxes, prints the address |
| 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` |
Only the Hyprland pair has been run; the others are written from the tools'
documentation.
### Claude Code
```sh
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
```
Blocking calls default to 55 s and are capped by `PIR_MAX_WAIT_MS` (540 s).
Keep the cap under your host's MCP tool timeout; an agent that needs to watch
for longer just calls again.
### Other settings
| variable | default | meaning |
|---|---|---|
| `PIR_REGIONS` | unset | JSON file of regions to define at startup |
| `PIR_THRESHOLD` | `0.05` | default change threshold |
| `PIR_INTERVAL_MS` | `500` | default sampling period |
| `PIR_DEFAULT_WAIT_MS` | `55000` | default timeout for blocking calls |
| `PIR_MAX_WAIT_MS` | `540000` | cap for blocking calls |
| `PIR_CAPTURE_TIMEOUT_MS` | `10000` | how long one capture may take |
| `PIR_SELECT_TIMEOUT_MS` | `60000` | how long the person has to draw a selection |
| `PIR_MAX_CELLS` | `64` | grid resolution on the long side; smaller is coarser and more private |
A regions file looks like:
```json
[
{ "name": "bar", "x": 0, "y": 0, "w": 1920, "h": 26,
"masks": [{ "x": 1690, "y": 0, "w": 110, "h": 26 }] }
]
```
## Example
The case that produced this: a status bar that occasionally froze for hours
while its process looked healthy. The clock in it should change every
minute, so a bar that is still for three minutes is a frozen bar.
```
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` comes back only if the bar stopped; otherwise the call returns
`still=false` at the timeout and the agent calls again. Nothing on the screen
was ever seen, and the person drew the rectangle themselves.
## Contributing starting points
`contrib/macos/` holds an AppKit rectangle selector and capture recipe,
written blind and untested. If you run it on a real Mac, fix what breaks and
send it back.
## Tests
```sh
npm test
```
## License
MIT.
Lo que la gente pregunta sobre pir-mcp
¿Qué es Solteris-Dev/pir-mcp?
+
Solteris-Dev/pir-mcp es mcp servers para el ecosistema de Claude AI. A motion sensor for AI agents: MCP server that reports when a screen region changes or goes still. Scores, never pixels. Tiene 1 estrellas en GitHub y su última actualización registrada es del 2026-09-16.
¿Cómo se instala pir-mcp?
+
Puedes instalar pir-mcp clonando el repositorio (https://github.com/Solteris-Dev/pir-mcp) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.
¿Es seguro usar Solteris-Dev/pir-mcp?
+
Nuestro agente de seguridad ha analizado Solteris-Dev/pir-mcp y le ha asignado un Trust Score de 95/100 (tier: Verified). Revisa el desglose completo de comprobaciones superadas y flags en esta página.
¿Quién mantiene Solteris-Dev/pir-mcp?
+
Solteris-Dev/pir-mcp es mantenido por Solteris-Dev. La última actividad registrada en GitHub es del 2026-09-16, con 0 issues abiertos.
¿Hay alternativas a pir-mcp?
+
Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.
Despliega pir-mcp en tu cloud
Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.
¿Mantienes este repo? Añade un badge a tu README
Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.
[](https://claudewave.com/repo/solteris-dev-pir-mcp)<a href="https://claudewave.com/repo/solteris-dev-pir-mcp"><img src="https://claudewave.com/api/badge/solteris-dev-pir-mcp" alt="Featured on ClaudeWave: Solteris-Dev/pir-mcp" width="320" height="64" /></a>Más MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ
The fastest path to AI-powered full stack observability, even for lean teams.