161 lines
5.9 KiB
Markdown
161 lines
5.9 KiB
Markdown
# MCP Desktop Control
|
|
|
|
An open-source Model Context Protocol (MCP) server that provides AI agents with native, low-level control over your desktop environment.
|
|
|
|
Designed specifically with modern Linux (Wayland) in mind, this server bypasses high-level display server restrictions by communicating directly with the Linux kernel via `evdev` and `/dev/uinput` to simulate real physical hardware inputs.
|
|
|
|
## Features
|
|
|
|
- **Keyboard Control**: Type text with full layout awareness, or trigger common shortcuts (e.g., `copy`, `paste`, `select_all`).
|
|
- **Layout Support**: Currently supports standard US (`us`) and Slovenian (`si`) layouts out of the box, with intelligent fallback mechanisms (reading `localectl`, environment variables, or `setxkbmap`).
|
|
- **Mouse Control**: Absolute and relative cursor movement, clicking (left, right, middle), and scrolling.
|
|
- **Configurable Delays**: Adjust typing speeds and pre-action delays for smooth interactions.
|
|
- **Multiple Transports**: Run seamlessly over standard `stdio` or `streamable-http`.
|
|
- **(WIP) Screenshots**: Stubs are in place for future full-screen and area screenshot support.
|
|
|
|
---
|
|
|
|
## Requirements
|
|
|
|
- **OS:** Linux (Wayland or X11)
|
|
- **Python:** 3.11+
|
|
- **System:** `uinput` kernel module loaded (standard on almost all distributions).
|
|
|
|
## Installation
|
|
|
|
This project is managed by [Poetry](https://python-poetry.org/).
|
|
|
|
1. Clone the repository and navigate into it:
|
|
```bash
|
|
cd vibe-coded-mcp-desktop-control
|
|
```
|
|
|
|
2. Install the dependencies:
|
|
```bash
|
|
poetry install
|
|
```
|
|
|
|
This will automatically create the `mcp-desktop-control` executable in your Poetry environment.
|
|
|
|
---
|
|
|
|
## The Permission Problem
|
|
|
|
Because this server simulates real hardware at the kernel level, it requires write access to the `/dev/uinput` device node. By default, regular users do not have this permission.
|
|
|
|
You have two choices on how to run this server depending on your workflow.
|
|
|
|
### Option 1: The Native Route (Recommended for background agents like Goose)
|
|
Permanently grant your standard user account access to simulate input. This allows agents to seamlessly start the server in the background without getting stuck waiting for a `sudo` password.
|
|
|
|
1. Add your user to the `input` group:
|
|
```bash
|
|
sudo usermod -aG input $USER
|
|
```
|
|
2. Create a `udev` rule to ensure the input group can write to `/dev/uinput`:
|
|
```bash
|
|
echo 'KERNEL=="uinput", GROUP="input", MODE="0660"' | sudo tee /etc/udev/rules.d/99-uinput.rules
|
|
sudo udevadm control --reload-rules && sudo udevadm trigger
|
|
```
|
|
3. **Reboot your computer** (or log out and back in) for the group changes to take effect.
|
|
|
|
You can now run the server normally:
|
|
```bash
|
|
poetry run mcp-desktop-control
|
|
```
|
|
|
|
### Option 2: The Sudo Route (Using Streamable HTTP)
|
|
If you don't want to change your user groups, you can run the server as `root` in a separate terminal using `sudo`. To prevent your AI agent from hanging on a password prompt, you can run the server over **Streamable HTTP** and have your agent connect to it over the local network.
|
|
|
|
1. Install dependencies for the root user (only needed once):
|
|
```bash
|
|
sudo poetry install
|
|
```
|
|
2. Start the server in a separate terminal:
|
|
```bash
|
|
sudo poetry run mcp-desktop-control --transport streamable-http --host 127.0.0.1 --port 8000
|
|
```
|
|
|
|
*(You can also pass `XKB_DEFAULT_LAYOUT=si` before the command if you want to force a specific layout).*
|
|
|
|
---
|
|
|
|
## Integrating with Goose
|
|
|
|
Goose stores extensions in `~/.config/goose/config.yaml` (Linux/macOS) or `%APPDATA%\Block\goose\config\config.yaml` (Windows).
|
|
|
|
### Option A: STDIO (command) extension
|
|
|
|
Use this when Goose should start the server as a subprocess. The most reliable form is to give the absolute path to the `poetry` binary and the absolute path to the project.
|
|
|
|
```yaml
|
|
extensions:
|
|
desktop_control:
|
|
enabled: true
|
|
name: desktop_control
|
|
type: stdio
|
|
cmd: /usr/bin/poetry
|
|
args:
|
|
- run
|
|
- mcp-desktop-control
|
|
envs:
|
|
XKB_DEFAULT_LAYOUT: "si" # Optional
|
|
```
|
|
|
|
If you have activated the Poetry virtual environment, you can also use just `cmd: mcp-desktop-control` with no `args`.
|
|
|
|
### Option B: Streamable HTTP extension
|
|
|
|
Start the server in a terminal first (this needs `/dev/uinput` access, so run as root if you have not set up the udev rule):
|
|
|
|
```bash
|
|
poetry run mcp-desktop-control --transport streamable-http --host 127.0.0.1 --port 8000
|
|
```
|
|
|
|
Then point Goose at it with `type: streamable_http` and `uri:` (Goose uses `uri`, not `url`):
|
|
|
|
```yaml
|
|
extensions:
|
|
desktop_control:
|
|
enabled: true
|
|
name: desktop_control
|
|
type: streamable_http
|
|
uri: http://localhost:8000/mcp
|
|
timeout: 300
|
|
headers: {}
|
|
envs: {}
|
|
```
|
|
|
|
The server listens on `/mcp` for streamable HTTP traffic, so use `http://localhost:8000/mcp`.
|
|
|
|
---
|
|
|
|
## Available Tools
|
|
|
|
Once connected, your AI agent will automatically have access to the following tools:
|
|
|
|
- `keyboard_type`: Types a string of text dynamically calculating `Shift` and `AltGr` modifiers based on the active layout.
|
|
- `keyboard_action`: Triggers common keyboard shortcuts (`copy`, `paste`, `select_all`, `cut`, `undo`).
|
|
- `mouse_action`: Presses, releases, or clicks the mouse (`left`, `right`, `middle`).
|
|
- `mouse_move_absolute`: Moves the cursor to precise X/Y screen coordinates.
|
|
- `mouse_move_rel`: Moves the cursor relative to its current position.
|
|
- `mouse_scroll`: Scrolls the mouse wheel up or down.
|
|
- `set_pre_action_delay`: Adjusts the sleep timer before actions are executed.
|
|
- `screenshot_full` / `screenshot_area`: *(Coming soon)*
|
|
|
|
## Development
|
|
|
|
Run the test suite with pytest:
|
|
|
|
```bash
|
|
poetry run pytest
|
|
```
|
|
|
|
The Linux backend tests mock `evdev.UInput` so they can run without `/dev/uinput` access.
|
|
|
|
## Future Roadmap
|
|
|
|
1. **Windows Support**: Abstract the `InputBackend` to implement `PyAutoGUI` or `ctypes` for native Windows support.
|
|
2. **macOS Support**: CoreGraphics backend implementation.
|
|
3. **Screenshots**: Implement screenshot capture returning base64 image data for visual agents.
|