Skip to main content
Glama

rex-mcp

Let an AI agent read, type into, and run commands in Rex terminal blocks on your own machine, through the rex CLI.

rex-mcp is an MCP server over stdio by default, with an optional HTTP mode (bearer token) for clients on other machines. Ask the agent to list your sessions, read a block's screen, type a command into a block, or run a command and wait for it to finish.

It follows the design of herdr-mcp: one passthrough tool that runs a fixed allowlist of CLI verbs, plus a skill tool that serves the CLI's own guide. The differences are the CLI underneath and the transports (stdio by default; HTTP with a bearer token when you enable it, where herdr-mcp is HTTP-only).

What you need

  • Rex installed, with its app or server available on this machine. The CLI finds the local server on its own; like plain rex, a call may autostart a missing server.

  • Node.js 22 or later.

  • rex on the PATH of the process that spawns the MCP server, or REX_MCP_BINARY pointing at it. Inside Rex terminals this is automatic; outside, check which rex.

Related MCP server: Shell Server

Install

git clone <this repo> && cd rex-mcp
npm install
npm test

Run it

The server speaks MCP over stdio, so a client spawns it; running it by hand just waits for JSON-RPC on stdin. Point a client's MCP config at it:

{
  "mcpServers": {
    "rex-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/rex-mcp/bin/rex-mcp.mjs"]
    }
  }
}

On startup it prints one probe result to stderr: the Rex server endpoint it will drive (a unix socket or a host address), the server version and session count. There is no HTTP host or port — if you see Rex server: not reachable, the first tool call may still autostart the local server, like plain rex does.

Or install the package and use the binary: npm install -g rex-mcp (or just link from a checkout), then set "command": "rex-mcp".

Optional environment variables:

Variable

Default

Meaning

REX_MCP_BINARY

rex

Path to the rex executable. REX_BIN_DIR is used as a fallback parent directory.

REX_MCP_WAIT_MAX

90000

Wait ceiling in milliseconds for wait calls.

REX_MCP_HTTP

unset

Set to 1 to serve Streamable HTTP instead of stdio. Same as --http.

REX_MCP_HOST

127.0.0.1

HTTP bind address (--host overrides).

REX_MCP_PORT

8791

HTTP port (--port overrides).

REX_MCP_TOKEN_FILE

~/.config/rex-mcp/token

Bearer token file for HTTP mode, mode 0600, 64 hex chars.

REX_MCP_ORIGINS

empty

Comma-separated Origin allowlist for HTTP mode; empty allows all.

On startup it prints one probe result to stderr: the Rex server endpoint it will drive (a unix socket or a host address), the server version and session count. In stdio mode there is no HTTP host or port — if you see Rex server: not reachable, the first tool call may still autostart the local server, like plain rex does.

HTTP mode for other machines

rex-mcp --http (or just serve) serves Streamable HTTP at /mcp with bearer auth instead of stdio. On first start it generates the token file (~/.config/rex-mcp/token, mode 0600); rex-mcp token prints a fresh token for rotation. Clients authenticate with a header:

Authorization: Bearer <token>

A generic remote client config looks like:

{
  "mcpServers": {
    "rex-mcp": {
      "url": "https://<host>.<tailnet>.ts.net:8443/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}

Reaching it over Tailscale

Rex ships with its own Tailscale integration (rex server status shows the node), but the bridge is a separate process, so put it on the tailnet with tailscale serve:

rex-mcp --http &                                    # binds 127.0.0.1:8791
tailscale serve --bg --https=8443 http://127.0.0.1:8791

The remote instance then talks to https://<host>.<tailnet>.ts.net:8443/mcp with the token header — use the URL tailscale serve prints, since the node name there can differ from the one Rex's own integration shows (macOS can run two Tailscale nodes). Port 8443 keeps this clear of Rex's built-in Tailscale HTTPS, which occupies the node's default port. Traffic stays inside the tailnet: WireGuard-encrypted, invisible to the public internet.

On macOS the Tailscale CLI lives inside the app: /Applications/Tailscale.app/Contents/MacOS/Tailscale serve .... Serve targets must be on this machine (127.0.0.1), so bind the bridge to its default and let serve proxy it.

Alternatives:

  • Bind to the tailnet IP directly: rex-mcp --http --host <tailscale-ip>. No proxy, plain HTTP inside the tailnet; fine for tailnet-only clients.

  • Public internet: tailscale funnel --bg --https=8443 http://127.0.0.1:8791 exposes the URL beyond the tailnet. Only do this if a hosted client outside your tailnet needs it; the token is then the only gate.

To undo a serve rule: tailscale serve --https=8443 off.

Tasks

just drives everything; run just with no arguments to list recipes.

Recipe

What it does

just install

Install dependencies.

just test

Run the test suite, no Rex server needed.

just run

Start the server on stdio.

just serve

Start the server in HTTP mode on 127.0.0.1:8791.

just live

End-to-end probe against the real Rex server (creates and closes two blocks).

just pack

Build the npm tarball into dist/.

just link

npm link so rex-mcp is on PATH.

just publish

Publish the current version to npm.

just clean

Remove dist/.

Package and release

npm pack ships only bin/, src/, README and LICENSE (see the files field), and prepublishOnly runs the tests first.

CI (.github/workflows/ci.yml) runs the suite on push and pull requests across Ubuntu and macOS with Node 22 and 24.

Releases (.github/workflows/release.yml) run when you push a v* tag: tests, tarball, GitHub release with the tarball attached, then npm publish. Setup, once:

  1. Push the repo to GitHub and git init + commit if you have not already.

  2. Create an npm automation token and add it as the repository secret NPM_TOKEN.

  3. Cut a release: npm version patch && git push --follow-tags.

For a local release without CI: just pack, then npm publish (or just publish).

Tools

rex runs one rex command. Supply exactly one of args (an array of strings) or command (a quote-only string; no shell operators, substitution, or expansion).

Allowed verbs, with what the bridge does to them:

Verb

Notes

list, ls

List sessions.

session ls/inspect, window ls/inspect

Discovery.

block ls/inspect/types/capture/send/send-key

Inspect and drive one block.

client ls/inspect

See connected clients.

api ls/list/describe

Read the server's control API surface.

capture

Print a block's screen (text, html or vt). An explicit target is required.

send, send-key

Type into a terminal. An explicit target is required: -b BLOCK, -w WINDOW, or -s SESSION.

run

Start a command in a new block; add --wait for its exit status and --keep-open to read its output with capture afterwards.

wait

Block until a target ends. The bridge pins --for at the ceiling (default 90 s).

help

Read command syntax.

Listing and inspection calls get --json appended, so output is stable to parse. Failure envelopes carry a code, a message, and recovery advice in next. Rex's exit statuses map as: 2 invalid arguments, 3 target not found or ambiguous, 4 server unreachable, 130 cancelled.

The bridge runs outside any Rex terminal, so there is no default session or block: scope calls explicitly. Two patterns cover most work:

# Run a command and read its output
rex run -s SESSION --wait --keep-open -- CMD   # exit status comes back; block stays open
rex capture -b BLOCK --trim                    # the command's output

# Work in an existing terminal
rex send -b BLOCK 'make test'                  # type; delivery is not completion
rex wait BLOCK --for 90s                       # exit status when the command ends

rex_skill returns the installed CLI guide verbatim. Read it once before the first rex call.

What is disabled

do (Lua), events, block stream, api call, attach, every create, layout, rename, close, and kill command, and -S server routing. The bridge drives the local Rex server only. This keeps an agent from deleting sessions, rearranging layout, or reaching other hosts through the MCP surface.

Wait semantics

Rex blocks are terminals, not agents. wait TARGET returns when the target's child process exits, with that exit status; wait --for bounds the wait and returns non-zero on timeout. There is no idle/working/done state to poll. To check on a running command, capture the block and read the screen; to wait for a command to finish, call wait again with the same target. On wait_timeout, capture first: the reply may already be on screen.

Risks

The rex tool types into your real terminals and starts real processes with the permissions of the MCP client. A malicious prompt or document can steer an agent into using that access. Terminal output may contain passwords, keys, or private work, and a capture can surface them into agent context. The allowlist reduces accidents, not intent; treat a connected agent as someone typing at your keyboard.

In HTTP mode the token is shell-equivalent access to this machine, as the user running the bridge. Keep the endpoint tailnet-only unless a hosted client forces a funnel, keep the token out of chat and screenshots, and rotate it with rex-mcp token if it leaks, then update every client.

Development

just test
just live

The tests cover argument splitting and allowlist rules, wait budgeting, exit-status mapping, the spawn runner, the token file semantics, a full MCP handshake over stdio, and a full bearer-authenticated HTTP session against a fake rex binary, so they run without a Rex server. scripts/live.mjs is the same handshake against your real Rex server; it creates two short-lived blocks and closes them at the end.

Credits

rex-mcp is inspired by herdr-mcp by Igor Warzocha, the MCP bridge for Herdr. The tool design (a passthrough CLI tool with an allowlist plus a skill tool) and parts of the bridge and HTTP code are adapted from it, under the MIT licence. rex-mcp targets Rex instead of Herdr, runs as a local stdio server by default (HTTP with a bearer token for remote machines), and waits on terminal process exits instead of agent state.

Licence

MIT © Edgardo Yoliani. Contains code adapted from herdr-mcp, MIT © Igor Warzocha; see the notice in LICENSE.

Available Tools

2 tools
rexRex CLIA

Run the rex CLI against the local Rex server. This bridge runs outside any Rex terminal, so there is no default session or block: scope every call explicitly. Discovery: list (sessions), then block ls -s SESSION or session inspect -s SESSION. Act: capture -b BLOCK reads a terminal screen; send or send-key types into a terminal and needs an explicit target (-b BLOCK, -w WINDOW or -s SESSION); run -s SESSION -- CMD starts a command in a new block, with --wait to block until it exits (its exit status becomes the call's exit status) and --keep-open to keep the block for capture afterwards; wait TARGET blocks until a block, window or session ends, capped at 90000 ms; help shows syntax; rex_skill reads the full guide. To run a command and read its output: run -s SESSION --wait --keep-open -- CMD, then capture -b BLOCK. On wait_timeout, capture the target (a reply may already be on screen) and repeat wait with the same target if the exit status is still needed; otherwise carry on and check back later. send confirms typing, not that a command finished. Supply exactly one of args (array of strings) or command (quote-only string). Disabled here: do (Lua), events, block stream, api call, attach, and create, layout, rename, close or kill commands; also -S server routing, because this bridge drives the local Rex server only.

Inputs: args, command.

rex_skillRex CLI guideA

Read the installed Rex CLI guide verbatim (about 20 KB). Read this before the first rex call; it documents commands, targets and flags for the installed Rex version.

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.4/5.0

    Scored across 2 tools

    Disambiguation4/5

    rex_skill only retrieves the installed Rex CLI guide, while rex executes scoped CLI commands against the local server; the documentation-vs-execution split is understandable. There is minor overlap because rex also exposes help subcommands and refers back to rex_skill, but the primary purposes are distinct.

    Naming Consistency3/5

    Both tools share the rex namespace, but the set does not follow a predictable verb_noun pattern: rex is a bare command name and rex_skill is a noun-like guide tool. The names are readable but not self-explanatory without descriptions.

    Tool Count3/5

    Two tools is thin for a CLI bridge, but one is an omnibus executor and the other provides necessary version-specific documentation. Each earns its place, though the surface is intentionally narrow rather than comfortably scoped.

    Completeness3/5

    The set covers discovery, inspection, capture, send/send-key, run, wait, and help, so core terminal interaction is available. However, lifecycle operations such as create, close, kill, rename, and layout are explicitly disabled, along with events/streaming, API calls, and server routing, leaving notable gaps.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      Not graded
      maintenance
      A secure and pluggable MCP server to run terminal commands on your local machine or cloud server — remotely, safely, and with LLMs or agentic clients.
      -
    • F
      license
      A
      quality
      D
      maintenance
      A lightweight MCP server that provides AI assistants with access to a system's terminal through a secure terminal tool. It enables users to execute shell commands and receive stdout, stderr, and exit codes directly within an MCP-compatible client.
      1
      -