codex-cua-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@codex-cua-mcpclick the OK button in Notepad"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
codex-cua-mcp
Collaborative Windows computer use for any MCP agent harness — no cloud, no account, no usage limits.
Windows-MCP and similar tools take over your PC: while the agent drives the mouse and keyboard, you can't. This server does the opposite. Every action names a target window and is delivered to that window only, without raising it, so you keep your focus, your mouse, and your keyboard while the agent works alongside you.
It is backed by the local Codex computer-use helper — a Windows binary that ships with the Codex app. No model runs through it, no request leaves your machine, and there is nothing to be rate-limited by. The model is whatever your harness already talks to: Claude Code, OpenCode, Hermes, Codex, Gemini CLI, Cursor — anything that speaks MCP.
"No cloud" describes this server: it makes no network calls of its own. The accessibility tree and the screenshot it returns go to your harness, which passes them to your model provider — so what leaves your machine is whatever your model already sees.
It also has a second backend that needs no OpenAI binary at all: the
MIT-licensed trycua/cua driver. Same
sixteen tools, same names, same arguments — a harness config does not
change when you switch. See Two backends.
Why this is different from Windows-MCP
Windows-MCP | codex-cua-mcp | |
Focus during agent action | Taken from you (low-level input hooks block you) | Left alone — actions are routed to the target window |
Mouse | Moves the real cursor | Stays where you left it |
Screenshots of occluded windows | No | Yes (Windows.Graphics.Capture) |
Cloud / usage limits | No, but no model either | No — the model is your harness's |
Per-app consent | App-level | App-level, surfaced as an MCP elicitation you answer |
The collaboration is not a wrapper trick. It is a property of how the helper delivers input: per-window UI Automation actuation and coordinate-routed background injection, instead of a global cursor-and-keyboard takeover.
Related MCP server: guarded-computer-use-mcp
Install
One machine
git clone https://github.com/osamabinabsar/windows-cua
cd windows-cua
powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1 -Harness claudeWindows ships with a
Restrictedexecution policy, which blocks local.ps1files. The-ExecutionPolicy Bypassabove is scoped to that one command. If your organisation manages the policy, ask it to allow signed local scripts instead.
The installer creates a virtualenv, installs the package, registers the
server with your harness, and verifies it can find the helper. It is
idempotent — run it again after a git pull and it will update in place.
-Harness accepts claude, codex, opencode, or all.
-Backend accepts codex (the default) or cua.
To install on another PC, clone the repo there and run the same script. See Deploying to other PCs. The one thing that does not copy across is the helper binary: it comes from the Codex app's runtime, not from this repo.
Manually
uv pip installs into a virtualenv, so make one first:
uv venv
uv pip install -e .Or run it straight from the checkout, without a separate install step — uv
makes a virtualenv for it and installs the package into that:
uv run --with "mcp>=2" python -m codex_cua_mcp.serverRequirements
Windows 10 or 11 with UI Automation. (The code checks
sys.platform, not the Windows version — it runs on either, but UI Automation behaves differently on older builds.)Python 3.11+, or
uv, which will fetch one.uvis what the installer uses.Git, to clone the repo. There is no PyPI package yet.
For the
codexbackend: the Codex app (or a standalone helper package), which suppliescodex-computer-use.exe; and thecodexCLI, used for the approval handshake.The Codex CLI on its own is not enough.
npm i -g @openai/codexships the CLI but not the helper. The helper arrives with the Codex desktop app, which installs a runtime the server searches:%LOCALAPPDATA%\OpenAI\Codex\runtimes\cua_node\*\bin\node_modules\@oai\cua\bin\windows\codex-computer-use.exe %LOCALAPPDATA%\OpenAI\Codex\runtimes\cua_node\*\bin\node_modules\@oai\sky\bin\windows\codex-computer-use.exeA current install carries both package names, and the server searches both. Override with
CODEX_COMPUTER_USE_BINif yours lives elsewhere.If you would rather not depend on an OpenAI binary at all, use the
cuabackend below — it needs neither the app nor an account.
Verify the setup:
.venv\Scripts\codex-cua-mcp.exe --checkcodex-cua-mcp is on your PATH only while the virtualenv is
activated; the full path works from anywhere. --check reports which
binaries it found — it is a discovery check, not a test of the whole
chain, so read a clean report as "the pieces are present", not "the
server works".
The MIT backend (no OpenAI binary)
If you would rather not depend on a proprietary binary, install the
trycua/cua driver instead and run the
server with --backend cua:
codex-cua-mcp --backend cua --checkThe driver is MIT-licensed and Rust; it needs no Codex CLI and no OpenAI account. See Two backends.
Register with your harness
The installer does this for you
(powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1 -Harness claude).
To do it by hand:
The examples below start the default
codexbackend. If you installed the MIT driver instead, add--backend cuato the server's arguments — otherwise you silently get the OpenAI binary whichever one you meant.WINDOWS_CUA_BACKEND=cuain the server's environment does the same thing.
Claude Code
claude mcp add --scope user codex-cua -- \
C:\path\to\windows-cua\.venv\Scripts\python.exe -m codex_cua_mcp.serverOr as JSON (~/.claude.json / .mcp.json):
{
"mcpServers": {
"codex-cua": {
"command": "C:\\path\\to\\windows-cua\\.venv\\Scripts\\python.exe",
"args": ["-m", "codex_cua_mcp.server"],
"env": {}
}
}
}OpenCode
~/.config/opencode/opencode.json:
{
"mcp": {
"codex-cua": {
"type": "local",
"command": ["C:\\path\\to\\windows-cua\\.venv\\Scripts\\python.exe", "-m", "codex_cua_mcp.server"],
"enabled": true
}
}
}Codex CLI
~/.codex/config.toml:
[mcp_servers.codex-cua]
command = 'C:\path\to\windows-cua\.venv\Scripts\python.exe'
args = ['-m', 'codex_cua_mcp.server']Any other MCP client
The server speaks MCP over stdio. Point any client at:
C:\path\to\windows-cua\.venv\Scripts\python.exe -m codex_cua_mcp.serverIf you did not use the installer and have no virtualenv, the equivalent is:
uv run --project <path> python -m codex_cua_mcp.serverUninstalling
powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1 -UninstallThat removes the codex-cua entries from ~/.claude.json,
~/.codex/config.toml and ~/.config/opencode/opencode.json — and
nothing else. The rest of each file is edited in place, byte for byte,
so your other settings and their formatting survive. The virtualenv,
the repository and every other setting are left alone.
It is safe to run twice, and safe to run when you never installed anything. If it cannot remove one of the entries it says which file and leaves that file unchanged rather than risking it, and exits non-zero.
Taking the computer back
One chord stops the agent, from outside the harness, at any moment:
Ctrl + Alt + Shift + BackspacePress it once and the agent loses the computer. Press it again and it gets it back. No panel, no tray icon, no prompt to answer.
One press stops the action in flight, takes the on-screen banner down, revokes every approval the agent had been given, and leaves the server running so it can be resumed. While it is held, every computer-use call fails with a message telling the agent to stop and wait for you.
The chord is armed automatically whenever the server starts. Change it
with --takeover-key "Ctrl+Alt+Shift+Pause", or switch it off with
--no-takeover.
The banner
While the Codex helper is driving, it draws a banner on screen. Both sentences in it are yours to set, in a JSON file the helper already reads — no binary is patched:
%USERPROFILE%\.codex\computer-use\config.json{
"accentColor": "#339cff",
"direction": "ltr",
"locale": "en-GB",
"strings": {
"usingComputer": "AI is controlling this computer",
"escToCancel": "Press Ctrl+Alt+Shift+Backspace to take over"
}
}python scripts\set-overlay-text.py --show
python scripts\set-overlay-text.py \
--using "AI is controlling this computer" \
--hint "Press Ctrl+Alt+Shift+Backspace to take over"The helper reads it when it starts an overlay, so restart the MCP
server to see the change. One rule: escToCancel is a label. It does
not make a key work — point it at a key that actually stops the agent.
Tools
Tool | Purpose |
| Installed apps and the windows each owns. Start here. |
| Every open, targetable window. |
| Rehydrate a window by id after a lost binding. |
| Accessibility tree (with element indexes) and/or screenshot. |
| Just the tree text — cheaper than a full state read. |
| Click at window-relative coordinates. |
| Click an element by index, via UI Automation. Prefer this. |
| Type literal text. Pass |
| Key or chord ( |
| Scroll from a window-relative point. |
| Drag between two window-relative points. |
| Replace an editable element's value by index. Empty clears it. |
|
|
| Launch an app by id or |
| Brings a window to the front. The one tool that takes focus on purpose. |
| Which binaries are in use, what is approved, helper log. |
Every action except activate_window leaves your foreground window, your
focus, and your mouse cursor exactly where they were — with one
exception. On the cua backend, a window that refuses background input
makes the driver ask for delivery_mode: "foreground", which it
performs as a brief focus swap that restores your previous window
afterwards. The server never fronts a window on a guess.
Two backends
The server speaks to one of two drivers. Both present the same sixteen tools, so your harness config does not change when you switch.
|
| |
Driver |
|
|
Licence | Proprietary (OpenAI) | MIT |
Needs the Codex app | Yes | No |
Needs an OpenAI account | No | No |
Approval | Per-app MCP elicitation you answer | The driver's own permission model |
Element handles | Per-observation indexes | Stable |
Input delivery | Per-window UI Automation | Explicit |
Switch with a flag:
python -m codex_cua_mcp.server --backend cuaor the WINDOWS_CUA_BACKEND=cua environment variable. --driver (or
CUA_DRIVER_BIN) points at a specific cua-driver.exe if the
auto-detection misses it.
The two differ in three places
Both backends are honest about where they are not equivalent:
perform_secondary_action. The Codex helper has a real accessibility-action tool (Expand,Collapse,Toggle,Invoke). The cua driver does not — its closest isinvoke_menu, which walks an application menu path. So on the cua backend,File>Save Asgoes toinvoke_menu, a plain action name likeInvokeis honoured by clicking the element, and anything it cannot express raises rather than silently doing nothing.Background delivery. Some window classes (dialogs, for instance) refuse background input. The cua driver detects that, says so, and asks for
delivery_mode: "foreground"— which it performs as a brief focus swap that restores your previous foreground window after. The client takes that escalation; it never fronts a window on a guess.Text delivery. The Codex helper's
type_textgoes to whatever holds focus, so it needs anelement_indexto be reliable. The cua driver routes keystrokes to the target window itself, so it works without one — but passelement_indexwhen you mean a specific control.
Where the text goes
On the codex backend, type_text and press_key send keystrokes to
the control that holds focus in the target window. If nothing holds
focus there, the characters are lost and the call still reports
success. So always pass element_index:
type_text(text="hello", element_index=3) # clicks element 3, then types
set_value(element_index=3, value="hello") # no focus needed — the reliable oneset_value with an empty value clears the field. On Windows, click
needs coordinates and click_element is the element-targeted path.
The cua driver routes keystrokes to the target window itself, so
type_text works there without an element_index — but pass one anyway
when you mean a specific control.
Approval model
The helper gates every app behind per-app consent. This server surfaces that as an MCP elicitation: your harness shows you a prompt, you answer, and the answer decides.
The approved-app key is written to the wire only after you accept.
Approvals persist for the session.
list_apps,list_windows,get_window, andstatusnever prompt — they are read-only.
If your harness does not support elicitation, the action fails with a clear error naming the app, rather than proceeding unapproved.
To skip prompts entirely (not recommended):
python -m codex_cua_mcp.server --auto-approveWorkflow that works
Element indexes are only valid for the observation that produced them, and coordinates are only valid for the screenshot they came from. Observe, act once, re-observe.
1. list_apps -> find the app, get its window id
2. get_window_state -> read the tree, note element indexes
3. click_element(index=…) -> exactly one action
4. get_window_state -> verify what changedLayout
src/codex_cua_mcp/
transport.py JSON-RPC over the helper's stdio; approval handshake
client.py the sky Windows API, typed (Codex backend)
cua_backend.py a small MCP client for the trycua/cua driver
cua_client.py the same sky API, over the cua driver
server.py MCP surface + elicitation-based approval
takeover.py the take-over chord, and the gate it closes
overlay.py the helper's banner text
scripts/ protocol probes and a smoke test
tests/ the test suite; CI runs it on every pushEvery script in there is indexed in
scripts/README.md, with what it touches and what
it does not.
Checking the drivers
Codex ships a new helper build now and then, and the helper's undocumented behaviours are the fragile part of this project. When it updates, re-check that the workarounds still hold:
.venv\Scripts\python.exe scripts\probe_helpers.pyIt runs eight checks against the live helper and reports pass/fail for each. The target is Character Map, which cannot hold a user document, so running it cannot damage your work.
The cua backend has its own probe, with the same shape:
.venv\Scripts\python.exe scripts\probe_cua_backend.pyTwenty-four checks against the live cua-driver.exe. Run it after
updating the driver — the driver moves faster than the helper, and its
error messages are specific enough to tell you exactly what changed.
See the architecture doc for what the three workarounds are and why each is needed.
Troubleshooting
Symptom | Where to look |
| You are running an old checkout against new code, or the clone is missing files. Re-clone, or |
| The Codex CLI is not enough — the helper ships with the Codex app. See Requirements. Or use |
| The helper could not find the |
| The virtualenv is not activated. Use |
The mouse pointer disappears over parts of the screen (Explorer nav pane, VS Code file tree, Windows Search list, chat messages) — the item still highlights, but the arrow is gone | |
The agent did not stop when you pressed the chord |
|
The invisible cursor is a Windows 11 / display-driver compositing
fault, not this server and not the MCP tooling. The doc records what
was measured on the machine, what was ruled out, the three candidate
mechanisms, and the by-eye tests that separate them — plus
scripts/fix-mouse-cursor.ps1, which reports and (with Administrator,
and a full power cycle) applies the MPO overrides.
More
Doc | What it is for |
Pointing Claude Code, OpenCode, Codex CLI, Cursor, Gemini CLI or anything else at this server, and telling an agent it exists. | |
Installing on a second or third machine, and what does not copy across. | |
The short version, if you have never set up an MCP server before. | |
The take-over chord, and the banner text. | |
How the pieces fit together, and the three undocumented helper behaviours this project works around. | |
The other projects in this space, and how they differ. |
Licence
MIT. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
Hosted MCP server and REST API that lets AI agents use apps with no API, signed in as you.
- PomeradoOAuthai.pomerado
MCPs that do tasks on any website. Search flights, book, shop, check accounts and fill in forms.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceMCP server for driving any Windows app through five layers including OCR, UI Automation, and direct OS operations. Enables AI agents to control Windows desktop and OS cursor-free, even on background/locked windows.51 npm2MIT
- AlicenseNot gradedqualityAmaintenanceEnables agentic control of Windows via MCP tools for screenshots, mouse, keyboard, UI Automation, OCR, windows, and clipboard, while risky actions require real-human approval through a policy-gated dialog with audit logging.5MIT
- AlicenseNot gradedqualityAmaintenanceGives AI agents full control of a Windows computer over MCP through 63 native tools — screenshots and UI trees for vision, mouse/keyboard input, Chrome control via CDP, plus files, terminal, processes, and SSH/SFTP. The agent can look at the screen, click, type, launch apps, run commands, and verify each step with a fresh screenshot.45MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to see and operate Windows applications through MCP, including windows, screenshots, mouse, keyboard, scrolling, UI Automation, clipboard, and freehand or geometric drawing. Supports supervised creative workflows with native Win32 input, screenshots, allow-listed apps, and an idle safety guard.MIT