Skip to main content
Glama
jordi-murgo

cliptunnel-mcp

by jordi-murgo

cliptunnel-mcp

제한된 원격 머신을 클립보드를 통해 운영합니다.

기능

cliptunnel-mcp는 공유 클립보드를 두 머신 간의 신뢰할 수 있는 제어 채널로 전환합니다. 원격 머신이 Citrix 세션, 제한된 VDI, 또는 SSH, 파일 전송, 네트워킹을 차단하지만 클립보드는 여전히 노출하는 환경 뒤에 위치할 때, ClipTunnel은 명령을 그 단일 슬롯을 통해 터널링하고 이를 Model Context Protocol 도구로 노출합니다.

패키지는 세 가지 구성 요소를 제공합니다:

  • 프로토콜 — base64 페이로드, 시퀀스 번호, 타입이 지정된 메시지(명령, 응답, 오류, ack)를 갖춘 와이어 포맷(CT1).

  • 엔드포인트 — Controller(운영자 측)와 Agent(원격 측), 주입된 Transport로 연결됩니다. 둘은 ARQ 재전송, 시퀀스 기반 중복 제거, 세대 안전 수명 주기를 갖춘 백그라운드 스레드를 실행합니다.

  • MCP 서버 — FastMCP 애플리케이션으로, Controller의 헬퍼를 remote_shell, remote_fs_*, remote_upload, remote_download 도구로 stdio를 통해 노출합니다.

핵심 패키지는 의존성이 없습니다. MCP 서버는 선택적 [server] 확장(mcp>=1.2,<2)이 필요합니다.

Related MCP server: Sky Windows Remote Executor

아키텍처

Mermaid diagram

두 엔드포인트는 단일 last-writer-wins 클립보드 슬롯을 공유합니다. 프로토콜은 stop-and-wait ARQ를 사용합니다: Controller는 하나의 명령을 쓰고, Agent는 즉시 ACK하고, 워커 풀에서 명령을 처리한 다음, 하나의 타입이 지정된 응답(R 또는 E)을 쓰고 Controller의 일치하는 ACK가 도착할 때까지 재전송합니다. Controller는 한 번에 하나의 명령을 보내고 응답이 돌아오면 퓨처를 해결합니다.

와이어 포맷

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

필드

값

CT1

프로토콜 서명 + 버전

from

C(Controller) 또는 A(Agent)

to

C 또는 A

seq

양의 정수, Controller 세션당 단조 증가

type

C(명령), R(응답), E(오류), A(ack)

payload

Base64 인코딩된 UTF-8

설치

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

두 모드 모두 콘솔 진입점을 설치합니다:

바이너리

필요한 확장

용도

cliptunnel-agent

(없음)

로컬 OS 클립보드에서 Agent를 실행합니다.

cliptunnel-mcp

[server]

stdio를 통해 MCP 서버를 실행합니다.

빠른 시작

에이전트(원격 머신)

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

이것은 시스템 클립보드(macOS의 pbcopy/pbpaste, Windows의 user32, Wayland의 wl-copy/wl-paste, X11의 xclip/xsel)로 지원되는 ClipboardTransport를 구축하고 operations.dispatch를 명령 핸들러로 연결합니다. Agent는 클립보드 슬롯을 감시하고, 명령을 ACK하고, 워커 풀에서 처리하고, 응답을 다시 씁니다. Ctrl+C를 눌러 중지합니다.

컨트롤러 + 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"]
    }
  }
}

서버 바이너리는 ClipboardTransport로 지원되는 Controller를 주입하고 stdio를 통해 FastMCP 애플리케이션을 실행합니다. 모든 remote_* 도구가 즉시 사용 가능합니다.

참고: MCP 서버는 pip install cliptunnel-mcp[server]가 필요합니다.

컨트롤러만 사용(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"}))

프로그래매틱 에이전트

사용자 정의 핸들러 또는 전송이 필요한 경우:

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

운영자 측 엔드포인트. 명령을 비동기적으로 보내고, 한 번에 하나씩 디스패치하며, 응답이 도착하면 퓨처를 해결합니다.

메서드

설명

send_command(command: str) -> Future

명령을 큐에 넣습니다; 응답 페이로드로 완료되거나 실패 시 None으로 완료되는 Future를 반환합니다.

send_command_sync(command: str) -> str | None

보내고 응답 또는 timeout 초까지 차단합니다.

close()

백그라운드 스레드를 중지합니다. 멱등적입니다.

생성자 매개변수: transport(필수), timeout, retries, poll_interval, ack_timeout, initial_seq, persist_seq, seq_store.

Agent

원격 측 엔드포인트. 슬롯을 감시하고, 명령을 즉시 ACK하고, 워커 풀에서 처리하며, 재전송과 함께 한 번에 하나의 타입이 지정된 응답을 씁니다.

메서드

설명

close()

이 에이전트 세대를 중지합니다. 멱등적이며 스레드를 버려두지 않습니다.

생성자 매개변수: 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"}')

프로토콜 프리미티브

기호

설명

pack(msg) -> str

Message를 와이어 포맷으로 직렬화합니다.

unpack(raw) -> Message | None

와이어 문자열을 파싱합니다; None은 잘못된 입력 시 반환됩니다.

validate(raw, my_role) -> bool

raw가 잘 구성되고 my_role에 주소가 지정된 경우 True.

Message

데이터클래스: frm, to, seq, mtype, payload.

MsgType

열거형: COMMAND, RESPONSE, ERROR, ACK.

Role

열거형: CONTROLLER, AGENT.

SeqTracker

시퀀스별 중복 제거 상태: 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 핸들러는 다음 작업을 지원합니다:

작업

매개변수

반환

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 도구

서버는 stdio를 통해 13개의 도구를 노출합니다:

도구

설명

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는 모든 명령을 처리하기 전에 ACK하여 Controller를 위해 슬롯을 비웁니다.

  • 한 번에 하나의 응답: Agent는 정확히 하나의 보류 중인 응답 봉투를 보유합니다. 새 명령은 보류 중인 응답을 암시적으로 ACK하지 않습니다. 오직 Controller의 일치하는 A(seq)만이 이를 해제합니다.

  • 재전송: 양쪽 모두 ACK 타임아웃 시 재전송합니다. Controller는 retries 횟수(기본값 3)만큼 재시도합니다. Agent는 response_ack_timeout초(기본값 1.0)마다 응답을 재전송합니다.

  • 중복 제거: Agent의 SeqTracker는 seq별 상태(new → processing → done)를 추적합니다. 중복 명령은 ACK되고, 완료된 명령은 캐시된 타입 응답을 재생하며, 진행 중인 명령은 이미 처리 중입니다.

  • 오래된 메시지 가드: Controller는 seq <= min_seq인 모든 R/E를 건너뜁니다 — 이는 이전 세션의 오래된 슬롯 콘텐츠입니다.

  • 세대 안전: 모든 중지 상태와 큐는 각 인스턴스에 로컬입니다. 새 Agent 또는 Controller를 닫고 시작해도 스레드가 좌초되지 않습니다.

  • 간격 조절 쓰기: Controller는 제한된 쓰기 간 간격(폴링 간격의 2배)을 적용하므로 Agent는 각 메시지를 덮어쓰기 전에 읽을 수 있습니다.

백엔드 선택

ClipTunnel은 OS 클립보드를 기반으로 하는 전송인 ClipboardTransport를 제공합니다. Wayland에서는 이벤트 기반 변경 감지를 위해 wl-paste --watch를 사용합니다(폴링 없음, 유휴 시 CPU 0%). macOS, Windows, X11에서는 해시 기반 변경 감지로 100ms마다 폴링합니다. 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 ms)

Windows

테스트됨

ctypes + user32 (추가 의존성 없음)

폴링 (100 ms)

Linux / Wayland

테스트됨

wl-copy/wl-paste (wl-clipboard 패키지)

이벤트 기반

Linux / X11

핵심 동작

xclip (대체: xsel)

폴링 (100 ms)

개발

# 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

테스트 스위트는 리비전과 제한된 대기를 갖춘 last-writer-wins 채널을 모델링하는 결정적 ClipboardSlot 테스트 더블을 사용합니다. 클립보드 하드웨어는 필요 없습니다.

제한 사항

  • 텍스트 전용 클립보드: 프로토콜은 UTF-8 문자열을 전달합니다. 바이너리 파일은 base64로 인코딩되어 전송 시 크기가 약 두 배가 됩니다.

  • 단일 슬롯: 클립보드는 한 번에 하나의 값만 보유합니다. ARQ 프로토콜은 모든 트래픽을 이를 통해 직렬화하므로 처리량은 클립보드 왕복 지연 시간에 의해 제한됩니다.

  • 암호화 없음: 와이어 형식은 일반 base64입니다. 클립보드가 관찰 가능한 경우 전송 또는 핸들러에 암호화 계층을 사용하세요.

라이선스

MIT — LICENSE 참조.

Related MCP Connectors

Related MCP Servers