Skip to content
xjoker edited this page Jul 21, 2026 · 1 revision

FAQ

Why is only port 8651 exposed? What is 8650?

8651 is the Python MCP gateway — the single process any MCP client (or human) is meant to talk to. 8650 is the Java backend that wraps jadx's headless API directly; in the fused image it binds 127.0.0.1:8650 and is never EXPOSEd or published (docker/Dockerfile, docker/entrypoint.sh), so it's unreachable from outside the container even if you tried to publish it. The gateway proxies both MCP tool calls and the two file-transfer endpoints through to it over loopback. See Deployment and docs/architecture-reference.md for the full two-process shape.

Which token do I use where? (the 3-token model)

Three distinct tokens exist — see the full table in Configuration#the-three-token-model:

  1. DELAMAIN_AUTH_TOKENS (plural) — the MCP client whitelist. This is the one you actually hand to your AI/MCP client's Authorization: Bearer header. Required, no default; any value in the comma/newline list grants identical full access.
  2. DELAMAIN_AUTH_TOKEN (singular) — the gateway↔Java internal token, only relevant if you run the two processes separately yourself (bare-metal).
  3. JADX_INTERNAL_TOKEN — the fused-container equivalent of #2; auto-generated by entrypoint.sh if you don't set it, and never exposed to clients.

If you're deploying via Compose or docker run, you almost always only need to set #1.

How do I load a large APK that won't fit conveniently in the mounted directory?

Two ways:

  • Simplest: copy/symlink the file into whatever host directory is mounted at /apks (JADX_APK_DIR), then call the list_available_files_tool / load_file_tool MCP tools with a path relative to /apks.
  • Out-of-band upload (preferred for very large files or when you can't touch the host filesystem): call the create_transfer_token MCP tool to get a one-time token + upload_url, then stream the bytes directly to the gateway with the delamain-cli companion CLI (resumable, chunked, SHA-256 verified) or a single curl -T. The file's bytes never pass through the AI's context window. Full flow in docs/file-upload.md and Development-and-Integration. Once the upload reports consumed: true, call load_file with the returned path.

How do I check it's healthy?

curl -s http://127.0.0.1:8651/health
# → {"status":"healthy","version":"…","jadx_version":"1.5.6"}

That's the same check the Compose healthcheck: block runs every 30s. There's no separate host-visible health endpoint for the Java backend in the fused deployment — its /health is only reachable at 127.0.0.1:8650 from inside the container, which the gateway itself waits on during startup before it starts serving.

What inputs are supported?

Anything jadx itself accepts:

  • Android distribution formats (first-class, tested): .apk, .apks, .xapk, .apkm, .aab
  • Other JVM bytecode formats: .jar, .dex, .aar, .class, .zip

The decompile/search/xref core works on any of these, but the higher-level Android-specific tooling (manifest inspection, resource extraction, Frida hook generation, attack-surface/security scan) targets Android/APK specifically; plain JVM inputs like a bare .jar decompile fine but aren't the current testing focus. The same extension allowlist gates both load_file and the out-of-band upload endpoint (MultiFileLoader.VALID_EXTENSIONS).

How much RAM does it need? How does it handle huge APKs?

There's no single fixed number — it scales with the index-stack design rather than a hard RAM floor. The key mechanism: decompiled source, the usage graph, and the code-search index are backed by an mmap'd, read-only, on-disk shard layer (index.shard.shard.N files + .shardcat catalog) that does not consume JVM heap. On a constrained-heap host, a purely in-memory trigram index gets skipped under memory pressure (code search permanently degraded); the mmap shard index keeps code search fully covered on the same host because it's backed by the OS page cache, not the JVM heap.

For a very large APK on a low-spec target machine, you can also front-load the cost: build the full index once on a large-heap machine, then ship the resulting --index-dir to the low-spec host for a second-scale FAST_RESTORE instead of paying for the full Phase-1 decompile + index build there. See Deployment ("Prebaked index volume") and docs/prebaked-index.md.

Which jadx version is bundled? How do I bump it?

The Dockerfile pins a specific jadx release (ARG JADX_VERSION, currently 1.5.6, with a matching JADX_ZIP_SHA256 checksum) and installs jadx-all into the build's local Maven repo, since jadx-all isn't published to Maven Central. To upgrade, run:

scripts/bump-jadx.sh 1.5.7

This downloads the release zip, computes its SHA-256, installs it into the local m2 repo, and updates the version references in pom.xml/Dockerfile/docs. It intentionally does not commit anything and does not run mvn test — verify compatibility and commit manually after bumping.

Is delamain multi-user or multi-instance?

No — it's explicitly single-user, single-instance, multi-equal-token. The gateway proxies to exactly one fixed Java backend (InstanceRegistry.configure()), holds singleton in-memory state (one registry, one shared httpx.AsyncClient, one busy-tracker table), and must run with a single uvicorn worker — never workers=N or a multi-process manager, or that state silently forks into inconsistent copies. Any token in DELAMAIN_AUTH_TOKENS grants identical full access; there is no per-token identity, role, or isolation between callers. The instance_id parameter accepted by many MCP tools is a vestigial call-site-compatibility artifact and is ignored — it does not select among multiple backends, because there is exactly one.

See also: Configuration for the full env/TOML reference, Development-and-Integration for how a client actually connects.