jordi-murgo

cliptunnel-mcp

Community jordi-murgo
Updated

Operate a locked-down remote machine through its clipboard — MCP server tunneled over clipboard

cliptunnel-mcp

Operate a locked-down remote machine through its clipboard.

What it does

cliptunnel-mcp turns a shared clipboard into a reliable control channel between two machines. When the remote machine sits behind a Citrix session, a locked-down VDI, or any environment that blocks SSH, file transfer, and networking but still exposes a clipboard, ClipTunnel tunnels commands through that single slot and exposes them as Model Context Protocol tools.

The package ships three layers:

  • Protocol — a wire format (CT1) with base64 payloads, sequence numbers, and typed messages (command, response, error, ack).
  • EndpointsController (operator side) and Agent (remote side), connected by an injected Transport. Both run background threads with ARQ retransmission, sequence-bound deduplication, and generation-safe lifecycle.
  • MCP server — a FastMCP application that exposes the Controller's helpers as remote_shell, remote_fs_*, remote_upload, remote_download, and remote_sysinfo tools over stdio.

The core package has zero dependencies. The MCP server requires the optional [server] extra (mcp>=1.2,<2).

Architecture

Mermaid diagram

Both endpoints share a single last-writer-wins clipboard slot. The protocol uses stop-and-wait ARQ: the Controller writes one command, the Agent ACKs immediately, processes the command in a worker pool, then writes one typed response (R or E) and retransmits it until the Controller's matching ACK arrives. The Controller sends one command at a time and resolves futures as responses come back.

Wire format

CT1|<from>|<to>|<seq>|<type>|<payload>
Field Value
CT1 Protocol signature + version
from C (Controller) or A (Agent)
to C or A
seq Positive integer, monotonic per Controller session
type C (command), R (response), E (error), A (ack)
payload Base64-encoded UTF-8

Installation

pip install cliptunnel-mcp          # core + cliptunnel-agent binary
pip install cliptunnel-mcp[server]  # adds cliptunnel-mcp server binary (mcp>=1.2,<2)

Both modes install console entry points:

Binary Extra needed Purpose
cliptunnel-agent (none) Runs the Agent on the local OS clipboard.
cliptunnel-mcp [server] Runs the MCP server over stdio.

Quick start

Agent (remote machine)

The simplest way to run the Agent is the installed binary:

cliptunnel-agent

Antivirus / EDR workaround (Windows): unsigned .exe entry points may be quarantined. Use python -m instead — it runs through the already-trusted Python interpreter with no generated binary:

python -m cliptunnel_mcp.agent    # instead of cliptunnel-agent
python -m cliptunnel_mcp.server   # instead of cliptunnel-mcp

This builds a ClipboardTransport backed by the system clipboard (pbcopy/pbpaste on macOS, user32 on Windows, wl-copy/wl-paste on Wayland, xclip/xsel on X11) and wires operations.dispatch as the command handler. The Agent watches the clipboard slot, ACKs commands, processes them in a worker pool, and writes responses back. Press Ctrl+C to stop.

Controller + MCP server (operator machine)

On the operator side, configure your MCP client (Claude Desktop, Cursor, Pi, etc.) to launch the server binary:

{
  "mcpServers": {
    "cliptunnel": {
      "command": "cliptunnel-mcp",
      "args": []
    }
  }
}

If the cliptunnel-mcp binary is blocked by antivirus, use python -m:

{
  "mcpServers": {
    "cliptunnel": {
      "command": "python",
      "args": ["-m", "cliptunnel_mcp.server"]
    }
  }
}

The server binary injects a Controller backed by a ClipboardTransport and runs the FastMCP application over stdio. All remote_* tools are available immediately.

Note: the MCP server requires pip install cliptunnel-mcp[server].

Controller only (no MCP)

For programmatic use without an MCP client:

from cliptunnel_mcp.clipboard_transport import ClipboardTransport
from cliptunnel_mcp import Controller
import json

controller = Controller(transport=ClipboardTransport())

# Async — returns a Future
future = controller.send_command(json.dumps({"op": "shell", "cmd": "whoami"}))
result = future.result(timeout=30)

# Sync — blocks until response or timeout
output = controller.send_command_sync(json.dumps({"op": "fs.read", "path": "/etc/hostname"}))

Programmatic Agent

If you need a custom handler or transport:

from cliptunnel_mcp.clipboard_transport import ClipboardTransport
from cliptunnel_mcp import Agent
from cliptunnel_mcp.operations import dispatch

agent = Agent(transport=ClipboardTransport(), handler=dispatch)
# Blocks until agent.close() — run in a thread or manage lifecycle yourself.

API surface

Controller

The operator-side endpoint. Sends commands asynchronously, dispatches one at a time, and resolves futures as responses arrive.

Method Description
send_command(command: str) -> Future Queue a command; returns a Future that resolves with the response payload or None on failure.
send_command_sync(command: str) -> str | None Send and block until response or timeout seconds.
close() Stop background threads. Idempotent.

Constructor parameters: transport (required), timeout, retries, poll_interval, ack_timeout, initial_seq, persist_seq, seq_store.

Agent

The remote-side endpoint. Watches the slot, ACKs commands immediately, processes them in a worker pool, and writes one typed response at a time with retransmission.

Method Description
close() Stop this agent generation. Idempotent; never strands a thread.

Constructor parameters: transport (required), handler (required), poll_interval, max_workers, response_ack_timeout.

dispatch

The default Agent handler. Parses JSON payloads and routes to the matching operation.

from cliptunnel_mcp.operations import dispatch

output, is_error = dispatch('{"op": "shell", "cmd": "echo hello"}')

Protocol primitives

Symbol Description
pack(msg) -> str Serialize a Message into wire format.
unpack(raw) -> Message | None Parse a wire string; None on malformed input.
validate(raw, my_role) -> bool True if raw is well-formed and addressed to my_role.
Message Dataclass: frm, to, seq, mtype, payload.
MsgType Enum: COMMAND, RESPONSE, ERROR, ACK.
Role Enum: CONTROLLER, AGENT.
SeqTracker Per-seq dedupe state: new → processing → done.

Transport protocol

class Transport(Protocol):
    def read(self) -> str: ...
    def write(self, value: str) -> None: ...

class RevisionMonitor(Protocol):
    @property
    def revision(self) -> int: ...
    def wait_for_change(self, after: int, timeout: float = 1.0) -> int: ...

A transport must implement read/write (last-writer-wins). Implementing RevisionMonitor (or exposing wait_for_revision / wait_for_change) enables change-aware waits instead of polling.

Operations

The dispatch handler supports these operations:

Operation Parameters Returns
shell cmd JSON: {stdout, stderr, returncode}
fs.read path JSON: {content, lines}
fs.write path, content wrote N bytes to PATH
fs.list path JSON: [{name, size, is_dir}]
fs.delete path deleted PATH
fs.replace path, old, new replaced 1 occurrence in PATH (exact-once match)
fs.search path, pattern JSON: [{line, content}] (regex)
fs.find path, pattern JSON: [PATH, ...] (glob, ** recurses)
fs.bin_read path JSON: {path, size, b64}
fs.bin_write path, b64 wrote N bytes to PATH

MCP tools

The server exposes 13 tools over stdio:

Tool Description
remote_shell Execute a shell command; auto-sync (10 s) then async with job_id polling.
remote_shell_result Poll for the result of an async shell command.
remote_fs_read Read a file.
remote_fs_write Create or overwrite a file (creates parent dirs).
remote_fs_list List directory entries.
remote_fs_delete Delete a file.
remote_fs_replace Search-and-replace in a file (exact-once match).
remote_fs_search Regex search in a file.
remote_fs_find Glob-find files under a directory.
remote_fs_bin_read Read a binary file as base64.
remote_fs_bin_write Write base64 content to a binary file.
remote_upload Upload a local file to the remote machine.
remote_download Download a remote file to the local machine.
remote_sysinfo Return system info (OS, Python, CPU, memory, disk) from the remote machine.

Lifecycle and coalescing semantics

  • One command at a time: the Controller dispatches commands serially. The pending command's seq is published atomically with the slot write so the reader never observes the command before the dispatcher.
  • Immediate ACK: the Agent ACKs every command before processing, freeing the slot for the Controller.
  • One response at a time: the Agent holds exactly one pending response envelope. A new command never implicitly ACKs a pending response — only the Controller's matching A(seq) releases it.
  • Retransmission: both sides retransmit on ACK timeout. The Controller retries up to retries times (default 3). The Agent retransmits the response every response_ack_timeout seconds (default 1.0).
  • Deduplication: the Agent's SeqTracker tracks per-seq state (new → processing → done). Duplicate commands are ACKed; done ones replay the cached typed response; in-flight ones are already being processed.
  • Stale message guard: the Controller skips any R/E with seq <= min_seq — stale slot content from a previous session.
  • Generation-safe: all stop state and queues are local to each instance. Closing and starting a new Agent or Controller never strands threads.
  • Paced writes: the Controller enforces a bounded inter-write gap (2× poll interval) so the Agent can read each message before it is overwritten.

Backend selection

ClipTunnel ships ClipboardTransport, a transport backed by the OS clipboard. On Wayland it uses wl-paste --watch for event-driven change detection (zero polling, zero CPU when idle). On macOS, Windows, and X11 it polls every 100 ms with hash-based change detection. It implements both Transport and RevisionMonitor, so both endpoints get change-aware waits. The binaries cliptunnel-agent and cliptunnel-mcp use it automatically.

For custom setups — a Citrix clipboard redirection, a shared Gist, a network pipe — implement the Transport protocol (read() -> str, write(str) -> None) and optionally RevisionMonitor (revision + wait_for_change). Inject it into Controller or Agent directly.

Platform support

Platform Status Clipboard backend Change detection
macOS Tested pbcopy/pbpaste (built-in) Polling (100 ms)
Windows Tested ctypes + user32 (no extra deps) Polling (100 ms)
Linux / Wayland Tested wl-copy/wl-paste (wl-clipboard package) Event-driven
Linux / X11 Core works xclip (fallback: xsel) Polling (100 ms)

Development

# Create a virtual environment
uv venv && source .venv/bin/activate

# Install in development mode
uv pip install -e . pytest

# Run the test suite (161 tests)
python -m pytest -q
# or
python -m unittest discover -s tests -t .

# Bare mode — no install, just PYTHONPATH
PYTHONPATH=src:. python -m pytest -q

The test suite uses a deterministic ClipboardSlot test double that models the last-writer-wins channel with revisions and bounded waits. No clipboard hardware is needed.

Limitations

  • Text-only clipboard: the protocol carries UTF-8 strings. Binary files are base64-encoded, which roughly doubles their size over the wire.
  • Single slot: the clipboard holds one value at a time. The ARQ protocol serializes all traffic through it, so throughput is bounded by the clipboard round-trip latency.
  • No encryption: the wire format is plain base64. If the clipboard is observable, use an encryption layer in your transport or handler.

License

MIT — see LICENSE.

MCP Server · Populars

MCP Server · New

    mobbin

    Official Mobbin MCP server

    Official Mobbin MCP server repository

    Community mobbin
    frankchu91

    MindBase — Karpathy's LLM Wiki, as a product

    Karpathy's LLM Wiki idea as a product — an AI that builds and maintains a markdown wiki from your notes and sources. MCP server + web UI, runs on free local models (Ollama), no API key needed. MIT.

    Community frankchu91
    aakarim

    📜 OpenLore

    A minimal, extensible, agent-native knowledge base that keeps shared context current and inspectable

    Community aakarim
    sv-grid

    @svgrid/mcp

    Native Svelte 5 data grid. Headless-first engine + drop-in render component. Row + column virtualization (1M rows), Excel-style filters, inline editing, grouping, pivot, server-side data. MIT core (@svgrid/grid), MCP server for Claude / Cursor. https://svgrid.com

    Community sv-grid
    cinderline

    NorthCinder

    Buyer-run, ad-neutral shopping-agent MCP software with deterministic ranking, signed purchase mandates, and a local audit trail.

    Community cinderline