Termux Shell
FreeNot checkedGives an agent full shell access on Termux with file read/write/edit capabilities.
About
Gives an agent full shell access on Termux with file read/write/edit capabilities.
README
Streamable HTTP MCP server that gives an agent shell and file access inside Termux.
Install
One-liner
curl -fsSL https://raw.githubusercontent.com/nelvinzfx/termux-mcp-shell/master/install.sh | sh
The installer installs Python, Git, and Termux's native Rust build toolchain,
clones or updates the repository at ~/termux-mcp-shell, installs Python
dependencies, creates mcpsh and mcpsh-stop, and adds the repository's bin
directory to detected Bash, Zsh, or Fish configuration. Rust is required because
PyPI does not provide Android wheels for pydantic-core; the installer prepares
maturin and disables build isolation so pip uses Termux's Rust instead of the
unsupported rustup Android target. It is safe to rerun.
Use another destination or repository with:
MCP_DEST=$HOME/mcp MCP_REPO_URL=https://github.com/example/fork \
sh -c 'curl -fsSL https://raw.githubusercontent.com/nelvinzfx/termux-mcp-shell/master/install.sh | sh'
Manual
pkg install python python-pip git rust make pkg-config patchelf
python -m pip install --upgrade "setuptools>=70.1" wheel "maturin>=1.10,<2"
python -m pip install --no-build-isolation -r requirements.txt
python server.py
Only the mcp SDK is a direct Python dependency. The server otherwise uses the
Python standard library.
Run and stop
Foreground:
python server.py
Background, surviving terminal-tab closure:
mcpsh
mcpsh-stop
mcpsh writes the PID to ~/.mcpsh.pid, logs to ~/.mcpsh.log, and prints the
active endpoint and exposure status. The default MCP endpoint is:
http://127.0.0.1:8088/mcp
The server binds loopback-only 127.0.0.1:8088 by default. LAN access requires
explicit MCP_HOST=0.0.0.0; set MCP_AUTH_TOKEN whenever using a non-loopback
bind address.
Configuration
| Environment variable | Default | Purpose |
|---|---|---|
MCP_HOST |
127.0.0.1 |
Bind address; set 0.0.0.0 explicitly for LAN |
MCP_PORT |
8088 |
HTTP port |
MCP_TRUNC_LIMIT |
8192 |
Initial command-output bytes returned |
MCP_MAX_SESSIONS |
50 |
In-memory command-output buffers |
MCP_READ_MAX_LINES |
2000 |
Maximum lines per text read |
MCP_READ_MAX_BYTES |
51200 |
Approximate byte cap per text read |
MCP_AUTH_TOKEN |
unset | Optional shared Bearer/X-API-Key token |
Tools
Shell and output
run_command(command, timeout?, cwd?) runs /bin/sh -c asynchronously. Timeout
or cancellation kills the command's complete process group. Omitted cwd defaults
to $HOME; relative cwd values resolve from $HOME. Large stdout/stderr responses
include a session_id and continuation offsets for
read_output(session_id, stream, offset, length).
Reading files
read_file(path, offset=1, limit=null, line_numbers=true) returns paginated
UTF-8 text plus the exact file SHA-256. Line-number prefixes are display-only and
must not be copied into match_text; set line_numbers=false when copying exact
source. read_files(reads) batches up to 20 objects shaped as {path, offset, limit, line_numbers} with the same semantics.
read_file_bytes(path, offset=0, length=4096) returns Base64 for binary or
minified data.
Filesystem work runs in worker threads, so slow storage does not block unrelated MCP requests.
Relative file-tool paths resolve from $HOME, independent of server launch cwd,
and ~ and absolute paths remain supported. Android does not provide /tmp.
File-tool paths under /tmp and a run_command cwd under /tmp are mapped to
Termux's writable $TMPDIR.
Responses return the actual mapped path so later shell commands can reuse it.
Literal /tmp/... text inside run_command.command is deliberately not
rewritten; use the returned path or $TMPDIR/... there.
Writing files
write_file(path, content, expected_sha256=null, create_only=false) atomically
creates or replaces one UTF-8 file and its parent directories. expected_sha256
requires an existing file with that exact current hash; create_only=true requires
a missing target. The two guards cannot be combined. append_file(path, content, expected_sha256=null) atomically appends and can reject a stale current file. All
writes return the resulting SHA-256.
Editing files
edit_file(path, edits, dry_run=false, expected_sha256=null) edits one existing
UTF-8 file. edit_files(files, dry_run=false) applies the same operation atomically
across multiple existing UTF-8 files; each file item is {path, edits, expected_sha256?}. These tools never create files; use write_file to create or
replace one. Inputs are native arrays. Each edit has one canonical shape:
{
"mode": "replace_match | insert_before | insert_after",
"match_text": "unique text or anchor",
"write_text": "literal replacement or insertion"
}
Example transaction:
{
"files": [
{
"path": "src/A.kt",
"expected_sha256": "hash-from-read_file",
"edits": [
{
"mode": "replace_match",
"match_text": "val enabled = false",
"write_text": "val enabled = true"
}
]
},
{
"path": "src/B.kt",
"edits": [
{
"mode": "insert_after",
"match_text": "fun stop() {}",
"write_text": "\nfun reset() {}"
}
]
}
],
"dry_run": true
}
Compatibility input also accepts matchText/writeText and mode aliases
insert_before_match/insert_after_match. Schemas, documentation examples, and
results remain canonical snake_case. old_text/new_text and camel-case variants
remain unsupported. Insertions are literal and never add a newline automatically.
Every match must resolve uniquely. Matching supports normalized Unicode,
trailing-whitespace tolerance, and indentation-insensitive blocks. Fuzzy matching
only locates the original source span; unmatched text is never normalized or
rewritten. Overlapping edits and multiple operations at the same source position
are rejected before writing. The server validates every file before writing
anything, preserves UTF-8 BOM, line endings, and permission modes, always returns
diffs, and attempts rollback if publishing one file fails. dry_run previews
without writes. The recommended guarded flow is read_file(line_numbers=false)
then use its SHA-256 for dry_run, then apply the same payload and hash. Re-read and
rebuild the payload after any stale-source error.
Authentication
The unauthenticated default is reachable only over loopback. Anyone who can reach a non-loopback bind can execute commands and read or modify files. LAN exposure is explicit and should always use a strong token:
MCP_HOST=0.0.0.0 MCP_AUTH_TOKEN="<strong-random-token>" mcpsh
The server does not generate or persist secrets.
Clients may send either:
Authorization: Bearer <token>
or:
X-API-Key: <token>
Authentication uses one shared token. There is no TLS, per-client identity, or rate limiting. For exposure outside loopback or a trusted private network, place the server behind TLS and stronger access controls.
Installing Termux Shell
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/nelvinzfx/termux-mcp-shellFAQ
Is Termux Shell MCP free?
Yes, Termux Shell MCP is free — one-click install via Unyly at no cost.
Does Termux Shell need an API key?
No, Termux Shell runs without API keys or environment variables.
Is Termux Shell hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Termux Shell in Claude Desktop, Claude Code or Cursor?
Open Termux Shell on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
Fetch
Web content fetching and conversion for efficient LLM usage.
AWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
by modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
by xuzexin-hzCompare Termux Shell with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All ai MCPs
