Skip to main content
Glama
chushiyu111-design

sully-termux-mcp

README.md
# sully-termux-mcp

`sully-termux-mcp` is a Node.js 20+ TypeScript ESM gateway for running MCP tools in Termux. The production default is deliberately small: it listens on a loopback address only, requires a 32-byte Bearer token, and exposes a separate authenticated admin API.

## Quick start

```sh
npm ci
npm run build
node dist/cli.js setup
node dist/cli.js start
node dist/cli.js status
node dist/cli.js pair                 # explicit user action; prints both tokens
```

The generated configuration is `~/.config/sully-mcp/config.json` with mode `0600`; data, job output, and the redacted audit log are under `~/.local/share/sully-mcp` with mode `0700`. Never paste pairing JSON into a log or issue.

For phone controls, install the Termux:API command package (`pkg install termux-api`) and install the Termux:API companion Android app from the same signing source (for example, both from F-Droid, or both from GitHub). Android will not deliver API calls when the two packages come from different signing sources. Restart the gateway after installing or updating Termux:API so its command inventory is rebuilt.

The MCP endpoint is `http://127.0.0.1:8765/mcp`. This release supports the stable 2025-11-25 and 2025-06-18 session-based protocols using `initialize`, `notifications/initialized`, `tools/list`, and `tools/call`. The 2026-07-28 transport is intentionally not advertised until its required routing headers and response envelope are implemented. `DELETE /mcp` closes a 2025 session.

## Administration

`POST /admin/v1` uses the *admin* Bearer token and accepts `{ "action": "status", "params": {} }`. Actions include `status`, `doctor`, `permissions`, `capabilities`, `jobs.list`, `jobs.output`, `jobs.cancel`, `jobs.cleanup`, `profiles.list`, `profiles.upsert`, `profiles.remove`, `upstreams.list`, `upstreams.import`, `upstreams.update`, `upstreams.remove`, `gateway.stop`, `tokens.rotate`, and `pair.revoke`. All responses have `{ok:true,result}` or `{ok:false,error}`. Secrets are only returned for an explicit `tokens.rotate` response or the explicit `pair` CLI command.

`permissions` and `doctor` include a centralized Termux:API checklist grouped by device, communication, media, interaction, and automation. Command availability is detected at startup; Android runtime permission state is reported as `unknown`, and the same-signature-source requirement for Termux:API is explicit.

## Tools and limits

Built-ins include bounded `echo_safe`, `fs_read`, `fs_write`, `fs_list`, `fs_metadata`, `fs_find`, `fs_copy`, `fs_move`, command profiles, shell jobs, job status/output/cancel/cleanup, and detected Termux:API commands (including typed location, camera, notification, toast, clipboard, SMS, TTS, volume, and torch inputs). Less common API commands expose bounded raw `args` with a usage/help hint; consult the installed command's `--help` for exact options. `shell_exec` always spawns `bash -lc` with `shell:false`; command profiles and stdio upstreams use an executable plus argument array with `shell:false`. Jobs survive restarts as `interrupted`, capture at most 8 MiB, and return at most 64 KiB per output request. Requests are limited to 1 MiB and responses to 4 MiB; tool concurrency defaults to four.

HTTP upstreams must use HTTPS, or HTTP on the exact literal loopback host `127.0.0.1`/`::1` (no DNS aliases or whitespace). HTTPS destinations resolving to private, link-local, or metadata ranges are rejected. Redirects, URL credentials, fragments, and non-allowlisted tools are rejected. HTTP and stdio upstream tools are prefixed (`id__tool`) and can be restricted with `allowedTools`, `readOnly`, and `prefix`.

## Termux lifecycle

The normal `sully-mcp start`/`restart` lifecycle acquires `termux-wake-lock` when available and `stop` releases it. Install `termux-boot/sully-termux-mcp` as `~/.termux/boot/sully-termux-mcp` and make it executable to start after reboot. Android battery optimisation can still stop Termux; the application should treat an unavailable gateway as recoverable.

Supported CLI commands: `setup`, `start`, `stop`, `restart`, `status`, `logs`, `doctor`, `permissions`, `pair`, `update`, and `uninstall --yes`.

## Release integrity

`npm run release -- --version 0.2.0` requires `MCP_RELEASE_ED25519_PRIVATE_KEY` and runs a build before writing `sully-termux-mcp-0.2.0.tar.gz`, its SHA-256, manifest, and Ed25519 signature. The App command in `scripts/install-command.txt` downloads the fixed GitHub Release archive, hash, manifest, and signature into a temporary directory, compares the archive to its pinned expected hash, verifies the Ed25519 signature with its inline public key, and only then runs the verified archive's `scripts/install-local.sh`. The local installer checks Node 20+, runs `npm ci --omit=dev` and the build, and swaps an atomic `versions/<version>`/`current` symlink while preserving the previous current target on failure. It also creates a real `sully-mcp` wrapper in Termux's `$PREFIX/bin` (or `~/.local/bin`) and never uses an unverified `curl | sh` pipeline. The private signing key is supplied transiently through `MCP_RELEASE_ED25519_PRIVATE_KEY` by the release operator and is never committed.

## Security model

Only loopback hosts are accepted for the local listener. MCP and admin credentials are independent 64-hex random values and compared with a constant-time comparison. Configuration is written as UTF-8 with restrictive permissions. The server does not return tokens from `/health`, tool lists, normal errors, audit records, or job metadata. Audit entries are redacted and bounded. Side-effect tools are never automatically retried. Destructive upstream tools must be explicitly allowlisted by the caller.

This repository is licensed under the PolyForm Noncommercial License 1.0.0 carried over from SULLYTEST2.