nano-mcp-termux
A zero-dependency, single-file MCP server that gives AI agents read-only diagnostics about the host device, the server process, and the filesystem path environment on Termux/Android, Raspberry Pi, and Linux.
device_status— Snapshot of host hardware/OS: battery level, storage usage, CPU architecture, and memory (degraded fields marked unavailable, never raises).server_health— Self-diagnostics for the MCP server: pid/ppid, uptime, request and tool-call counters, live child processes, RSS, and Android Phantom Process Killer risk.resolve_path— Resolve and validate one filesystem path: expands~/$HOME/$PREFIX/$TMPDIR, follows symlinks, reports mount, permissions, and Android-equivalent spellings (e.g./sdcard↔/storage/emulated/0↔$HOME/storage/shared).path_adapter— Report the runtime's path environment: env class (termux/proot/android/linux), HOME/PREFIX/TMPDIR, Android storage roots, andnoexecmounts.
All four tools are read-only, idempotent, and non-destructive — the server inspects and reports, it does not modify the system.
Provides tools for interacting with the Android/Termux environment, including retrieving device status (battery, storage, architecture, memory), resolving and adapting Android filesystem paths (e.g., /sdcard, /storage/emulated/0, noexec mounts), and reporting Phantom Process Killer risk on Android 12+.
nano-mcp-termux
Zero-dependency, single-file MCP server for AI agents, natively running on Termux (Android), Raspberry Pi, and Linux.
🚀 Quick Start
Local (Termux / Linux)
cd /path/to/nano-mcp-termux
python3 nano_mcp_termux.pyDocker
docker build -t nano-mcp-termux .
docker run -i --rm nano-mcp-termuxHealth check (one-shot, no MCP handshake)
python3 nano_mcp_termux.py --healthRelated MCP server: Python MCP Toolkit Server
🔌 Connect to your MCP client
This server does not run standalone — it's a sidecar that your AI client connects to via the MCP protocol.
Below are the three most common ways to mount it.
Option 1 — Zero‑install (uvx), best for desktop AI clients
uvx nano-mcp-termuxThen add this JSON to your AI client's mcpServers config (see client‑specific notes below):
{
"mcpServers": {
"nano-mcp-termux": {
"command": "uvx",
"args": ["nano-mcp-termux"]
}
}
}Option 2 — Already pip installed, or you prefer a direct Python launch
pip install nano-mcp-termuxConfig snippet for your AI client:
{
"mcpServers": {
"nano-mcp-termux": {
"command": "nano-mcp-termux"
}
}
}Option 3 — Run the single file directly (e.g. inside Termux on Android)
# Clone or download the repo, then:
cd /path/to/nano-mcp-termux
python3 nano_mcp_termux.pyConfig snippet for your AI client:
{
"mcpServers": {
"nano-mcp-termux": {
"command": "python3",
"args": ["/full/path/to/nano_mcp_termux.py"]
}
}
}How to use these snippets: client‑specific config files
AI client | Config file location (examples) | Note |
Claude Desktop | macOS: | ∆ |
Cursor |
| ∆ |
Cline |
| ∆ |
Cherry Studio | GUI → MCP section (typically auto‑creates | JSON schema as above |
Operit |
| ∆ |
Tip: after editing the config file, restart your AI client so the new server is detected. If the client supports hot‑reload, you may not need a restart.
Troubleshooting
Symptom | Likely cause | Fix |
Client shows "server not found" |
| Use absolute path ( |
|
| Use a custom shell like |
"Connection lost" / process dies immediately | No stdin from client | This server is stdio‑bound; don't run it directly like |
🛠️ Features
✅ Zero-dependency: No external packages required
✅ Single-file: All logic in one Python script
✅ Cross-platform: Works in Termux (Android), on Raspberry Pi, Linux, and inside Docker
✅ Container-ready: Dockerfile at repo root for Glama introspection
✅ Standard stdio framing: Newline-delimited JSON-RPC (official MCP transport)
✅ Version negotiation: Echoes client
protocolVersion(2024-11-05 / 2025-06-18 / 2025-11-25), falls back to highest supported✅ Graceful degradation:
device_statusnever fails; unavailable inputs are marked, not crashed✅ [lifecycle] No orphaned processes: every command runs in its own process group; timeouts kill the whole tree (
SIGTERM→SIGKILL), never just the shell✅ [lifecycle] Self-terminating: parent-process watchdog + stdin-EOF detection + optional idle timeout, so a dead client never leaves a zombie server behind
✅ [lifecycle] Phantom Process Killer aware: reports Android 12+ child-count risk with concrete mitigations
✅ [paths] Android/Termux path adapter: resolves
/sdcard↔/storage/emulated/0↔$HOME/storage/shared, detectsnoexecmounts, case-insensitive filesystems, and shell-quoting hazards
🧩 Tools Overview
Tool | Description |
| Aggregate device info: battery / storage / arch / memory (degraded fields marked unavailable) |
| Runtime health: pid/ppid/env, uptime, request counters, live children, reaping policy, RSS, Phantom Process Killer risk |
| Resolve an Android/Termux path: canonical form, mount point, |
| Environment profile: runtime class, |
🔗 Protocol Surface
Method | Behavior |
| Echoes supported client version (2024-11-05 / 2025-06-18 / 2025-11-25), else responds with highest supported per MCP spec; declares |
| Silent (no response) |
| Returns |
| Returns tool catalog |
| Returns |
Unknown method / tool |
|
Malformed JSON |
|
🔄 Why 1.1.0: the orphan-process bug
Version 1.0.0 ran commands with subprocess.run(..., timeout=...). On timeout,
Python terminates only the direct child — the sh -c wrapper. Anything the
shell had already spawned is reparented to init and survives forever. On
Android that is the exact leak class that trips the Phantom Process Killer
and can get the whole app group killed.
1.1.0 fixes this at the root: commands are spawned with start_new_session=True
and torn down with os.killpg(pgid, SIGTERM) → SIGKILL, so the entire process
tree dies together.
The repository ships a reproducible A/B regression test for it:
python3 test_lifecycle_orphan.py
# current nano_mcp_termux.py leaked_grandchildren=0
# legacy nano_mcp_termux_v10_backup.py leaked_grandchildren=1 <- the bug
# PASS: current server leaves 0 orphaned grandchildren after timeout✅ Tests
python3 test_client.py # 32 protocol / tool / lifecycle assertions
python3 test_lifecycle_orphan.py # orphan-leak A/B regression (1.0.0 vs 1.1.0)
bash scripts/verify_glama_build.sh # Glama-build reproduction (see below)verify_glama_build.sh answers one question: will Glama's builder be able to
install and introspect this repo? It replays the same toolchain Glama uses
(uv venv && uv pip install -e ., i.e. a newer setuptools than most dev
machines have), then asserts the console entry point exists and that the server
answers initialize + tools/list over stdio. Exit codes are deliberately
three-valued so the script never lies about whose fault a failure is:
Exit | Meaning |
| Builds and introspects cleanly |
| Real problem in this repo (bad metadata, missing entry point, no tools) |
| Local environment problem (no |
The index is pinned to pypi.org on purpose — a local mirror inherited from
your shell profile can return 403 and make a healthy repo look broken. Override
with GLAMA_VERIFY_INDEX=https://your-mirror/simple only if you mean it.
Deprecation warnings about project.license are expected and non-fatal: the
SPDX form that silences them needs setuptools>=77, which requires Python 3.9+,
while this project still supports 3.8 source builds.
⚙️ Environment variables
Variable | Default | Purpose |
|
| Seconds of inactivity before the server exits on its own |
| unset | Set to |
🔗 Links
Original repository: Lmeng486/nano-mcp-termux
Verification report: awesome-termux-mcp
Measured overhead report (this server as subject under test, all numbers from a real device): MCP on Mobile: Measured Overhead Report
Dev.to article: Showdev: A zero-dependency MCP server that runs on Android Termux
Glama score verification (TDQS 4.6 / grade A, with version-metadata forensics): docs/GLAMA-SCORE.md
This server is designed to pass Glama introspection checks and serve as a lightweight MCP implementation for mobile and edge devices.
Available Tools
4 toolsdevice_statusDevice status (read-only)ARead-onlyIdempotent
Read-only snapshot of the host hardware and OS: battery level, storage usage, CPU architecture and memory. Use it when the answer depends on the physical device: free space before a download, battery before a long job, arch before picking a binary. Not for process or server state: use server_health for pid/uptime/counters of this MCP server, resolve_path to validate one path, and path_adapter for the runtime's path environment. Never raises: a field that cannot be read is reported with source unavailable. Returns {battery, storage, arch, memory}.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so safety is covered; the description adds a genuine contract beyond that: "Never raises: a field that cannot be read is reported with source unavailable." That partial-failure behavior is the key thing an agent needs, though it says nothing about freshness/caching of the snapshot or cost of the call.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the resource and its fields, then usage triggers, then exclusions, then the failure contract and return keys. Every clause carries routing or behavioral information; there is no restatement of the name or title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by naming the return shape `{battery, storage, arch, memory}` plus the degraded-value convention. Combined with the annotations and an empty input schema, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so there is nothing to disambiguate and the baseline is 4. The description correctly signals a no-argument call by framing the tool as a snapshot rather than implying any query/filter options.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("read-only snapshot of the host hardware and OS") and enumerates exactly which fields it covers: battery, storage, CPU architecture, memory. It explicitly separates itself from `server_health`, `resolve_path`, and `path_adapter`, so an agent can pick it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-use triggers tied to the agent's task ("free space before a download, battery before a long job, arch before picking a binary") and an explicit when-not clause naming all three siblings with their distinct scopes. Nothing about routing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
path_adapterPath environment adapter (read-only)ARead-onlyIdempotent
Report the runtime's path environment so you can translate host paths correctly: detected env class (termux/proot/android/linux), HOME/PREFIX/TMPDIR, each Android shared-storage root with its real mount, all noexec mounts that block in-place script execution, and runtime-specific notes. Takes no arguments. Sibling boundary: this answers the environment question (env class, HOME/PREFIX/TMPDIR, mount roots); resolve_path answers the per-path question (expansion, mount, alternatives for one path). Use path_adapter when the environment itself is unknown, resolve_path to validate a single candidate path. Returns {env, home, prefix, tmpdir, python, platform, android_roots, noexec_mounts, notes}.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (read-only, idempotent, non-destructive, closed-world), and the description adds substantial context beyond them: it says the tool takes no arguments and enumerates the reported data, including env class, HOME/PREFIX/TMPDIR, Android roots, noexec mounts, and notes. It also lists the return fields, which is valuable given there is no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action, then adds the no-argument note, sibling boundary, and return shape without filler. The density is high but every sentence serves selection or invocation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of an output schema, the description helpfully lists the returned keys and explains what environment information is reported. It is complete for a zero-parameter read-only diagnostic tool, though it could mention whether the reported environment is cached or live.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4; the description confirms "Takes no arguments," aligning with the empty schema. There are no parameter semantics beyond that, and none are needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: "Report the runtime's path environment," and immediately explains the practical purpose: translating host paths correctly. It also explicitly distinguishes itself from `resolve_path`, so an agent can identify the tool without opening sibling schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit routing rule: use `path_adapter` when the environment itself is unknown, and use `resolve_path` to validate a single candidate path. This names the alternative and the condition that selects it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_pathResolve filesystem path (read-only)ARead-onlyIdempotent
Resolve and validate one filesystem path in the runtime this server runs in: expands ~/$HOME/$PREFIX/$TMPDIR, follows symlinks, reports the mount backing the path, and lists every Android-equivalent spelling (/sdcard <-> /storage/emulated/0 <-> $HOME/storage/shared). Equivalent inputs: /sdcard/Download/x.txt, $HOME/storage/shared/Download/x.txt, ~/storage/shared/Download/x.txt, and relative docs/report.md (against cwd). Expansion: ~ and $HOME become the server's HOME; $PREFIX is the install prefix (e.g. /data/data/com.termux/files/usr); $TMPDIR is the server's own temp dir, never the client's. Useful when a path has to be handed to a shell command or another tool; not needed for paths already known-good on plain Linux. Sibling boundary: path_adapter reports the environment map itself (env class, HOME/PREFIX/TMPDIR, mount roots) and takes no arguments; resolve_path reports one concrete path. Use path_adapter for the environment, resolve_path for a candidate path. Returns {input, expanded, resolved, env, exists, is_dir, is_file, is_symlink, readable, writable, executable, mount, alternatives, warnings}.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to resolve. May be absolute or relative and may contain ~, $HOME, $PREFIX or $TMPDIR. Required and non-empty; an empty string returns an error object instead of raising. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already establish read-only, idempotent, non-destructive behavior, and the description adds substantial context beyond that: variable expansion rules, symlink following, mount detection, Android-equivalent path spellings, and the exact result fields returned. There is no contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is front-loaded and every major sentence contributes useful information. It is somewhat dense and run-on in the first sentence, but the density is justified by the number of path-expansion rules being communicated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description appropriately lists the return object fields. With only one parameter, explicit annotations, detailed expansion semantics, sibling differentiation, and return-shape disclosure, an agent has everything needed to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaningful semantics beyond the schema: concrete equivalent input forms, relative-path handling against the working directory, and the specific meanings of `~`, `$HOME`, `$PREFIX`, and `$TMPDIR`. The schema already covers required/non-empty behavior, so this is not a full 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: resolving and validating one filesystem path, including expansion, symlink following, mount reporting, and alternative spellings. It explicitly distinguishes itself from the sibling `path_adapter`, so an agent can select it without inspecting either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance: useful when a path must be handed to a shell command or another tool, and not needed for paths already known-good on plain Linux. It also draws a clear sibling boundary: `path_adapter` reports the environment map, while `resolve_path` reports one concrete path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
server_healthServer health (read-only)ARead-onlyIdempotent
Read-only self-diagnostics for this MCP server process: pid/ppid, runtime class, uptime, request and tool-call counters, tracked live child processes, RSS, and the Android Phantom Process Killer risk assessment. Use it to verify the server is alive, to debug client-side disconnects, or to check whether orphaned children are accumulating on Android. Not for the device itself: use device_status for battery, storage, arch and memory. Returns {server, children, memory, phantom_process}.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the safety profile is covered. The description adds real context beyond that: the scope is this server process rather than the device, it tracks live child processes, and it includes an Android-specific risk assessment. It stops short of saying anything about cost, frequency, or what an unhealthy result looks like, but the scope and content disclosure is solid.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the scope ("Read-only self-diagnostics for this MCP server process"), then the returned signals, then the usage boundary against `device_status`. The field enumeration is dense but each item is a distinct diagnostic the caller may need, so nothing reads as padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no parameters, the description carries the full burden of telling the agent what comes back, and it does: it names the four top-level return keys {server, children, memory, phantom_process} and the highlights of each. An agent has everything it needs to decide to call it and to interpret the response shape.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The description correctly implies no configuration is needed by framing the call as pure self-diagnostics, and it supplies no misleading parameter hints.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("read-only self-diagnostics for this MCP server process") and enumerates exactly what it reports: pid/ppid, uptime, counters, children, RSS, Phantom Process Killer risk. It explicitly distinguishes itself from the sibling `device_status`, so an agent can route correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives three concrete triggers (verify the server is alive, debug client-side disconnects, check for accumulating orphaned children on Android) and an explicit exclusion with a named alternative: "Not for the device itself: use `device_status` for battery, storage, arch and memory."
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v1.1.1- First observed
device_status - First observed
path_adapter - First observed
resolve_path - First observed
server_health
TDQS
Scored across 4 tools
Each tool targets a distinct question: device hardware (device_status), server process state (server_health), one candidate path (resolve_path), and the runtime path environment (path_adapter). Descriptions explicitly state sibling boundaries and even tell the agent which tool to use instead, eliminating misselection.
All names are snake_case and self-describing, with a clear domain term per tool. The pattern is noun_noun for three tools (device_status, server_health, path_adapter) and verb_noun for one (resolve_path), a minor deviation that is still highly readable.
Four tools is on the small side but each covers a distinct, non-overlapping diagnostic concern, so nothing feels padded or redundant. The surface is tightly scoped to introspection rather than trying to be a general shell wrapper.
The stated domain — read-only device, server, and path introspection — is well covered, including Android-specific concerns like phantom processes and shared-storage aliases. Minor gaps remain (no general process/network/log inspection), but agents can work around these via other tools or shell commands.
Maintenance
Related MCP Connectors
A simple MCP server built with FastMCP and python
MCP server for AI dialogue using various LLM models via AceDataCloud
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA simple MCP Server with shell execution capabilities that can be run locally with Ngrok tunneling or hosted in an Ubuntu 24 Docker container.4MIT
- AlicenseAqualityDmaintenanceA Python-based MCP server for file operations, web search with fallback, and task management, designed for Termux and extensible via plugins.32GPL 3.0
- AlicenseNot gradedqualityDmaintenanceUltra-lightweight MCP server for Bun with full protocol compliance. Enables building MCP servers with tools, resources, and prompts using minimal dependencies and heap footprint.46,312 npmMIT
- FlicenseNot gradedqualityCmaintenanceA Python MCP server that allows ChatGPT to execute commands on your local PC via a secure Cloudflare tunnel.-