PoC to try how implement something like Claude Cowork
- Rust 65.2%
- Nix 34.8%
| npins | ||
| src | ||
| .envrc | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
| shell.nix | ||
cowork_test
MCP server exposing Wayland desktop control tools (screenshot, pointer move, click).
Requirements
- A Wayland session with xdg-desktop-portal (GNOME or KDE)
- Rust toolchain
How it works
On Wayland, direct input/screen access is not allowed. This server uses the XDG Desktop Portal APIs via ashpd:
- RemoteDesktop portal — to move the pointer and send button/key events
- Screencast portal — to get a stream node ID required by RemoteDesktop
- Screenshot portal — to take screenshots
On startup, the portal will prompt for permission to control the desktop. Once granted, the session stays open until the server stops.
Run
cargo run
The server listens on http://127.0.0.1:8001/mcp.
Add to Claude Code
claude mcp add --transport http cowork_test http://127.0.0.1:8001/mcp
File structure
src/
├── main.rs — Entry point: initializes the Wayland desktop and starts the HTTP MCP server
├── tools.rs — Defines the exposed MCP tools (screenshot, move_pointer, click, press_key,
│ execute_actions) and dispatches calls to the DesktopController
└── desktop/
├── mod.rs — DesktopController trait, shared Key and MouseButton enums
└── wayland.rs — Wayland implementation via ashpd: manages the RemoteDesktop/Screencast session,
screenshots, pointer moves, clicks, and keyboard key events
Test
curl -X POST http://127.0.0.1:8001/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'