termux-mcp-shell
Provides shell and file access on Android devices via Termux, enabling remote command execution and file manipulation on the Android platform.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@termux-mcp-shelllist files in my home directory"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
termux-mcp-shell
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 | shThe 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.pyOnly the mcp SDK is a direct Python dependency. The server otherwise uses the
Python standard library.
Related MCP server: Android MCP Server
Run and stop
Foreground:
python server.pyBackground, surviving terminal-tab closure:
mcpsh
mcpsh-stopmcpsh 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/mcpThe 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 |
|
| Bind address; set |
|
| HTTP port |
|
| Initial command-output bytes returned |
|
| In-memory command-output buffers |
|
| Maximum lines per text read |
|
| Approximate byte cap per text read |
| 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>" mcpshThe 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.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/nelvinzfx/termux-mcp-shell'
If you have feedback or need assistance with the MCP directory API, please join our Discord server