Skip to main content
Glama

rig-gateway

A self-hosted MCP server that exposes a remote Windows machine to an AI agent, over a private tailnet. Built as a drop-in replacement for vendor remote-desktop MCP servers (AweSun / 向日葵, AnyDesk, TeamViewer and friends) on machines where you cannot accept a third-party client running resident and mediating every session through a vendor cloud.

Two parts, usable together or apart:

  • rig_gateway/ — the MCP server. Read-only by default; tiered opt-in for writes, screenshots, and command execution.

  • skills/rig-remote-ops/ — a Claude Skill encoding the operating discipline: deploy order, the verification ladder, and the failures that look green but prove nothing.


Why replace it

Vendor remote-desktop MCP

rig-gateway

Third-party client resident

yes

no

Session path

through vendor cloud

your own tailnet

Credential that can silently expire

vendor API token

none — yours, on your network

Works when the vendor is down or blocked

no

yes

What it can do

fixed, vendor-defined

tiered, you choose

Write confinement

vendor-specific rule

one configured root, component-checked

Audit trail

vendor-side

yours

The operational argument is the deciding one. A vendor token that expires quietly is indistinguishable from a machine that went offline, and the fix is not in your hands.

Related MCP server: Smart Assistant MCP

Honest capability comparison

Against a 17-tool AweSun MCP (session mgmt ×4, file transfer ×8, desktop control ×5):

Capability

AweSun

rig-gateway

Notes

Session/device status

✅

✅

File list / read

✅

✅

File upload / download

✅

✅

mkdir / rename / delete

✅

✅

writes need a configured sandbox root

Desktop screenshot

✅

✅

ours is a raw frame; no element annotation

Click / type / hotkeys

✅

✅

tier 3, off by default

Run command on target

✅

✅

tier 3, off by default

Interactive login / unlock

✅

❌

gap — we cannot type into a locked session

Multi-monitor / virtual display

✅

⚠️

ours captures the active display

Vendor SSO / device groups

✅

❌

by design

Mouse click injection

✅

⚠️

hotkeys and typing only; no click primitive

Two real gaps worth stating plainly: we cannot reach a locked or disconnected console (the vendor client can reattach a session; we cannot), and there is no click primitive — scripted automation that needs to press a specific pixel is not yet supported.

Install

pip install -e .

Requires Python ≥ 3.10 and, for the optional tiers, psutil, pillow, pyautogui.

Run

Read-only, stdio (the usual local-client setup):

export RIG_SANDBOX_ROOT='C:\approved\directory'   # writes are refused without it
rig-gateway --transport stdio

Add screenshot and file mutation:

rig-gateway --transport stdio --enable-tier2

Add command execution and keystrokes — requires both the flag and the server env var:

RIG_ALLOW_TIER3=1 rig-gateway --transport stdio --enable-tier2 --enable-tier3

The two-key requirement is deliberate. These are the tools that can reach the target's real control software; a client that enables them by accident is exactly the failure this is meant to prevent.

Over HTTP instead:

rig-gateway --transport streamable-http --host 127.0.0.1 --port 8099

Bind to a loopback or tailnet address and put authentication in front of it. This server has no built-in auth — that is a deliberate choice, so the auth story stays explicit rather than becoming a silent default.

Security model

  • Reads are unrestricted. A diagnostic channel that cannot read the thing it is diagnosing is not useful.

  • Every mutation is confined to RIG_SANDBOX_ROOT, checked component-wise. C:\rootX is outside C:\root, even though it starts with those characters — a prefix test is not containment, and that distinction is enforced by tests.

  • Both ends of a transfer are on the host. An MCP tool cannot see the client's disk, so transfer_out/transfer_in's "local" side is the server's own filesystem. The read end stays unrestricted; the write end is confined like every other write. (It was not, once — a copy could land anywhere the process could write.)

  • Overwriting takes two independent keys: overwrite=True from the caller and RIG_ALLOW_OVERWRITE=1 on the server.

  • Directory deletion requires an explicit recursive=True, so a stray call cannot take out a non-empty tree by accident.

  • Tier 3 is refused by default, twice over: the flag and the environment variable.

  • host_status() reports the live policy instead of asserting safety in prose.

Verification

The failure that motivates the Skill: a server with no log destination blocks permanently once the pipe buffer fills. It keeps its listening socket, so TCP still connects and every HTTP request times out. A listening port is not a responding server.

verify_endpoint.py walks eight checks — route, TCP, liveness, auth enforcement, handshake, exact tool inventory, a real tool call, and an identity read-back — and fails at the first unproven step.

python verify_endpoint.py --host 100.64.0.1 --port 8099 --auth none \
    --expect-marker-file 'C:\approved\directory\channel-marker.txt'

--auth none is not a shortcut — it is the honest statement that this server ships without authentication, and the verifier says so on exit rather than reporting a green run as if auth had been checked. If you have put auth in front of it, pass --auth required and the check becomes a real one. --profile vendor covers the older GetSystemInfo/FileRead naming if you are verifying a server you have not replaced yet.

The tests are negative on purpose. test_starved_listener_is_rejected reproduces a socket that accepts and never answers, and asserts the verifier rejects it — without that assertion, a regression would pass the happy path while the channel was dead.

What has actually been run

Verified end to end on a real host over streamable-http (mcp 2.1.1, Python 3.14): the eight checks pass against the live server, tools/list returns exactly the enabled tier, a real system_info call returns live data, and a marker file reads back from an intended path. The sandbox was confirmed by attempting the escapes — transfer_out to the desktop and write_file to C:\Windows are both refused with the reason text, while the same transfer_out into the sandbox root succeeds.

That last detail is a fix, not a detail: a refusal used to reach the client as Error executing tool write_file with the policy text scrubbed, which reads as a broken server rather than a working sandbox.

Deploying over the internet

Use a mesh VPN (Tailscale, Headscale, Netbird) so no inbound ports are opened on the target's router. The tailnet encrypts the transport; a relayed connection is slower but equivalent. See skills/rig-remote-ops/SKILL.md for the full sequence.

Provenance

Built behind the inkjet-rig work on DESKTOP-AE2K3NN, to replace the AweSun MCP that was the only usable channel to that machine. What it stands on, and what each debt actually is:

  • dddabtc/winremote-mcp (MIT) — the reference this project answers. We use no code from it; it is the 40-tool FastMCP server we were using and set out to replace, and the comparison table above is drawn against it. It in turn credits CursorTouch/Windows-MCP. The one piece still on loan is a name: the verifier's WINREMOTE_RIG_TOKEN and the vendor-profile tools it checks (GetSystemInfo/FileRead) are that project's vocabulary, kept so the verifier can still test a server you have not replaced yet. RIG_TOKEN and the rig-gateway profile are ours.

  • The mcp SDK (MIT) — the transport and protocol this server implements. Read dependency, not derived code.

  • CursorTouch/Windows-MCP — transitive, credited here only because the chain would be dishonest to truncate at one link. We depend on it in no form.

  • tailscale/tailscale (BSD-3-Clause) — carries the transport in deployment. Not a code dependency; the tailscale command in SKILL.md is the external CLI.

The skill in skills/rig-remote-ops/ was reworked from the operator notes and the verify_endpoint.py verifier of a first attempt, kept briefly at ClimbHillTmr/remote-win-mcp and since archived. That repository holds nothing this one does not.

License

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to safely perform file operations, run terminal sessions, manage processes, search content, and inspect Git repositories on a local Windows machine under configurable permission and audit controls.
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to safely work on Windows developer workstations through governed, project-scoped filesystem access, durable command execution, bounded search, Windows operations, and resource-aware runtime controls. It also supports optional developer-context backends for code navigation, repository graph exploration, and memory retrieval.
    Apache 2.0
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to administer a local Windows machine by listing and controlling services, processes, event logs, ports, network lookups and system diagnostics through sharply typed tools. A built-in web interface lets the operator switch every tool on or off individually, with least privilege as the default.
    2
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables AI coding agents to work inside a disposable Windows guest desktop, where they can run shell commands, launch applications, inspect and operate native GUI controls, perform browser DOM actions, and transfer files. Fresh observations, PNG screenshots, and hashed artifacts let agents verify results without touching the host desktop.
    18
    MIT