| name | mcpwn |
| description | Operate the MCPwn Kali/Debian MCP efficiently: manage sessions, discover catalog tools, choose synchronous, detached, or interactive execution, move files through workspace/CAS planes, establish tunnels and shells, and run GDB or Frida debugging in the MCPwn runtime or through explicit host/device transports. Use for MCPwn or Kali MCP work, pwn/CTF and dynamic-analysis sessions, remote targets, connectivity or file-transfer problems, and optional NeuroMatrix-backed emulation/debugging through MCPwn's emulation domain. |
MCPwn Operator
MCPwn is a Linux-container-backed MCP server (Kali or Debian base — the MCP/catalog contract is the same, while installed runtime tools differ and genuinely heavy tools remain Kali-only): a non-root runtime user with sudo NOPASSWD:ALL, ~200 security tools behind a catalog, a container workspace, a CAS artifact plane (:5001), tunnels, and reverse-shell handling. Prefix root-only operations with sudo. Use the right execution path, discover tools instead of guessing, and move files with the correct mechanism; wrong choices cause timeouts, lost output, orphaned processes, and wasted turns.
Network sharing is host-OS-dependent: only a Linux host shares its network with the container (network_mode: host) — local listeners and the host's tun0 are directly reachable. On Windows/macOS (Docker Desktop) the container is NAT'd, so a listener isn't reachable from the LAN/VPN unless you bring a VPN up inside the container (tunnel_up kind=vpn → routable tun0) or publish via a relay (reach=public). Don't assume host reachability off Linux.
Choose the debugger locus before attaching. local means the process namespace where MCPwn's API runs; in the standard Docker deployment that is the container, not the Windows/macOS host. Separate hosts require an explicit debugger server/transport, while NeuroMatrix is only needed for emulation. Keep a challenge's matching binary, loader, and libc together in the selected runtime.
The Loop
- Session first.
create_analysis_session() → keep session_id + workspace. Reuse it for the whole task. Lost it after a context reset? list_sessions() / list_interactive_sessions() to rediscover, don't spawn a duplicate.
- Discover, never guess. The infra tools are always direct — call them with no discovery: session (
create_analysis_session/list_sessions/delete_session), artifacts (request_upload/request_download/list_artifacts/analyze_artifact/import_artifact_to_workspace), jobs (list_jobs/poll_job/delete_job), workspace (write_workspace_file/read_workspace_file/patch_workspace_file), storage (storage_usage/prune_*), execution (execute_command), interactive (start_interactive_shell/send_to_shell/read_shell_output/run_in_shell/stabilize_shell/close_shell/list_interactive_sessions/signal_interactive_shell). Only DOMAIN tools (network/web/pwn/…) need discovery: list_catalog() → get_tools(domain=..., query=...) → get_tool("name") (read args) → run_tool("name", {...}). Catalog names are hidden until discovered; guessing them wastes turns — but never list_catalog to "find" an infra tool.
- Execute on the right path (see decision table below).
- Collect results; request
output_mode=auto or artifact when complete output may be large. The CAS artifact then preserves the complete streams while inline stdout/stderr remain bounded head/tail previews. /api/command defaults to inline, so read the digest, byte counts, and truncation flags instead of assuming a complete artifact exists.
- Cleanup when done:
close_shell, , . For emulation,
prove jobs/endpoints/interactive clients stopped before destruction and explicitly
delete only confirmed, unshared provider artifacts.
Debugging and optional emulation
MCPwn runs GDB and Frida without NeuroMatrix. It can also map its emulation domain onto a standalone, client-neutral NeuroMatrix server when emulation is required.
Load references/debugging-and-emulation.md before attaching to a host process, choosing GDB versus Frida, or composing MCPwn with NeuroMatrix.
NeuroMatrix compatibility boundary
list_catalog.provider_identity is authoritative. Persist it with provider_ref for
every session, artifact, workspace, job, interactive, and endpoint handle; IDs and refs
are opaque and provider-scoped.
- Keep
operation_id (the MCPwn bridge job for poll_job/delete_job) separate from
neuromatrix_job_id (the native provider job for emulation_operation/recovery).
Use the explicit native name when the compatibility alias is available.
workspace_ref is a non-path logical reference: pass it unchanged to provider tools.
Provider-private workspace/host paths never cross the boundary; guest/target paths
returned inside operational output remain caller-visible findings. On identity
mismatch, rediscover and restage instead of replaying stale handles.
- Recover lost provider jobs/artifacts with
list_jobs/list_artifacts; use
delete_artifact only for explicitly confirmed, unshared objects. Artifact PUT/GET
sends required_headers, accepts 2xx only, and disables redirects.
Execution path — pick correctly (top time-sink)
| Situation | Path |
|---|
Expected well below 20s, no stdin (whoami, cat, id, quick curl) | execute_command(cmd) |
Long one-shot, no stdin (nmap -p-, hashcat, ffuf, sqlmap, hydra, feroxbuster) | execute_command(cmd, detach=True) → poll_job(job_id, wait_seconds=20) loop |
| Catalog tool expected well below 20s | run_tool("name", {...}) |
Slow, uncertain, or long_running tool | run_tool("name", {...}, detach=True) → poll_job |
| Needs stdin/tty or live streaming (nc, ssh, gdb, REPL, penelope) | start_interactive_shell → run_in_shell/read_shell_output → close_shell |
Known-long commands are rejected synchronously on execute_command — use detach=True. Never send real scans, brute-force, cracking, or fuzzing work inline. Exact informational invocations containing only -h/--help/-V/--version remain valid inline; adding operands makes them workload commands again.
The detached contract decides what you can run at all. execute_command(cmd, detach=True) with no timeout has no deadline and stays interruptible — delete_job SIGKILLs its owned process tree and verifies the kill. It is the path for any long-running or unwrapped program. Inline is capped at 20s (clients that serialize requests stall on anything longer); MCPWN_INLINE_TIMEOUT_CAP only lowers it, to a 5s floor, and only an operator's MCPWN_ALLOW_LONG_INLINE=1 lifts it. Cleanup adds bounded time after the timeout, so detach anything near 20s or duration-uncertain. A detached catalog job reports killable=true while a local subprocess phase is active; pure-Python, remote, and between-command phases remain cooperative and may stay cancellation_pending. Its wrapper owns the deadline: inspect get_tool, poll_job, and list_jobs; use execute_command(detach=True) when arbitrary work must remain continuously hard-killable or outlive a wrapper ceiling.
Duration-uncertain catalog wrappers — especially deep decompilation or global analysis — must use detach=True, bounded poll_job intervals, and limited concurrent heavy jobs. A caller/MCP request timeout may end the wait without cancelling the backend job; inspect job and cancellation state before retrying or duplicating work. If the backend reports unhealthy/unavailable, report that state and do not restart or rebuild it without user direction. Active detached jobs expose lifecycle state, not incremental stdout/stderr; use an interactive stream or a bounded workspace progress file when early output matters. After terminal status, retrieve and persist the result or artifact before delete_job, because deletion removes the retained payload.
Interactive shells: prefer run_in_shell(id, cmd) for a discrete command. It is marker-synced — returns THAT command's output + exit_code in ONE call (autodetects posix/powershell/cmd) — so no guess-the-timing send_to_shell+read_shell_output loop and no command-echo / job-control noise bleeding into the read. Keep read_shell_output(wait_seconds=N) for streaming / TUI / a shell you must watch live; wait_seconds is server-clamped to ~20s, so loop it for longer waits rather than expecting one longer block. Full rules, sleep/backgrounding traps, and the interactive lifecycle: load references/execution-model.md.
Moving files — use the right mechanism
| Goal | Mechanism |
|---|
| Text you AUTHOR in-context (script/config/exploit) | write_workspace_file(content_text=...) — 1 call, already in context, no corruption risk; auto-creates parent dirs |
| Read/patch a workspace file | read_workspace_file / patch_workspace_file (no shell; reads are bounded and paginatable; patches are atomic) |
| A file that ALREADY EXISTS on disk (any size, binary or text) | request_upload → curl -X PUT --data-binary @f the raw bytes to the :5001 URL from your own local shell → import_artifact_to_workspace (only after the 201; skip import if a CAS ref is enough). |
| Small binary blob generated in-context, not on disk | write_workspace_file(content_base64=..., sha256=<digest>) — last resort |
| Pull a result OUT | request_download → curl the tokenized :5001 GET URL from your local shell |
| CAS artifact → mutable workspace (needed by GDB/pwntools/patch tools) | import_artifact_to_workspace |
| Inspect an artifact without transferring | analyze_artifact (preview) / list_artifacts |
| Read-only analyzers | pass the CAS ref directly: mcp://artifacts/<sha256> |
| Ship a payload TO a target host | list_payloads → get_payload → upload_to_target (smb/scp/ftp/http, PtH-aware) |
Decide by source/type, not size. NEVER base64 -w0 a file that exists on disk into write_workspace_file — it streams the bytes through model context (token cost ∝ file size) and one flipped char stays valid base64 = silent corruption (decoded bytes differ from source with no error; downstream PKI/binary consumers reject the result). The :5001 PUT has no minimum size and is SHA-addressed — default for any on-disk file. If you must send content_base64, pass sha256= (server refuses on mismatch).
Details, the pre-staged /opt/*-payloads depots, and the sub-agent CAS-handoff rule: references/files-and-artifacts.md.
Connectivity & reverse shells (bring reachability up FIRST)
A missing route fakes an all-filtered scan — establish and verify the path before enumerating.
- Route/pivot/VPN/LHOST →
get_tools(domain="network") then tunnel_up (kind = vpn/expose/proxy/forward) and tunnel_revshell (cross-OS LHOST:LPORT + ready payloads).
- VPN by artifact:
run_tool("tunnel_up", {"kind":"vpn","config_ref":"mcp://artifacts/<sha>"}) → iface=tun0 + IP.
- Catch shells with penelope (default), not raw
nc: auto PTY upgrade + on-disk transcript. penelope/pwncat are pty-only — launch them via start_interactive_shell (pexpect gives them a TTY); fired through execute_command they're now guarded (you get guard: pty_only_listener + an nc fallback_command, not a crash — treat it as a signal to relaunch interactively). After catching, stabilize_shell (shell-aware — auto-skips the Linux PTY upgrade on a Windows shell); run discrete commands with run_in_shell (returns scoped output + exit_code — no fragmented reads). Never SIGINT the listener to stop a remote job (it drops the shell).
- Windows / AD / Kerberos: a raw Windows callback has no Unix PTY — drive it with
run_in_shell (cmd/powershell autodetected), then pivot to evil-winrm for a clean PTY (creds / -H <nthash> PtH / -r <REALM> Kerberos). Kerberos needs the DC FQDN and REALM in /etc/hosts + no clock skew (krb_time_probe → faketime, impacket-getTGT → KRB5CCNAME). Full flow: references/tunnels-and-shells.md.
Tunnel kinds, cross-OS reach logic, Windows/AD shell pivots, and raw-channel survival patterns: references/tunnels-and-shells.md.
Catalog domains
16 domains for get_tools(domain=...): network, web, pwn, crypto, forensics, pcap, mobile, cloud, web3, ics, osint, llm, ml, runtime, sessions, emulation. Search is tag/alias-aware — query by intent (rdp, smb, jwt, rop, pivot, disk image, factordb, neuromatrix) not exact tool names.
Strict rules
- One session per task; discover before running; read
get_tool args before first use of any wrapper.
- Long/known-slow work →
detach=True + poll_job, or an interactive shell. Never inline.
- Caller-visible results and command metadata intentionally preserve operational findings such as recovered credentials, private keys, submitted commands, and guest/target paths. Only diagnostic logs and provider-private metadata are redacted best-effort; treat the MCP/chat transcript as sensitive.
- If a pre-existing secret must not appear in that transcript, do not embed it in an
execute_command string. Reference a mode-0600 file, use an stdin-capable interactive session, or use a credential-aware wrapper.
- Cancellation proves MCPwn's owned local process tree stopped, not that descendants launched through SSH or another remote transport stopped. Bound remote monitors target-side with
timeout -k 2s 90s <command>, then verify the remote PID is gone.
- Don't hand-read large outputs. Auto-CAS only triggers at ~64 KB, so bulky sub-64 KB dumps (a few hundred lines) still print inline and silently burn context when you loop them — the classic tax on iterative analysis of a big read-only artifact (mmap-carving a memory dump, sifting a PCAP/disk image via heredoc scripts). Fix: write results to a workspace file and
grep/head only the slice you need, or force a handoff with execute_command(..., output_mode="artifact", output_filename="..."). Extract the few lines that matter; never reprint the whole set each turn. For a long carving/sift loop, quarantine it in a sub-agent that returns a digest.
- Recursive analysis is always detached.
firmware_analyze and auto_malware_hunt scan only by default; binwalk_analyze requires a session when extracting and unblob_analyze always requires one. Preserve their unique output directories and explicit depth/file/entry/aggregate-byte controls; do not smuggle output/depth/process overrides through free-form arguments. Treat files as extractor output and analysis_logs as bounded helper diagnostics.
execute_command is sh -c (dash on a Debian base, bash on Kali) — wrap bashisms in bash -c '...' so they don't silently degrade. start_interactive_shell has no shell — use cwd= (no cd &&) or bash -lc.
- is a bind mount — append with , not .
Resources
references/
references/execution-model.md — load when a command times out, output is lost/fragmented, a process orphans, or you need the sleep/backgrounding/interactive-shell rules and the short-vs-async-vs-interactive decision in full.
references/files-and-artifacts.md — load for any non-trivial file movement: the :5001 upload/download handoff, workspace vs CAS vs import, the /opt payload depots, upload_to_target (incl. pass-the-hash), and the sub-agent handoff pattern.
references/tunnels-and-shells.md — load when establishing connectivity or catching a shell: tunnel_up kinds and params, tunnel_revshell cross-OS reach, penelope/stabilize_shell/run_in_shell, and raw nc/socat survival tradecraft.
references/debugging-and-emulation.md — load for GDB/Frida sessions, container-versus-host reachability, debugger-server transports, Frida loader-crash triage, or the optional MCPwn-to-NeuroMatrix emulation bridge.