Skip to main content
Glama
jordi-murgo

cliptunnel-mcp

by jordi-murgo

cliptunnel-mcp

Управляйте изолированной удалённой машиной через её буфер обмена.

Что это делает

cliptunnel-mcp превращает общий буфер обмена в надёжный канал управления между двумя машинами. Когда удалённая машина находится за сессией Citrix, в изолированном VDI или в любом окружении, которое блокирует SSH, передачу файлов и сеть, но всё ещё предоставляет буфер обмена, ClipTunnel туннелирует команды через этот единственный слот и предоставляет их как инструменты Model Context Protocol.

Пакет включает три уровня:

  • Protocol — формат передачи (CT1) с payload в base64, порядковыми номерами и типизированными сообщениями (команда, ответ, ошибка, подтверждение).

  • Endpoints — Controller (сторона оператора) и Agent (удалённая сторона), соединённые инжектируемым Transport. Оба запускают фоновые потоки с повторной передачей ARQ, дедупликацией на основе порядковых номеров и жизненным циклом, безопасным для поколений.

  • MCP server — приложение FastMCP, которое предоставляет помощники Controller как инструменты remote_shell, remote_fs_*, remote_upload и remote_download через stdio.

Базовый пакет не имеет зависимостей. MCP-сервер требует дополнительный extra [server] (mcp>=1.2,<2).

Related MCP server: Sky Windows Remote Executor

Архитектура

Mermaid diagram

Обе конечные точки используют единый слот буфера обмена по принципу last-writer-wins. Протокол использует ARQ с остановкой и ожиданием: Controller записывает одну команду, Agent немедленно отправляет ACK, обрабатывает команду в пуле воркеров, затем записывает один типизированный ответ (R или E) и повторяет передачу, пока не придёт соответствующий ACK от Controller. Controller отправляет по одной команде за раз и резолвит futures по мере поступления ответов.

Формат передачи

CT1|<from>|<to>|<seq>|<type>|<payload>

Field

Value

CT1

Сигнатура протокола + версия

from

C (Controller) или A (Agent)

to

C или A

seq

Положительное целое, монотонное в рамках сессии Controller

type

C (команда), R (ответ), E (ошибка), A (подтверждение)

payload

UTF-8, закодированный в Base64

Установка

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

Оба режима устанавливают консольные точки входа:

Binary

Extra needed

Purpose

cliptunnel-agent

(none)

Запускает Agent с системным буфером обмена.

cliptunnel-mcp

[server]

Запускает MCP-сервер через stdio.

Быстрый старт

Agent (удалённая машина)

Самый простой способ запустить Agent — установленный бинарник:

cliptunnel-agent

Обходной путь для антивируса / EDR (Windows): неподписанные .exe-точки входа могут быть помещены в карантин. Вместо этого используйте python -m — он работает через уже доверенный интерпретатор Python, и никакой бинарник не создаётся:

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

Это создаёт ClipboardTransport на основе системного буфера обмена (pbcopy/pbpaste на macOS, user32 на Windows, wl-copy/wl-paste на Wayland, xclip/xsel на X11) и подключает operations.dispatch в качестве обработчика команд. Agent следит за слотом буфера обмена, отправляет ACK на команды, обрабатывает их в пуле воркеров и записывает ответы обратно. Нажмите Ctrl+C для остановки.

Controller + MCP-сервер (машина оператора)

На стороне оператора настройте ваш MCP-клиент (Claude Desktop, Cursor, Pi и т. д.) на запуск серверного бинарника:

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

Если бинарник cliptunnel-mcp блокируется антивирусом, используйте python -m:

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

Серверный бинарник внедряет Controller на основе ClipboardTransport и запускает приложение FastMCP через stdio. Все инструменты remote_* доступны сразу.

Примечание: для MCP-сервера требуется pip install cliptunnel-mcp[server].

Только Controller (без MCP)

Для программного использования без MCP-клиента:

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"}))

Программный Agent

Если вам нужен собственный обработчик или транспорт:

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

Controller

Конечная точка на стороне оператора. Отправляет команды асинхронно, диспетчеризует по одной и резолвит futures по мере поступления ответов.

Method

Description

send_command(command: str) -> Future

Ставит команду в очередь; возвращает Future, который резолвится с полезной нагрузкой ответа или None при сбое.

send_command_sync(command: str) -> str | None

Отправляет и блокирует выполнение до получения ответа или истечения timeout секунд.

close()

Останавливает фоновые потоки. Идемпотентно.

Параметры конструктора: transport (обязательный), timeout, retries, poll_interval, ack_timeout, initial_seq, persist_seq, seq_store.

Agent

Конечная точка на удалённой стороне. Следит за слотом, немедленно отправляет ACK на команды, обрабатывает их в пуле воркеров и записывает по одному типизированному ответу за раз с повторной передачей.

Method

Description

close()

Останавливает поколение этого Agent. Идемпотентно; никогда не оставляет поток в подвешенном состоянии.

Параметры конструктора: transport (обязательный), handler (обязательный), poll_interval, max_workers, response_ack_timeout.

dispatch

Обработчик Agent по умолчанию. Разбирает JSON-полезные нагрузки и направляет их в соответствующую операцию.

from cliptunnel_mcp.operations import dispatch

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

Примитивы протокола

Symbol

Description

pack(msg) -> str

Сериализует Message в формат передачи.

unpack(raw) -> Message | None

Разбирает строку формата передачи; None при некорректном вводе.

validate(raw, my_role) -> bool

True, если raw корректно сформирован и адресован роли my_role.

Message

Датакласс: frm, to, seq, mtype, payload.

MsgType

Перечисление: COMMAND, RESPONSE, ERROR, ACK.

Role

Перечисление: CONTROLLER, AGENT.

SeqTracker

Состояние дедупликации по seq: new → processing → done.

Транспортный протокол

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: ...

Транспорт должен реализовывать read/write (last-writer-wins). Реализация RevisionMonitor (или предоставление wait_for_revision / wait_for_change) позволяет ожидать изменения вместо опроса.

Операции

Обработчик dispatch поддерживает следующие операции:

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 (совпадение ровно один раз)

fs.search

path, pattern

JSON: [{line, content}] (регулярное выражение)

fs.find

path, pattern

JSON: [PATH, ...] (glob, ** — рекурсивный обход)

fs.bin_read

path

JSON: {path, size, b64}

fs.bin_write

path, b64

wrote N bytes to PATH

Инструменты MCP

Сервер предоставляет 13 инструментов через stdio:

Tool

Description

remote_shell

Выполняет команду оболочки; автосинхронизация (10 с), затем асинхронно с опросом job_id.

remote_shell_result

Опрашивает результат асинхронной команды оболочки.

remote_fs_read

Читает файл.

remote_fs_write

Создаёт или перезаписывает файл (создаёт родительские каталоги).

remote_fs_list

Перечисляет содержимое каталога.

remote_fs_delete

Удаляет файл.

remote_fs_replace

Поиск и замена в файле (ровно одно совпадение).

remote_fs_search

Поиск по регулярному выражению в файле.

remote_fs_find

Находит файлы по glob-шаблону в каталоге.

remote_fs_bin_read

Читает бинарный файл как base64.

remote_fs_bin_write

Записывает base64-содержимое в бинарный файл.

remote_upload

Загружает локальный файл на удалённую машину.

remote_download

Скачивает удалённый файл на локальную машину.

Жизненный цикл и семантика объединения

  • По одной команде за раз: Controller отправляет команды последовательно. seq ожидающей команды публикуется атомарно вместе с записью слота, поэтому читатель никогда не наблюдает команду до диспетчера.

  • Немедленный ACK: Agent подтверждает каждую команду до обработки, освобождая слот для Controller.

  • Один ответ за раз: Agent хранит ровно один ожидающий конверт с ответом. Новая команда никогда не подтверждает неявно ожидающий ответ — только совпадающий A(seq) от Controller освобождает его.

  • Повторная передача: обе стороны повторно передают при таймауте ACK. Controller делает до retries попыток (по умолчанию 3). Agent повторно отправляет ответ каждые response_ack_timeout секунд (по умолчанию 1.0).

  • Дедупликация: SeqTracker Agent отслеживает состояние по каждому seq (new → processing → done). Дублированные команды подтверждаются получают ACK; завершённые проигрывают кэшированный типизированный ответ; выполняемые уже обрабатываются.

  • Защита от устаревших сообщений: Controller пропускает любые R/E с seq <= min_seq — устаревшее содержимое слота из предыдущей сессии.

  • Безопасность между поколениями: всё состояние остановки и очереди изолированы для каждого экземпляра. Закрытие и создание нового Agent или Controller никогда не оставляет зависшие потоки.

  • Размеренные записи: Controller обеспечивает ограниченный интервал между записями (2× интервал опроса), чтобы Agent успевал прочитать каждое сообщение до его перезаписи.

Выбор бэкенда

ClipTunnel поставляется с ClipboardTransport — транспортом на основе системного буфера обмена. На Wayland он использует wl-paste --watch для событийного обнаружения изменений (ноль опроса, ноль нагрузки на CPU в простое). На macOS, Windows и X11 используется опрос каждые 100 мс с обнаружением изменений по хэшу. Он реализует и Transport, и RevisionMonitor, так что обе конечные точки получают ожидание с учётом изменений. Бинарники cliptunnel-agent и cliptunnel-mcp используют его автоматически.

Для пользовательских конфигураций — перенаправление буфера обмена Citrix, общий Gist, сетевой канал — реализуйте протокол Transport (read() -> str, write(str) -> None) и, опционально, RevisionMonitor (revision + wait_for_change). Внедряйте его напрямую в Controller или Agent.

Поддержка платформ

Платформа

Статус

Бэкенд буфера обмена

Обнаружение изменений

macOS

Протестировано

pbcopy/pbpaste (встроенный)

Опрос (100 мс)

Windows

Протестировано

ctypes + user32 (без доп. зависимостей)

Опрос (100 мс)

Linux / Wayland

Протестировано

wl-copy/wl-paste (пакет wl-clipboard)

Событийное

Linux / X11

Ядро работает

xclip (фallback: xsel)

Опрос (100 мс)

Разработка

# 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

Тестовый набор использует детерминированный тестовый двойник ClipboardSlot, моделирующий канал «последний запишет — тот и победил» с ревизиями и ограниченными ожиданиями. Оборудование для значений изменений изменений изменений изменений.

Ограничения

  • **Буфер обмена только для текста протокол переносит UTF-8 строки. Бинарные файлы кодируются в base64, что примерно удваивает их размер.

  • Один слот: буфер обмена хранит одно значение. Протокол ARQ сериализует весь трафик через него, поэтому пропускная способность limited латентностью прохождения данных через буфер обмена.

  • Без шифрования: wire-формат — обычный base64. Если буфер обмена можно наблюдать, используйте слой шифрования в вашем транспорте или обработчике.

Лицензия

MIT — см. LICENSE:<-/p>

Related MCP Connectors

Related MCP Servers