Ghost

MCP serverWeb & browsing

Verified desktop control for agents on Windows and Linux: apps with no API, windows, shell, browser.

Unavailable. This server has no hosted endpoint yet, so ahel can't serve it.

Connect ahel once, and every AI you use reads what you have installed.

From the project's README

As published by northtekdevs/ghost in README.md.

Verified control of the whole desktop, for agents and programs, on Windows and Linux. Ghost gives Claude Code, Codex, Cursor, any MCP harness, or a plain script the operating system's own control surface: the apps with no API, the windows, the shell, and the browser you are already logged into - in the background without taking your screen or cursor, with every action proven to have happened.

Like Playwright, but for the native desktop, and built for agents. Ghost does the perceiving, the acting, and the verifying; the model you are already running does any looking that is needed, so there is no vision API key to set.

One MCP surface, two engines: Win32 UI Automation on Windows, AT-SPI2 over D-Bus on Linux. The verbs, the locator tiers and the act-then-verify loop are written once and behave the same on both. Platform support · Linux setup

Why Ghost is different

  • Runs in the background, and that is enforced. An agent can click, type, and use shortcuts inside an app while you keep working in another window - no focus steal, no cursor jump. It posts window messages to real controls and uses UI Automation patterns on windowless ones; most tools can only drive whatever is in the foreground. Since 0.19 this is a policy, not a preference: the focus policy defaults to background. Since 0.20 it is also constructive: anything Ghost starts (an app, a windowed browser) is born on a hidden desktop that has its own input queue and cannot take your foreground, and the ordinary verbs drive it there by window title. A call that truly has no background path fails naming the action instead of quietly taking the screen. Since 0.22 the policy is locked there: no tool call can raise it, so an agent cannot decide on its own to take your mouse. You can, by setting GHOST_FOCUS_LOCK=off in the server's environment. And since 0.23 a window that grabs the foreground on its own - browsers do, on their own accessibility calls - is handed straight back, so your typing keeps going where you are looking. Measured on a real desktop with a person typing throughout: of roughly 490 keystrokes a run, zero to one reached the window the agent was driving. (how)
  • Never your window by accident. The session remembers the last window the agent named or launched and every window-scoped verb targets it by default. The human's foreground window is used only when nothing was ever anchored, and the response says so. Three weeks of real transcripts showed "element not found in the foreground window" as the top failure before this; it was the agent searching the window you had open.
  • Many agents at once. Requests are dispatched in parallel, so a 15-second wait in one tab does not stall an instant query behind it, and a second Ghost process runs its own browser alongside the first without contending for the mouse.
  • Prove it on your machine. ghost verify drives the real MCP server over stdio and audits every claim above against hard timing budgets, exiting non-zero if any of them does not hold on your hardware.
  • Every action is verified. Ghost re-checks the screen (or reads the control's value back) after acting and returns verified / focus_confirmed - never a blind ok:true. Agents fail by acting and not knowing if it worked; Ghost closes that loop.
  • Drives apps with no API. Legacy Win32, WPF, Electron, UWP, vendor portals - the software that has no integration and most needs automating. No CDP, no browser, no app cooperation required.
  • No vision key. The model driving Ghost reads ghost_see (every element with its name, role and on-screen centre) or ghost_screenshot itself. Ghost's own vision tier is optional, exists for callers with no model of their own, and is off until configured.
  • Accessibility-native and deep. Real element discovery through the OS's own accessibility API - UI Automation on Windows, AT-SPI2 on Linux - not pixel-guessing. Elements come back with real names, roles and bounds.

See it in one script: examples/background_agent_demo.py drives an app in the background while the foreground stays yours. Honest comparison vs Playwright-MCP / cua-driver / Computer Use: docs/comparison.md.

What people use it for

Vision is the smallest part of it. In a typical session an agent calls Ghost mostly to act, to manage windows and processes, to run commands, and to read state back.

UseToolsTypical caller
Driving apps with no API: installers, legacy line-of-business software, vendor portals, WPF and Electron toolsghost_act, ghost_key, ghost_scroll, ghost_dragagents, RPA scripts
Window and process control: launch invisibly, focus, minimize, restore, close, recover hidden windows, sweep orphaned browsersghost_window, ghost_desktop_*, ghost_statsagents, ops scripts
A terminal for the agent: builds, git, CLIs, persistent PowerShell state, spawning another Claude Code sessionghost_shell, ghost_runcoding agents on Windows
Driving the browser you are already signed into, through its DevTools port: tabs, navigation, DOM clicks, JS eval, page text19 ghost_browser_* and ghost_tab_* toolsagents, web automations
Reading data out of apps with no export: accessibility text, tab text, OCRghost_see mode=text, ghost_tab_textagents, reporting scripts
Making "did it work" a machine check: element exists, value equals, wait for idle or textghost_assert, ghost_waitQA agents, CI
Isolated desktops: overnight GUI work and parallel agents that never touch the human's screenghost_window op=launch, the focus policy, ghost_desktop_*autonomous runs
Reproducible multi-step flows with retries and conditions, no model in the loopintents via ghost run, POST /run, ghost_execute_intentscheduled jobs
The clipboard as a bridge into apps that resist typingghost_clipboardall of the above

Every row runs under the same guarantees: the action returns verified, the default policy never takes your foreground, and Ctrl+Alt+G stops every Ghost process at once.

What is Ghost?

Ghost is the layer between a model and the desktop. The model reasons; Ghost sees the screen the way the operating system does, acts on real controls without touching your foreground, and reports whether the action took. It gives programmatic control over any desktop application - native Win32, Electron, WPF, UWP, GTK, Qt, or otherwise - to an agent, a script, or a program.

On Windows it uses UI Automation for element discovery, SendInput for keyboard/mouse injection, and DXGI/GDI for screen capture. On Linux it uses AT-SPI2 over D-Bus for discovery and actions, XTEST (X11) or the RemoteDesktop portal / uinput (Wayland) for input, and X11 GetImage or the Screenshot portal for capture. The Linux engine is pure Rust - no -devel packages to install.

Ship it three ways:

  • ghost-mcp server - the primary surface: a Model Context Protocol server for Claude Code, Claude Desktop, Codex, Cursor, and any MCP client (54 tools on Windows)
  • ghost CLI - one-shot commands, great for scripts and CI (ghost click --name "Submit")
  • ghost-http server - local REST API, call it from Python, Node, curl, anything (curl http://127.0.0.1:7878/list-windows)

The MCP surface is 20 desktop verbs, 19 ghost_browser_* / ghost_tab_* tools for driving individual browser tabs in the background (Chrome, Comet, Edge, Brave), and 15 Windows-only tools: the focus policy plus ghost_desktop_* for explicit control of isolated Windows desktops the user never sees. Under the default policy you rarely need the latter: ghost_window op=launch already starts the app on the hidden desktop auto, and ghost_see / ghost_act / ghost_key / ghost_scroll reach it with window=<title> exactly as they reach a window on your own desktop (target.surface in the response tells you which). UIA, window messages and capture work fully there. Real SendInput does not, because Windows refuses it off the input desktop, and typing is proven by reading the control's value back, so a target that drops posted characters returns an error rather than a false success. The desktop verbs and the browser tools build on Linux as well; the focus policy and hidden desktops are Windows-only.

No Claude required. No browser required. No CDP. It drives apps through the OS's own automation and input APIs, so it works with native apps that have no API and no automation hooks of their own - the same reliability whether or not an app was built to be automated.

Platforms

PlatformStatusEngine
Windows✅ full and verifiedghost-core - Win32 UI Automation, SendInput, posted window messages, DXGI/GDI capture
Linux, X11✅ functional - verified by live CI tests against a real GTK appghost-linux - AT-SPI2 over D-Bus, XTEST input, X11 GetImage capture
Linux, Wayland⚠️ implemented, NOT verified - no test has run it on hardwaresame AT-SPI2 discovery and actions; input and capture go through the RemoteDesktop / Screenshot portals or uinput instead
macOS🚧 scaffoldAccessibility + CGEvent + ScreenCaptureKit - to be built on a Mac

Wayland deserves the separate row rather than a footnote: it is the default session on current Ubuntu and Fedora, so it is what most Linux users would actually run, and it is the part with no test behind it. The discovery and action layer is shared with X11 and is covered, and it is the layer that matters most here - AT-SPI2 asks the application to do the thing, so there is no pointer to move and no window to raise. What is unverified is the fallback underneath: portal input, portal capture, uinput. If you run Wayland, treat ghost doctor as the first thing to run and expect to file bugs. Reports are welcome and are the fastest way that row changes.

ghost-session and ghost-mcp are shared: the locator tiers, grounding cascade, act-then-verify loop and the 20 core MCP verbs are written once and run on both platforms. Only the engine underneath changes, behind a one-line cfg alias. The browser and tab tools are engine-independent and build for both; the focus policy and isolated desktops are Windows-only and are reported as such rather than faked.

The wedge survives the port. On Windows, driving an app without stealing focus is built on posted window messages. Linux has a cleaner analogue in AT-SPI2 actions: the application performs the operation through its own toolkit, so there is no pointer to move and no window to raise. That layer is the same code under X11 and Wayland; synthetic input is only the fallback beneath it, and the fallback is the part Wayland has not been tested on.

This is tested, not asserted: CI stands up a real desktop (Xvfb + D-Bus + at-spi-bus-launcher), drives a real GTK application, and requires that text written through AT-SPI reads back from the app and that invoking a button actually dismisses the dialog. Wayland portal input and capture are implemented but not yet verified on hardware.

Linux setup, verification checklist and honest limitations: docs/linux-fedora.md. Capability matrix across all three: docs/cross-platform.md.

Ghost is a general-purpose automation tool. Use it on systems you own or are authorized to automate, and in line with the terms of the software you drive.

Install

One-click - MCP Bundle (free). Every release ships ghost-windows-x64.mcpb and ghost-linux-x86_64.mcpb on the Releases page. Open one in a client that supports MCP Bundles (Claude Desktop: Settings -> Extensions -> Install from file) and Ghost is registered, no PATH or config editing, and no API key. Ghost is also listed in the MCP registry as io.github.NORTHTEKDevs/ghost, so registry-aware clients can install it from there. The bundle holds the ghost-mcp server only; the CLI and HTTP server are in the archives below.

Prebuilt binaries (free). Every release ships signed-by-checksum archives for both platforms on the Releases page:

# Linux x86_64
curl -LO https://github.com/NORTHTEKDevs/ghost/releases/latest/download/ghost-linux-x86_64.tar.gz
curl -LO https://github.com/NORTHTEKDevs/ghost/releases/latest/download/ghost-linux-x86_64.tar.gz.sha256
sha256sum -c ghost-linux-x86_64.tar.gz.sha256
tar -xzf ghost-linux-x86_64.tar.gz && ./install.sh

Windows: download ghost-windows-x64.zip from the same page. Verify the checksum, unzip, and add the folder to your PATH. Then run ghost doctor.

Check where a download came from. Every release artifact carries a signed build provenance attestation, so you can prove a file came out of this repository's release workflow and nowhere else, at a named commit:

gh attestation verify ghost-windows-x64.mcpb --repo NORTHTEKDevs/ghost

The binaries are not code-signed yet, so Windows SmartScreen will warn you on first run (click More infoRun anyway). That warning is about publisher identity, which needs a paid certificate tied to a verified legal entity; the attestation above is the stronger statement about origin and costs nothing, but Windows does not read it. The pipeline signs the moment a certificate is configured, from any CA - see docs/code-signing.md, and docs/signing-policy.md for what gets signed, by whom, and what leaves your machine (nothing, unless you configure a vision key). If an antivirus engine quarantines a release, verify the checksum and see docs/antivirus.md for what the binaries do to stay recognisable and how to report a false positive. The kit buys convenience, not capability - everything Ghost can do is in the free source below, and building it yourself takes one command.

Option C - Build from source (free, MIT). Ghost is open source. Compile it yourself:

git clone https://github.com/NORTHTEKDevs/ghost
cd ghost
cargo build --release --bin ghost --bin ghost-http --bin ghost-mcp
# binaries in target/release/

Requirements: Windows 10 build 19041+, or Linux with at-spi2-core (and Rust stable only if building from source).

On Linux:

sudo dnf install at-spi2-core xdg-desktop-portal xdg-desktop-portal-gnome
gsettings set org.gnome.desktop.interface toolkit-accessibility true
./scripts/install.sh          # build, install, register the MCP server, run doctor

No -devel packages are needed - the Linux engine is pure Rust. Full setup and troubleshooting: docs/linux-fedora.md.

Check your machine first:

ghost doctor

Reports PASS/WARN/FAIL and exits 1 if anything is FAIL. Run it before opening an issue - it usually names the problem outright.

  • Windows: build version, interactive desktop, UI Automation, DPI awareness, monitor layout, screen capture, optional vision credentials.
  • Linux: session type (X11/Wayland), AT-SPI bus reachability, whether applications are actually exposing accessible trees, the selected input backend, and screen capture.

Quick Start - coding agents and MCP clients

This is the path Ghost is built for. Nothing to configure and no API key.

Claude Desktop: download ghost-windows-x64.mcpb (or the Linux bundle) from the latest release and open it: Settings -> Extensions -> Install from file.

Claude Code:

claude mcp add ghost --scope user -- C:/path/to/ghost-mcp.exe

Any other MCP client (Codex, Cursor, a custom harness): register the binary as a stdio server.

{
  "mcpServers": {
    "ghost": { "command": "C:/path/to/ghost-mcp.exe" }
  }
}

Ghost is also listed in the MCP registry as io.github.NORTHTEKDevs/ghost for clients that install from there.

The repo's Dockerfile builds a headless image (docker build -t ghost-mcp .) that answers initialize and tools/list with no display; registries and CI use it to introspect the server. A container has no windows to drive, so it is not an install path for real use.

How an agent uses it. The loop is look, act, confirm:

  1. ghost_see window="Invoice Editor" - every element in the window with its name, role, enabled state, and on-screen centre. Text mode extracts the readable text instead, roughly ten times cheaper in tokens than an image.
  2. ghost_act window="Invoice Editor" name="Save" action="click" - Ghost drives the control in the background and returns verified: true only when the screen or the control's value shows the action took.
  3. ghost_screenshot window="Invoice Editor" - pixels, for the moments a layout, a chart, or a canvas needs the model's own eyes.

The model reads step 1 and step 3 and chooses; Ghost never has to guess what a picture means, and no vision key is involved.

Beyond the loop: ghost_shell runs commands and persistent PowerShell sessions, ghost_window launches, lists, focuses, restores and closes windows (on a hidden desktop by default), ghost_assert and ghost_wait turn "did it work" into a check, and the ghost_tab_* tools drive the browser you are already signed into. Most real sessions spend more calls there than on looking.

54 tools on Windows (legacy names stay dispatchable): 20 desktop verbs covering see/snapshot/find/act/keys/scroll/drag/clipboard/screenshot/windows/shell/waits/query/run, 19 ghost_browser_* / ghost_tab_* tools, and 15 Windows-only tools for the focus policy and isolated desktops. Building from source instead of downloading: cargo build -p ghost-mcp --release.

Every tool runs on its own task, so a slow call does not block a fast one, and a second Ghost process can run alongside the first. Once it is mounted, run ghost verify to audit that on your own machine.

Speed. Ghost's own time is small: about 75 ms for a text read, 200 ms for a verified click, 1 ms to list windows. What makes an agent session slow is what happens around the calls, and three habits remove most of it. Name the window once and omit window= afterwards: the anchor follows that window by handle, and a title it used to have still resolves instantly with title_drift in the response. Wait for a condition, not a duration: ghost_wait for=element, for=value, and for=navigate (sets the address bar in the background and returns when the title changes, about 0.4 to 1.4 s where a fixed sleep costs 6) return the moment the thing happened. Batch with ghost_run so one model turn does several steps. scripts/speed-probe.mjs measures all of this against any ghost-mcp binary.

Shell control (ghost_shell)

Ghost drives GUIs and the command line. ghost_shell runs terminal commands and persistent PowerShell sessions - builds, git, CLIs, file edits on hosts without file tools, or launching apps. op=run is a one-shot (powershell/pwsh/cmd); op=open starts a persistent PowerShell whose variables and cwd survive across op=send calls. Output is merged stdout+stderr, tail-capped for the agent's context window; a timed-out command keeps running and is drained with op=read; ghost_stop kills a runaway. op=run with the default powershell is served from a pre-spawned spare process, so a command costs about 85 ms instead of the 230-450 ms a fresh PowerShell start takes (the spare is single-use and replaced immediately; GHOST_SHELL_WARM=off disables it).

Spawn a fresh Claude Code session from the agent: ghost_shell op=run cmd='Start-Process wt -ArgumentList "pwsh","-NoExit","-Command","claude"', then drive the new terminal window with ghost_see / ghost_act / ghost_key.

Security: shell access is powerful. Set GHOST_SHELL=off in the server's env to disable the verb entirely - every op then returns a clear refusal, leaving the GUI automation verbs fully usable.

Quick Start - CLI

# Launch Notepad and type into it
ghost launch notepad.exe
ghost focus-window "Notepad"
ghost type --role edit --text "hello from ghost"

# Keys and hotkeys
ghost press Enter
ghost hotkey --mods Ctrl --key s

# Screenshot
ghost screenshot --out shot.png

# Enumerate windows or UI
ghost list-windows
ghost describe --window "Notepad"

# Click at coords or by name
ghost click-at 500 300
ghost click --name "Save"

# Run a JSON intent (finite-state machine with retries, timeouts, conditions)
ghost run my-flow.json
echo '{"ops":[{"op":"launch","exe":"notepad.exe"}]}' | ghost run -

Everything outputs JSON for easy piping into jq or scripts.

Quick Start - HTTP Server

Start the server:

ghost-http --addr 127.0.0.1:7878

Then from any language:

# Bash / curl
curl http://127.0.0.1:7878/list-windows
curl -X POST http://127.0.0.1:7878/click \
  -H 'content-type: application/json' \
  -d '{"name":"Submit"}'
curl http://127.0.0.1:7878/screenshot -o shot.png
# Python
import requests
requests.post("http://127.0.0.1:7878/launch", json={"exe": "notepad.exe"})
requests.post("http://127.0.0.1:7878/type",
              json={"role": "edit", "text": "hello from python"})
// Node
await fetch("http://127.0.0.1:7878/hotkey", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ mods: ["Ctrl"], key: "s" }),
});

Endpoints: /health, /tools, /click, /click-at, /type, /press, /hotkey, /screenshot, /launch, /list-windows, /focus-window, /window-state, /describe, /clipboard (GET/POST), /run.

Quick Start - Rust SDK

[dependencies]
ghost-session = { git = "https://github.com/NORTHTEKDevs/ghost" }
use ghost_session::{GhostSession, By, session::Region};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let session = GhostSession::new()?;
    session.launch("notepad.exe").await?;
    let edit = session.find(By::role("edit")).await?;
    edit.type_text("hello world")?;
    let png = session.screenshot(Region::full()).await?;
    std::fs::write("screen.png", png)?;
    Ok(())
}

Reliability Model

Desktop automation driven from an MCP client has a hostile focus environment: between tool calls, the client's own terminal usually retakes OS focus. Ghost is built for that:

Shortened here. Read the whole README on GitHub.

Signals

GitHub stars
24
Forks
3
Last commit
Sep 2026
Advanced
Delivery
ghost MCP server → your ahel gateway (mcp.ahel.ai) → every connected AI client.
Catalog kind
mcp-server
Gateway key
io-github-northtekdevs-ghost
Source
github.com/northtekdevs/ghost