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.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues