MalDroid
Local static-analysis assistant for Android malware research that manages investigation cases, exposes MCP tools via a local server, and persists evidence-backed findings without cloud dependency.
README
MalDroid
MalDroid is a local, static-analysis assistant for Android malware research. It manages
investigation cases, starts one local llama-server, exposes a profile-specific tool set through
a local Python MCP server, and persists evidence-backed findings. Investigation data is never sent
to a cloud model.
MalDroid is not an automatic APK scanner, malware sandbox, dynamic-analysis system, or arbitrary shell agent. It does not run APKs, DEX files, native libraries, scripts, ADB, Frida, or emulators.
Supported systems and profiles
V1 supports macOS and Kali Linux with Python 3.11–3.14. Profiles are available for generic,
react-native, native, flutter, unity, cordova, and cocos. Version-sensitive external
adapters remain explicit and report compatibility limitations rather than assuming support.
Installation
git clone https://github.com/yayaya142/maldroid.git
cd maldroid
./install.sh
The installer creates ~/.local/share/maldroid/venv, installs MalDroid there, and creates
~/.local/bin/maldroid. It never installs Python packages into the system interpreter. Preview
all actions with ./install.sh --dry-run. Installation uses public PyPI in isolated mode, so an
unrelated global or corporate pip configuration cannot redirect MalDroid dependencies. An
approved private mirror can be selected explicitly:
MALDROID_PIP_INDEX_URL="https://packages.example/simple" ./install.sh
The installer presents five explained steps, detects llama-server when it is already in PATH,
and shows defaults that can be accepted with Enter. Existing configuration is preserved on
reinstallation.
After installation, enable native shell completion and inspect the command map:
maldroid --install-completion
maldroid --version
maldroid --help
maldroid help mcp serve
The first-use setup requests the local llama-server and GGUF paths. The supplied macOS default
model is:
~/Desktop/Tools/Ai Models/gemma-4-12B-it-qat-q4_0.gguf
Validate model tool calling before research use:
maldroid doctor --show-command
maldroid doctor --model-tool-test
The built-in chat supplies its system prompt automatically. SYSTEM_PROMPT.md
contains the same short prompt in a ready-to-paste form for direct llama.cpp or external MCP client
sessions.
Daily use
maldroid
maldroid new CASE_NAME
maldroid /path/to/investigation
maldroid /path/to/index.android.bundle --profile react-native
maldroid /path/to/artifact --copy
maldroid /path/to/artifact --mcp-port 8765
maldroid resume
maldroid cases
Opening an existing directory creates only .maldroid/ initially. Opening a file creates a
managed case and registers a symlink by default. No analysis starts merely because an artifact is
detected.
The terminal workspace provides persistent input history, slash-command and profile completion,
multiline input, rendered Markdown, live model/tool activity, elapsed time, and a bottom status bar
with estimated context remaining, findings, TODOs, notes, and the active profile. Use Enter to send,
Alt+Enter for a newline, Tab to complete, arrow keys for history, Ctrl+L to redraw, and Ctrl+D to
exit. /help is the complete command index; /context, /checkpoints, /history, /mcp, and
/shortcuts expose the most useful live views. Reasoning defaults to medium; /reasoning shows
all levels and /reasoning high changes the budget immediately without restarting llama-server.
Long investigations run through an autonomous phase controller. Every configured tool-round window creates a durable checkpoint and continues the same objective without returning to the prompt or throwing away usable context. Compaction is independent and runs only when the actual context ratio crosses its configured threshold. Phases are unlimited, with three automatic retries for transient model-server failures. During streaming generation, the active status line shows elapsed time, generated tokens, context consumption, and estimated tokens remaining.
Profile selection is automatic by default. MalDroid recursively inspects bounded artifact names,
archive entries, ELF magic, and small content samples, then activates React Native, Flutter, Unity,
Cordova, Cocos, Native, or Generic tools with evidence-backed confidence. Mixed apps use scored
framework indicators so incidental native libraries do not override a stronger framework match.
For ambiguous artifacts, the model can call MalDroid_detect_profile and make a validated
MalDroid_select_profile recommendation after inspecting concrete evidence. /profile NAME is a
manual session override; /profile auto restores adaptation.
MalDroid does not rely on the local model to remember progress voluntarily. It directs the model to create and complete TODOs, turn supported facts and labeled hypotheses into evidence-backed Findings, and save meaningful phase notes. Before accepting a final answer it requires a fresh note after the latest evidence work. If the model ignores that instruction, the automatic checkpoint records the objective, bounded tool inputs/results, structured case state, synthesis, and next action—not merely tool names. Context is compacted automatically at 72% usage by default, with durable case state used as a fallback if model summarization fails.
MCP tools
Every normal interactive run starts a loopback-only MCP Streamable HTTP server and prints its exact endpoint and selected port. The model-side tool executor connects to this endpoint through the official MCP client; it does not bypass MCP. To expose a case without starting the model chat:
maldroid mcp serve /path/to/case
maldroid mcp serve /path/to/case --port 8765
maldroid mcp serve /path/to/case --json
Connect an MCP client to the printed URL, normally http://127.0.0.1:8765/mcp. A typical client
entry is:
{
"mcpServers": {
"maldroid": {
"type": "http",
"url": "http://127.0.0.1:8765/mcp"
}
}
}
The normal maldroid command starts this MCP server in the background inside the same Python
process; a second terminal is not required. The endpoint uses modern MCP Streamable HTTP, so its
path is /mcp, not the legacy SSE path /sse. MalDroid permits browser requests only from the
active loopback llama.cpp WebUI port and includes the required CORS response headers. The WebUI may
connect directly or through its per-connection Use llama-server proxy option.
Every managed tool name starts with MalDroid_, for example MalDroid_read_case_state and
MalDroid_search_text. This keeps MalDroid tools recognizable when the WebUI connects several MCP
servers at once.
Additional MCP servers
MalDroid can attach additional local MCP servers directly to its CLI agent. Paste the URL and, optionally, give it a short nickname:
maldroid mcp add http://127.0.0.1:8080/mcp --name ghidra
maldroid mcp add http://localhost:9000/sse --name legacy
maldroid mcp list
maldroid mcp test ghidra
maldroid mcp history
maldroid mcp remove ghidra
The /mcp suffix selects Streamable HTTP and /sse selects legacy SSE automatically. Without
--name, MalDroid uses local-PORT. Discovered tools are namespaced as
MCP_<nickname>_<tool-name>, added to the model on the next MalDroid session, shown by /tools and
/mcp, and recorded in normal case tool history. An unavailable saved server produces a warning
and is retried on the next run without blocking the investigation.
Connectors and their add/remove/test/connection history live in
~/.config/maldroid/mcp-servers.json and mcp-servers-history.jsonl. A normal reinstall or
uninstall preserves them. uninstall.sh removes them only when the user explicitly approves the
configuration-removal prompt. URLs are restricted to loopback, cannot embed credentials or query
tokens, and may use only HTTP(S). External MCP servers have their own permissions and are not
restricted by MalDroid's case path policy; only their invocation status and returned-output limit
are enforced by MalDroid.
The MCP port is fixed. Its default is 8765, and MalDroid fails clearly if it is occupied rather
than silently changing the endpoint. Set another persistent fixed port once with
maldroid config set mcp.preferred_port PORT; --port on mcp serve and --mcp-port on normal
chat are one-run overrides. Tool discovery always returns only core
tools plus the case's active profile. The endpoint is intentionally not exposed beyond loopback;
any local client connected to it can invoke case-scoped tools until the server stops.
Configuration
Configuration is stored at ~/.config/maldroid/config.toml:
maldroid config init
maldroid config show
maldroid config show --json
maldroid config get mcp.preferred_port
maldroid config set llama.temperature 0.1
maldroid config set llama.reasoning_level high
maldroid config set llama.api_key_enabled true
maldroid config set limits.auto_compact_ratio 0.72
maldroid config validate
maldroid config reset llama.temperature --yes
maldroid config path
config show groups every effective value by section, marks it as default or custom, and explains
its purpose. Setters validate the complete configuration before performing an atomic save. Generate
a ready-to-paste connector definition with maldroid mcp client-config.
CLI options override configuration for one run. The preferred model port is 7575 and may fall back when configured as a default. The MCP port is fixed at 8765 by default and never falls back.
The loopback llama.cpp API does not require an API key by default, which keeps direct local UIs and
clients simple. Enable llama.api_key_enabled only when local model API authentication is needed;
MalDroid then creates a new random key on every server start. /status and /server show the key
for the active process. Treat it as a secret. The model host remains loopback-only.
The llama.cpp WebUI, experimental MCP proxy, and --tools all are enabled by default for the local
owner-controlled workflow. WebUI built-in tools include shell execution and unrestricted host file
access; they are not case-scoped or audited by MalDroid. The separate MalDroid MCP tools at
http://127.0.0.1:8765/mcp retain profile, path, output, and audit enforcement. Both servers remain
loopback-only, and --agent stays forbidden.
Evidence, findings, and large files
Evidence is registered by symlink or copy and is never overwritten. The assistant reads bounded
line ranges, uses exact or regex search, and stores oversized results under tool-output/. The
large-text index stores chunk boundaries and a contentless FTS5 token index; it does not store a
second readable copy of the source.
Findings, TODOs, notes, session events, and summaries survive exit and resume. Every code-based finding should identify the case path, line or offset range, tool, and confidence.
Knowledge
maldroid knowledge add ./playbook.md --profile react-native --copy
maldroid knowledge list
maldroid knowledge reindex
Built-in, user, and case playbooks are indexed locally with SQLite FTS5. Only bounded matching excerpts enter model context.
Troubleshooting
llama-server was not found: runmaldroid config initand provide its absolute path.- Model missing: update
llama.model; paths with spaces are supported. - Tool call returned as prose: run
maldroid doctor --model-tool-testand configure a compatible Jinja chat template. - Server startup failure: inspect
<case>/.maldroid/logs/llama-server.stderr.log. - MCP port unavailable: stop the process already using it, or persist another fixed value with
maldroid config set mcp.preferred_port PORTand update the MCP client once. - WebUI MCP
Failed to fetch: use the exact URLhttp://127.0.0.1:8765/mcp, confirm the normal MalDroid session is still open, and reinstall or upgrade MalDroid if the browser-origin fix is not present./sseis only for legacy MCP servers. - Python venv unavailable on Kali: install
python3-fullandpython3-venv.
Use --debug only when a traceback is needed. Closing the terminal, pressing Ctrl-C, sending
SIGTERM, or using /exit shuts down the MCP listener and the entire managed llama-server process
group. A forceful kill -9 cannot be handled by any application. Uninstall safely with
./uninstall.sh; cases and user knowledge are retained by default.
Distribution
Maintainers can run the complete local release gate and build an installable wheel without manually activating Python:
./scripts/dev release-check
./scripts/dev build
The wheel is written under dist/ and can be installed into any supported isolated environment
with python3 -m pip install /path/to/maldroid-0.1.0-py3-none-any.whl. See
docs/CLI.md for the command and automation-output reference.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。