Content
# mcp-screenshot
A cross-platform MCP server that allows AI agents to capture screenshots of the WeChat developer tool simulator, forming a closed loop of "modify code → take screenshot → see effect".
## What problem does it solve
Previously, agents had to manually take screenshots, upload them to OSS, and share links after modifying the mini-program. This MCP automates the process: agents call a tool to capture the current screen, obtain the local path, and then read it using the `Read` tool, **without relying on OSS or network**.
The core idea is that the agent can read local images, so the MCP's responsibility is only to "capture → save locally → return absolute path", and the rest of the loop is completed by the agent.
## Tools
### screenshot_capture
| Parameter | Type | Description |
|---|---|---|
| scope | `"window"` \| `"region"` \| `"full"` | Default is `"window"`. `"window"` searches by title; `"region"` searches by coordinates; `"full"` takes a full screenshot |
| title | string | Window title keyword, defaulting to WeChat developer tool related windows |
| region | string `"x,y,w,h"` | Only takes effect when `scope=region`, four integer pixel coordinates |
Successfully returns the absolute path of a local PNG image, which can be read by the agent using the `Read` tool to see the screenshot. Failure returns a structured error with a readable hint (e.g., suggesting to use `scope=full` as a fallback).
### Capture only the simulator area
`scope=window` captures the entire developer tool window (including directory tree and debugger). If you only want to capture the simulator (phone preview) area, add the parameter `simulator=true`:
```
screenshot_capture { scope: "window", simulator: true }
```
The position of the simulator within the window is configured by the environment variable `SIMULATOR_RECT`, in the format `"x1,x2,y1,y2"` with four percentage integers (0-100), representing the simulator's **left, right, top, and bottom** boundaries within the window bounds:
```json
{
"mcp": {
"servers": {
"screenshot": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/mcp-screenshot/dist/index.js"],
"env": {
"SIMULATOR_RECT": "50,64,7,99"
}
}
}
}
}
```
This means the simulator is located in the rectangular area from 50% to 64% from the left, 7% to 99% from the top within the window. The actual coordinates are calculated based on the current window size, so **moving the window, changing screens, or adjusting the ZCode window size does not affect** the capture, as long as the internal layout of the developer tool (directory tree/simulator/debugger proportions) remains unchanged.
**How to measure the suitable percentage**: First, capture a complete window screenshot using `scope=window`, and then visually estimate the percentage positions of the simulator's four edges within the window (how many percent from the left, right, top, and bottom), and fill them into `SIMULATOR_RECT`. Configure once and use permanently, unless the developer tool layout changes significantly.
> Note: `simulator=true` only makes sense when `scope=window` (requires locating the window first, then cropping the region). If `SIMULATOR_RECT` is not configured, calling `simulator=true` will return a clear error message.
## Integration with ZCode
In the project workspace `.zcode/config.json` (configuration file does not expand `${...}` template variables, must use absolute paths):
```json
{
"mcp": {
"servers": {
"screenshot": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/mcp-screenshot/dist/index.js"]
}
}
}
}
```
Restart the session, input `/mcp` to check the connection status (should display "connected"). Screenshots are saved in the project `.screenshots/` (automatically added to gitignore).
> Remark: `projectRoot` defaults to the server process's `process.cwd()`. If the ZCode server's cwd is not the expected project root, set the environment variable `MCP_SCREENSHOT_PROJECT_ROOT` to point to the target project directory, and screenshots will be saved there in `.screenshots/`.
## Development
```bash
cd mcp-screenshot
bun install
bun run build # Compile to dist/ (tsc, zero errors)
bun test # Run tests (bun test)
bun run start # Equivalent to node dist/index.js
```
Source code structure:
```
src/
├── index.ts # stdio entry
├── server.ts # MCP tool definition (screenshot_capture)
├── paths.ts # Screenshot path/gitignore maintenance (pure function, tested)
└── platform/
├── types.ts # Platform capture interface
├── index.ts # Dispatch by process.platform
├── win32.ts # Windows: PowerShell + System.Drawing
└── darwin.ts # macOS: screencapture + osascript
```
## Platform support
| Platform | Implementation | Status |
|---|---|---|
| Windows | PowerShell + System.Drawing.CopyFromScreen, locate by window title | Tested |
| macOS | `screencapture -l<wid>` / `-R x,y,w,h`, osascript to find window | Code ready, pending Mac testing (requires "screen recording" permission) |
## Design principles
- **capture() always resolves, never rejects** - Failure is expressed through structured `CaptureFailure`. If the stdio MCP server crashes, the entire session's tools are lost, so stability is the first constraint.
- **Window not found is a normal situation** - Returns a clear error + hint, letting the agent decide (e.g., use `scope=full` as a fallback).
- **YAGNI** - MVP only captures the current screenshot, no clicks/navigation/OCR/comparison.
## Future plans
- v2: `screenshot.list_windows` lists all windows, letting agents precisely specify which to capture
- v3: Integrate with miniprogram-automator, add navigate/tap, truly "control + screenshot" loop
- v4: CDP directly connects to the simulator Chromium, captures pure rendering screenshots