Skip to content

Commit e83cd54

Browse files
k4cper-gclaude
andcommitted
Add MCP server for cross-OS control from Claude Code
Instead of a standalone agent loop, this exposes remote CUP machines as MCP tools that Claude Code can call directly. Just add the MCP server to your config, point it at cup_server instances on each machine, and talk naturally. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7aba028 commit e83cd54

File tree

2 files changed

+362
-50
lines changed

2 files changed

+362
-50
lines changed

examples/cross-os/README.md

Lines changed: 85 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,123 @@
11
# Cross-OS Agent Demo
22

3-
An AI agent that performs tasks across multiple machines running different operating systems, all using the same CUP (Computer Use Protocol) format.
3+
Control multiple machines running different operating systems from Claude Code (or any MCP client), all through the same CUP accessibility tree format.
44

5-
This demonstrates CUP's core value: **one protocol, every OS**. The agent sees identical accessibility tree formats whether a machine runs Windows, macOS, or Linux — no platform-specific code needed.
5+
This demonstrates CUP's core value: **one protocol, every OS**. Claude sees identical UI trees whether a machine runs Windows, macOS, or Linux — no platform-specific prompting needed.
66

77
## Architecture
88

99
```
1010
┌──────────────────────────────────────────────┐
11-
│ Agent (agent.py) │
12-
│ Claude interprets CUP trees from all │
13-
│ machines and coordinates actions across them │
14-
└──────┬──────────────┬──────────────┬─────────┘
15-
│ │ │
16-
WebSocket WebSocket WebSocket
17-
│ │ │
18-
┌──────▼──────┐ ┌─────▼───────┐ ┌───▼─────────┐
19-
│ Windows PC │ │ Linux Box │ │ Mac │
20-
│ cup_server │ │ cup_server │ │ cup_server │
21-
│ (UIA) │ │ (AT-SPI2) │ │ (AXUIElement│
22-
└─────────────┘ └─────────────┘ └─────────────┘
11+
│ Claude Code / MCP Client │
12+
│ "Open Notepad on windows, type hello, │
13+
│ then open Notes on mac and paste it" │
14+
└──────────────────┬───────────────────────────┘
15+
│ MCP (stdio)
16+
┌──────────────────▼───────────────────────────┐
17+
│ mcp_server.py (MCP bridge) │
18+
│ Exposes snapshot, action, find tools │
19+
│ for each connected machine │
20+
└──────┬──────────────────────────┬────────────┘
21+
│ WebSocket │ WebSocket
22+
┌──────▼──────┐ ┌─────▼────────────┐
23+
│ Windows PC │ │ Mac │
24+
│ cup_server │ │ cup_server │
25+
│ (UIA) │ │ (AXUIElement) │
26+
└─────────────┘ └──────────────────┘
2327
```
2428

2529
## Files
2630

2731
| File | Purpose |
2832
|------|---------|
29-
| `cup_server.py` | WebSocket server that wraps `cup.Session()` — run on each machine |
30-
| `cup_remote.py` | Client library: `RemoteSession` (single machine) and `MultiSession` (multi-machine) |
31-
| `agent.py` | The orchestrator: connects to all machines, uses Claude to perform cross-OS tasks |
33+
| `cup_server.py` | WebSocket server wrapping `cup.Session()` — run on each machine |
34+
| `mcp_server.py` | MCP bridge — connects to remote cup_servers, exposes tools to Claude Code |
35+
| `cup_remote.py` | Client library: `RemoteSession` and `MultiSession` |
36+
| `agent.py` | Standalone agent (alternative to MCP — runs its own Claude loop) |
3237

33-
## Setup
38+
## Quick Start (MCP + Claude Code)
3439

3540
### 1. Install dependencies on every machine
3641

3742
```bash
3843
pip install computeruseprotocol websockets
3944
```
4045

41-
### 2. Start the server on each machine
46+
### 2. Start cup_server on each machine
4247

48+
**On your Windows PC:**
4349
```bash
44-
# On your Windows PC (e.g., 192.168.1.10)
45-
python cup_server.py --port 9800
50+
python cup_server.py --host 0.0.0.0 --port 9800
51+
```
52+
53+
**On your Mac:**
54+
```bash
55+
python cup_server.py --host 0.0.0.0 --port 9800
56+
```
57+
58+
### 3. Add the MCP server to Claude Code
59+
60+
Install the MCP server dependencies (on the machine running Claude Code):
61+
```bash
62+
pip install mcp websocket-client
63+
```
4664

47-
# On your Linux box (e.g., 192.168.1.20)
48-
python cup_server.py --port 9800
65+
Add to your Claude Code MCP config:
4966

50-
# On your Mac (e.g., 192.168.1.30)
51-
python cup_server.py --port 9800
67+
```json
68+
{
69+
"mcpServers": {
70+
"cup-cross-os": {
71+
"command": "python",
72+
"args": [
73+
"C:/path/to/examples/cross-os/mcp_server.py",
74+
"windows=ws://localhost:9800",
75+
"mac=ws://192.168.1.30:9800"
76+
]
77+
}
78+
}
79+
}
5280
```
5381

54-
### 3. Run the agent from any machine
82+
Replace the paths and IPs for your setup. If you're running Claude Code on your Windows machine, `windows` can point to `localhost`.
83+
84+
### 4. Talk to Claude
85+
86+
Now just ask Claude Code naturally:
87+
88+
```
89+
"What apps are open on both machines?"
90+
91+
"Open Notepad on windows and type 'Hello from Mac', then open TextEdit on mac and type 'Hello from Windows'"
92+
93+
"Take a snapshot of the foreground window on mac"
94+
95+
"Click the Submit button on windows"
96+
```
97+
98+
Claude sees the CUP tools (`snapshot_machine`, `act_on_machine`, etc.) and uses them to interact with both machines.
99+
100+
## Standalone Agent (alternative)
101+
102+
If you prefer a self-contained script instead of MCP:
55103

56104
```bash
57-
# Install agent dependencies
58105
pip install anthropic websocket-client
59106

60-
# Set your API key
61-
export ANTHROPIC_API_KEY=sk-ant-...
62-
63-
# Run with a task
64107
python agent.py \
65-
windows=ws://192.168.1.10:9800 \
66-
linux=ws://192.168.1.20:9800 \
67-
--task "Open Notepad on Windows and type 'Hello from Linux', then open gedit on Linux and type 'Hello from Windows'"
108+
windows=ws://localhost:9800 \
109+
mac=ws://192.168.1.30:9800 \
110+
--task "Open a text editor on both machines and type today's date"
68111

69112
# Or interactive mode
70-
python agent.py windows=ws://192.168.1.10:9800 linux=ws://192.168.1.20:9800
113+
python agent.py windows=ws://localhost:9800 mac=ws://192.168.1.30:9800
71114
```
72115

73116
## Example tasks
74117

75118
```
76119
# Cross-OS text relay
77-
"Copy the title of the focused window on Windows and type it into the terminal on Linux"
120+
"Copy the title of the focused window on Windows and type it into the terminal on Mac"
78121
79122
# Parallel app launch
80123
"Open a text editor on both machines and type today's date in each"
@@ -83,13 +126,11 @@ python agent.py windows=ws://192.168.1.10:9800 linux=ws://192.168.1.20:9800
83126
"Take a snapshot of both machines and tell me what apps are running on each"
84127
85128
# Multi-step workflow
86-
"On Windows, open Chrome and navigate to example.com. On Linux, open Firefox and navigate to the same URL."
129+
"On Windows, open Chrome and navigate to example.com. On Mac, open Safari and navigate to the same URL."
87130
```
88131

89132
## Using the client library directly
90133

91-
You don't need the agent to use cross-OS CUP. The client library works standalone:
92-
93134
```python
94135
from cup_remote import RemoteSession, MultiSession
95136

@@ -98,33 +139,27 @@ with RemoteSession("ws://192.168.1.10:9800") as win:
98139
print(win.snapshot(scope="overview"))
99140
win.open_app("notepad")
100141
tree = win.snapshot(scope="foreground")
101-
# find the text area, type into it, etc.
102142

103-
# Multiple machines
143+
# Multiple machines in parallel
104144
with MultiSession({
105145
"win": "ws://192.168.1.10:9800",
106-
"linux": "ws://192.168.1.20:9800",
146+
"mac": "ws://192.168.1.30:9800",
107147
}) as multi:
108-
# Snapshot all machines in parallel
109148
trees = multi.snapshot_all(scope="foreground")
110149
for name, tree in trees.items():
111150
print(f"--- {name} ---")
112-
print(tree[:200]) # first 200 chars
151+
print(tree[:200])
113152

114-
# Act on specific machines
115153
multi["win"].action("e5", "click")
116-
multi["linux"].action("e12", "type", value="hello")
154+
multi["mac"].action("e12", "type", value="hello")
117155
```
118156

119157
## Protocol
120158

121-
The server uses a simple JSON-RPC protocol over WebSocket:
159+
The cup_server uses a simple JSON-RPC protocol over WebSocket:
122160

123161
```json
124-
// Request
125162
{"id": 1, "method": "snapshot", "params": {"scope": "foreground"}}
126-
127-
// Response
128163
{"id": 1, "result": "# CUP 0.1.0 | windows | 1920x1080\n..."}
129164
```
130165

0 commit comments

Comments
 (0)