npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mcp-remotetouch

v0.2.0

Published

MCP server for remote touch input via SSH to any Linux device

Readme

mcp-remotetouch

An MCP server for remotely controlling a touchscreen on any Linux device over SSH.

Injects tap, swipe, long press, double tap, and keyboard events directly into the device. The daemon auto-detects the touchscreen and screen resolution. Keyboard input is injected via a virtual keyboard device created through /dev/uinput. No installation required on the remote device — the Python daemon is sent via stdin over SSH, using only Python's standard library.

Architecture

Stdio mode (default)

Dev Machine                              Remote Linux Device
┌──────────────────┐    SSH (persistent)  ┌──────────────────┐
│ MCP Server (TS)  │ ──────────────────> │ Python daemon    │
│ stdio transport   │    JSON-line proto  │ (stdlib only)     │
│                   │ <────────────────── │                  │
│ touch_tap         │                     │ Auto-detect      │
│ touch_swipe       │                     │ touchscreen      │
│ touch_long_press  │                     │   ↓              │
│ touch_double_tap  │                     │ /dev/input/eventN│
│ key_press         │                     │   ↓              │
│ key_type          │                     │ /dev/uinput (kbd)│
│ touch_disconnect  │                     │   ↓              │
│                   │                     │ Linux Input      │
└──────────────────┘                     └──────────────────┘

The daemon scans /proc/bus/input/devices to find the physical touchscreen (by checking INPUT_PROP_DIRECT and ABS_MT_POSITION_X), then injects events directly into it. This works reliably with containerized compositors (e.g., Torizon with Qt EGLFS) where virtual uinput devices may not be detected.

HTTP server mode (--server)

AI Agent (remote) ──HTTP/SSE──> Express + StreamableHTTPServerTransport
                                         │
                                   McpServer (per MCP session)
                                         │
                                SshTouchSessionManager (shared)
                                         │
                                   SSH ──> Linux Device

Prerequisites

Dev Machine

  • Node.js 18+
  • SSH client

Remote Device

  • Any Linux device with a touchscreen (Raspberry Pi, SBC, embedded system, etc.)
  • Python 3
  • Read/write access to /dev/input/eventN (the touchscreen device)
  • Write access to /dev/uinput (for keyboard input — optional, touch works without it)

Add the user to the input group on the remote device:

sudo usermod -aG input $USER

Re-login for the change to take effect. Alternatively, use the useSudo option.

Installation

npm install -g mcp-remotetouch

Or run directly with npx:

npx mcp-remotetouch

Usage

Add to your MCP client configuration (e.g. Claude Desktop's claude_desktop_config.json):

{
  "mcpServers": {
    "remotetouch": {
      "command": "npx",
      "args": ["mcp-remotetouch"],
      "env": {}
    }
  }
}

Screen resolution is auto-detected from the device. You can override it with REMOTETOUCH_SCREEN_WIDTH and REMOTETOUCH_SCREEN_HEIGHT if needed.

Environment Variables

| Variable | Default | Description | |---|---|---| | REMOTETOUCH_SSH_HOST | (none) | SSH host of the remote device | | REMOTETOUCH_SSH_USER | pi | SSH username | | REMOTETOUCH_SSH_PORT | 22 | SSH port | | REMOTETOUCH_SSH_KEY | (none) | Path to SSH private key | | REMOTETOUCH_SCREEN_WIDTH | auto-detected | Screen width in pixels | | REMOTETOUCH_SCREEN_HEIGHT | auto-detected | Screen height in pixels | | REMOTETOUCH_USE_SUDO | false | Run daemon with sudo |

Tools

touch_connect

Connect to a remote Linux device via SSH and start the touch daemon. Returns a session ID.

| Parameter | Type | Description | |---|---|---| | host | string? | SSH host | | user | string? | SSH username | | port | number? | SSH port | | sshKey | string? | Path to SSH private key | | screenWidth | number? | Screen width (auto-detected if omitted) | | screenHeight | number? | Screen height (auto-detected if omitted) | | useSudo | boolean? | Run with sudo |

touch_tap

Tap at the given coordinates.

| Parameter | Type | Description | |---|---|---| | sessionId | string | Session ID | | x | number | X coordinate | | y | number | Y coordinate | | duration_ms | number? | Tap duration (default: 50ms) |

touch_swipe

Swipe from (x1, y1) to (x2, y2).

| Parameter | Type | Description | |---|---|---| | sessionId | string | Session ID | | x1 | number | Start X coordinate | | y1 | number | Start Y coordinate | | x2 | number | End X coordinate | | y2 | number | End Y coordinate | | duration_ms | number? | Swipe duration (default: 300ms) | | steps | number? | Number of interpolation steps |

touch_long_press

Long press at the given coordinates.

| Parameter | Type | Description | |---|---|---| | sessionId | string | Session ID | | x | number | X coordinate | | y | number | Y coordinate | | duration_ms | number? | Press duration (default: 800ms) |

touch_double_tap

Double tap at the given coordinates.

| Parameter | Type | Description | |---|---|---| | sessionId | string | Session ID | | x | number | X coordinate | | y | number | Y coordinate |

key_press

Press a key with optional modifier keys. Requires /dev/uinput access on the remote device.

| Parameter | Type | Description | |---|---|---| | sessionId | string | Session ID | | key | string | Key name (e.g. enter, a, tab, f1, up, space) | | modifiers | string[]? | Modifier keys to hold (e.g. ["ctrl"], ["ctrl", "shift"]) |

key_type

Type a string of text by simulating individual key presses. Requires /dev/uinput access on the remote device.

| Parameter | Type | Description | |---|---|---| | sessionId | string | Session ID | | text | string | Text to type (e.g. Hello, World!) |

touch_disconnect

Disconnect a session and clean up the remote daemon.

| Parameter | Type | Description | |---|---|---| | sessionId | string | Session ID |

touch_list_sessions

List all active sessions. No parameters.

HTTP Server Mode

Instead of running as a stdio MCP server, you can run mcp-remotetouch as an HTTP server that AI agents can connect to remotely over HTTP.

Starting the server

# Default: listen on 0.0.0.0:3000
npx mcp-remotetouch --server

# Custom port and host
npx mcp-remotetouch --server --port 8080 --host 127.0.0.1

CLI arguments

| Argument | Default | Description | |---|---|---| | --server | (off) | Enable HTTP server mode | | --port <N> | 3000 (or REMOTETOUCH_PORT env) | HTTP listen port | | --host <addr> | 0.0.0.0 | Bind address |

Without --server, the process runs in stdio mode (the default, backward-compatible behavior).

Workflow

A typical session from Claude Desktop:

  1. touch_connect — connect to the remote device
  2. touch_tap / touch_swipe / touch_long_press / touch_double_tap — interact with the screen
  3. key_press / key_type — send keyboard input
  4. touch_disconnect — end the session

Troubleshooting

Permission denied

The user on the remote device needs access to /dev/input/eventN. Either:

  • Add the user to the input group: sudo usermod -aG input $USER (re-login required)
  • Or set REMOTETOUCH_USE_SUDO=true

No physical touchscreen device found

The daemon could not find a touchscreen in /proc/bus/input/devices. Verify:

  • The device has a touchscreen connected and its driver is loaded
  • The device shows INPUT_PROP_DIRECT and has ABS_MT_POSITION_X capability

Keyboard input not available

The key_press and key_type tools require write access to /dev/uinput. If keyboard is reported as unavailable:

  • Add a udev rule to grant access:
    echo 'KERNEL=="uinput", GROUP="input", MODE="0660"' | sudo tee /etc/udev/rules.d/99-uinput.rules
    sudo udevadm control --reload-rules && sudo udevadm trigger
  • Ensure the user is in the input group: sudo usermod -aG input $USER (re-login required)
  • Or set REMOTETOUCH_USE_SUDO=true

Touch tools continue to work even if /dev/uinput is not accessible.

SSH connection fails

  • Ensure SSH public key authentication is configured for the remote device (password authentication is not supported since the connection uses BatchMode=yes)
  • Verify the hostname and port are correct

License

MIT