Sandbox
@vitalops/opendesk

Desktop control framework for MCP agents

Opendesk lets an agent see and operate a computer through screenshot, UI, mouse, keyboard, clipboard, and OCR tools. It also supports recording workflows, replaying them, scheduling tasks, and controlling paired remote machines over an encrypted connection.

85 stars16 forksPythonUpdated 12d ago
Who it's for

Builders who want their agent to operate a desktop, automate repeated workflows, or control a paired remote machine.

What it delivers

You can let your agent click, type, inspect, replay, and schedule real desktop workflows instead of doing them by hand.

What it does

Screenshot and UI tools

Captures the screen with marked elements and lets the agent click or type by element name instead of coordinates.

Mouse, keyboard, clipboard, and OCR

Provides low-level desktop actions plus text extraction from screen regions.

Learn and replay workflows

Records a task once and replays it later from the current screen state.

Scheduled runs

Runs learned or ad hoc tasks on a timer with `opendesk scheduler start`.

Remote machine control

Pairs controllers and controlled machines over an encrypted WebSocket and lets the same tools target local or remote desktops.

MCP integrations

Works as an MCP server with Claude Code, Claude Desktop, Cursor, Windsurf, Continue, and custom clients.

How to get it

  1. 1Run
    pip install 'opendesk[core,mcp]'
    opendesk install        # shortcut for Claude Code
  2. 2Run
    npm install @vitalops/opendesk-sdk
    npx opendesk-js install        # shortcut for Claude Code
  3. 3Once connected, try
    Take a screenshot of my screen
    Click the Chrome icon
    Open Spotify and play lo-fi beats
    Show me the audit log
    Replay everything from this session

README

opendesk

Give any AI agent eyes and hands on your desktop.

Opendesk is a computer use framework that lets AI agents navigate your computer just like a human would — screenshots, mouse, keyboard, UI interaction, OCR, workflow recording, scheduling, and remote machine control.

macOS · Linux · Windows

PyPI npm License: MIT Docs


https://github.com/user-attachments/assets/5a6fab31-9f53-4ddb-9efb-17f0afe97844

Single Machine Demo
Screenshot, click, type, navigate — all from natural language.

https://github.com/user-attachments/assets/629cf31b-12ab-4913-bc03-963f1cfbd682

Control Multiple Machines
Drive remote desktops over encrypted WebSocket — same tools, same agent.

https://github.com/user-attachments/assets/659c9e30-e8f6-4a5a-ab81-0fa7ccaf8fb8

UI Testing
Test a full web app — navigate, create, verify — with zero selectors.


SDKs

LanguageLocationPackageInstall
Pythonpython/opendesk (PyPI)pip install 'opendesk[core,mcp]'
JavaScript / TypeScriptjs/@vitalops/opendesk-sdk (npm)npm install @vitalops/opendesk-sdk

More SDKs can be added to this repo following the same pattern.


MCP install

opendesk works as an MCP server with any MCP-compatible client — Claude Code, Claude Desktop, Cursor, Windsurf, Continue, or any custom tool.

Python

pip install 'opendesk[core,mcp]'
opendesk install        # shortcut for Claude Code

Requires Python 3.10+

JavaScript / TypeScript

npm install @vitalops/opendesk-sdk
npx opendesk-js install        # shortcut for Claude Code

Other MCP clients (Cursor, Windsurf, Continue, custom)

Point your client at the opendesk-mcp binary:

{
  "mcpServers": {
    "opendesk": { "command": "opendesk-mcp" }
  }
}

For JS:

{
  "mcpServers": {
    "opendesk": {
      "command": "node",
      "args": ["/path/to/node_modules/@vitalops/opendesk-sdk/bin/opendesk-mcp.js"]
    }
  }
}

Once connected, try:

Take a screenshot of my screen
Click the Chrome icon
Open Spotify and play lo-fi beats
Show me the audit log
Replay everything from this session

SDK usage

Use opendesk programmatically in your own agent or app.

Python

from opendesk import create_registry, allow_all_context

registry = create_registry()
ctx = allow_all_context()

result = await registry.get("screenshot").execute(ctx, ...)

JavaScript / TypeScript

import { OpenDeskClient } from "@vitalops/opendesk-sdk";

const client = new OpenDeskClient();
await client.screenshot({ marks: true });
await client.ui({ action: "click", app: "Safari", title: "Go" });

Architecture

opendesk is built in independently-importable layers:

┌──────────────────────────────────────────────────────────────┐
│  Integrations   MCP  ·  Claude Code  ·  OpenAI  ·  LangChain │
├──────────────────────────────────────────────────────────────┤
│  Tools          screenshot · mouse · keyboard · ui ·         │
│                 clipboard · ocr · learn · schedule · audit   │
├──────────────────────────────────────────────────────────────┤
│  Computer       LocalComputer  ·  RemoteComputer  (ABC)      │
├──────────────────────────────────────────────────────────────┤
│  Remote         server · client · discovery (mDNS)           │
├──────────────────────────────────────────────────────────────┤
│  Protocol       frames · codec (msgpack) · peer · transports │
│                 auth (X25519 + AEAD, pairing)                │
└──────────────────────────────────────────────────────────────┘
LayerWhat it does
ComputerThe capability surface of a computer (observe / act / subscribe). LocalComputer drives the local machine; RemoteComputer forwards every call over the wire to a paired peer. Tools and integrations target this ABC — they never know whether the machine is local or remote.
ToolsOne class per capability, agent-friendly Pydantic schemas. Calls into the active Computer on the ToolContext.
IntegrationsThin adapters for MCP, Anthropic, OpenAI, LangChain — add one tool, get all four.
Remoteopendesk serve / opendesk pair, mDNS discovery, client helper.
ProtocolFive-frame wire protocol (msgpack binary, no base64 ever), WebSocket transport, mutual X25519 + ChaCha20-Poly1305 auth and encryption.
Automationlearn + schedule backed by pynput recording, JSON storage, APScheduler daemon.

Full details → docs/architecture.md


Tools

ToolWhat it does
screenshotCapture the screen with numbered boxes on every clickable element (Set-of-Marks)
uiClick and type by element name — no coordinates needed
mousePixel-level mouse control for anything ui can't reach
keyboardType text, press keys, send hotkeys
appOpen, close, and focus applications
clipboardRead and write the system clipboard
ocrExtract text from any region of the screen
learnRecord a workflow once, replay it anytime
scheduleRun any task or learned procedure on a timer

Full reference → docs/tools.md


Automation

Record a task once, replay it forever, or put it on a schedule.

Record

"Start recording task expense-form"

Perform the workflow yourself. The agent captures every click, keystroke, and screenshot.

Replay

"Stop recording"
"Replay expense-form"

The agent re-executes using the current screen state — no hardcoded coordinates.

Schedule

"Every morning at 9am, open my email in Chrome, take a screenshot, and summarize what's there"
"Schedule expense-form every friday at 5pm"
opendesk scheduler start

Supported timing: every 30m · every 2h · every day at 09:00 · every friday at 17:00 · raw cron

Full guide → docs/automation.md


Remote computer use

Control another machine from your agent — same tools, same MCP server, the Computer abstraction just lives on the other end of an encrypted WebSocket.

On the machine being controlled (one time):

pip install 'opendesk[core,remote]'
opendesk pair        # prints a 6-digit code, listens

On the controller (one time):

pip install 'opendesk[remote]'
opendesk discover                          # list opendesk peers on the LAN
opendesk pair-with <host> <code> --name mini

After pairing, the controlled machine runs the long-lived server:

opendesk serve            # accepts paired peers only

…and the controller drives it through the existing MCP server (Claude Code, Claude Desktop, Cursor — anything that speaks MCP). The agent gets new admin tools — opendesk_peers, opendesk_use, opendesk_status — and every existing tool accepts an optional peer: argument:

screenshot                       → controls the local machine
screenshot peer=mini             → controls the paired remote
opendesk_use mini                → make mini the default for this session
screenshot                       → [on mini] ...

With exactly one paired peer the agent doesn't have to specify anything — it becomes the implicit default. With multiple, the agent must pick explicitly (no silent fallback).

One controller at a time. Pair as many machines as you like, but only one drives the desktop at a time — a second peer trying to connect while one is active gets a clean BUSY error. Same peer reconnecting bumps the previous session (no waiting out a stale TCP). Two ways to free the slot from the controlled machine:

  • opendesk disconnectcooperative. Server asks the controller to leave via a session.evicted PUSH; a cooperative client (the in-tree RemoteComputer) suppresses its auto-reconnect and raises SessionEvicted. Trust is preserved.
  • opendesk unpair <name>enforced. Revokes trust + closes the session; next reconnect fails authentication.

Security model: pairing exchanges long-lived X25519 keypairs via a 6-digit code-authenticated handshake (PBKDF2-stretched, ~CPU-month to brute force). Subsequent connections use mutual static-key authentication. Every frame is ChaCha20-Poly1305 AEAD-encrypted with per-direction counters. No CA-signed certificates required — the keys ARE the trust.

Full guide → docs/remote.md


Installation options

pip install opendesk                              # core framework only
pip install 'opendesk[core,mcp]'                  # + screen capture + MCP server (recommended)
pip install 'opendesk[core,mcp,remote]'           # + control another machine over LAN
pip install 'opendesk[core,mcp,learn]'            # + task recording and replay
pip install 'opendesk[core,mcp,learn,schedule]'   # + scheduled tasks
pip install 'opendesk[all]'                       # everything

Platform support

FeaturemacOSLinuxWindows
Screenshot
Mouse & keyboard
UI element accessAppleScriptAT-SPI2UI Automation
Clipboardpbcopy/pbpastexclip/xselpyperclip
OCRVision / tesseracttesseractWinRT / tesseract
App controlopen -axdg-openstart
Task recording
Scheduled tasks
Remote control (LAN)
LAN discovery (mDNS)

System permissions

macOS

  • System Settings → Privacy & Security → Screen Recording — enable for your terminal
  • System Settings → Privacy & Security → Accessibility — enable for mouse/keyboard control

Linux

sudo apt install xclip xdotool python3-atspi

Windows

No extra permissions needed — opendesk uses Win32 APIs by default.

See docs/permissions.md for full setup guide.


Integrations

Claude Code

opendesk install        # registers opendesk-mcp globally
opendesk uninstall      # removes the registration

Claude Desktop

Add to your config file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "opendesk": { "command": "opendesk-mcp" }
  }
}

Python API

import asyncio
from opendesk import create_registry, allow_all_context

async def main():
    registry = create_registry()
    ctx = allow_all_context()

    result = await registry.get("screenshot").execute(
        ctx, registry.get("screenshot").Params(marks=True)
    )
    print(result.output)

asyncio.run(main())

Works with Anthropic SDK, OpenAI, and LangChain — see docs/integrations.md

On-device models (Ollama, LM Studio, vLLM, llama.cpp)

Any OpenAI-compatible local server works out of the box:

from openai import OpenAI
from opendesk.integrations.openai_compat import OpenAIAdapter

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
adapter = OpenAIAdapter()
result = await adapter.run_loop(client, model="qwen2.5:72b", messages=messages)

Citation

If you use opendesk in your research or project, please cite it:

@software{opendesk,
  author  = {Abraham, Abhigith Neil and Rahman, Fariz and Rahman, Fadil},
  title   = {opendesk: Open Desktop Automation Framework},
  year    = {2026},
  url     = {https://github.com/vitalops/opendesk},
  version = {0.2.0},
  license = {MIT}
}

A CITATION.cff is included — GitHub's "Cite this repository" button will pick it up automatically.


License

MIT

Files in the repo

Repository payload12 top-level entries
  • .github
  • docs
  • examples
  • js
  • python
  • .gitignore
  • CITATION.cff
  • CODE_OF_CONDUCT.md
  • CONTRIBUTING.md
  • LICENSE
  • mkdocs.yml
  • README.md

Discussion (0)

Ask about usage, or say what you built with it

Sign in to join the discussion.

No comments yet. Be the first to say what this is good for.

More frameworks & sdks

HKUDS/nanobotFrameworks & SDKs

Ultra-lightweight, open-source, self-hosted personal AI agent framework in Python with WebUI, tools, memory, MCP, multi-agent workflows, automation, and chat apps

48k
microsoft/
SkillOpt
microsoft/SkillOptFrameworks & SDKs

SkillOpt is a text-space optimizer that trains reusable natural-language skills for frozen LLM agents through trajectory-driven edits, validation-gated updates, and deployable best_skill.md artifacts.

17k
omnigent-ai/omnigentFrameworks & SDKs

Omnigent is an open-source AI agent framework and meta-harness: orchestrate Claude Code, Codex, Cursor, Pi, and custom agents — swap harnesses without rewriting, enforce policies and sandboxing, and collaborate in real time from any device.

9.8k
kyegomez/
OpenMythos
kyegomez/OpenMythosFrameworks & SDKs

A theoretical reconstruction of the Claude Mythos architecture, built from first principles using the available research literature.

15k
D4Vinci/ScraplingFrameworks & SDKs

🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!

80k