SapperMCP
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| SAPPER_ROOT | No | Path to this checkout (locates `lib/sapper.py` for the tools). Needed when running from an installed package so the tools find `lib/`. | |
| SAPPER_MODEL | No | Agent model used for dispatch loops. | |
| SAPPER_KB_ROOT | No | Override the knowledge-base directory. | |
| SAPPER_TIMEOUT | No | Per-call timeout for dispatch loops. | |
| BENCHMARK_TOKEN | No | Arena platform token (hosted mode injects this; or use `sapper_arena init` → `.sapper/arena.json`). | |
| SAPPERMCP_DISPLAY | No | Reach the X session for desktop tools from SSH/systemd. | |
| BENCHMARK_BASE_URL | No | Arena platform base URL (hosted mode injects this; or use `sapper_arena init` → `.sapper/arena.json`). | |
| SAPPERMCP_AUTH_TOKEN | No | Bearer token for `--http` mode. Can alternatively be passed with `--auth-token`. | |
| SAPPERMCP_XAUTHORITY | No | Xauthority path to reach the X session for desktop tools from SSH/systemd. | |
| LINUXMCP_SUDO_PASSWORD | No | Enables `sudo` for privileged linuxmcp calls. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
SapperMCP merges two toolsets on one MCP server:
The sapper-v2 autonomous pentest toolkit (sapper_* tools): a fact-intent working memory (init/fact/intent/done/status/graph/recall/doc), a flag ledger, a TSecBench-style arena bridge, an offline knowledge base, agent dispatch/auto loops, tmux peer messaging, multi-challenge orchestrators (fleet/command/sweep/bench), and reporting (view/board/report). Use these for authorized security testing, app debugging, and hardening work.
The LinuxMCP system toolset: shell commands and PTY sessions, filesystem, processes, systemd services, journald, apt packages, GNOME settings, and desktop control (screenshots, windows, input, clipboard).
Results are JSON; always check "ok". Graph tools take store = path to a
.sapper/ dir (default .sapper). Long runs (auto/command/sweep/bench/dispatch):
pass background=True to get a PTY session_id, then poll read_session_output.
Privileged ops need passwordless sudo or LINUXMCP_SUDO_PASSWORD on the server.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| logging | {} |
| prompts | {
"listChanged": true
} |
| resources | {
"subscribe": false,
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| sapper_initC | Create a fact-intent graph (like |
| sapper_statusC | Project + frontier summary text (like |
| sapper_graphC | Dump the whole graph. format=json gives the structured view, format=text renders the CLI text form. |
| sapper_validateC | Integrity-check the graph; returns a list of errors (empty = valid). |
| sapper_frontierB | List open intents that are ready to work (dependencies met, confirmed). Claimed intents come first. |
| sapper_pickC | Pick the next intent to work (like |
| sapper_factC | Record a confirmed fact (like |
| sapper_intentC | Add an intent - a unit of work derived from existing facts
(like |
| sapper_hintC | Add or list human hints for the agents (like |
| sapper_showC | Show project | fact | intent as JSON. |
| sapper_docC | Read or write a node's detailed doc (title=gist, doc=detail).
|
| sapper_recallB | Find prior facts/intents similar to a free-text gist; read the top hit's doc with sapper_doc to reuse what was learned. |
| sapper_claimC | Claim an open intent for a worker. |
| sapper_releaseC | Release a claimed intent back to open. |
| sapper_doneC | Conclude an intent with the fact it produced (atomic, like
|
| sapper_completeC | Mark the project goal satisfied, justified by the given facts
(like |
| sapper_confirmC | Confirm an intent that was created with confirm=True. |
| sapper_flagC | Record a captured flag (deduped). With submit=True also sends it via the arena API and updates the fact's status (recorded -> submitted/rejected). |
| sapper_arenaA | Competition platform bridge (TSecBench-style API). Actions:
init write .sapper/arena.json config template
challenges list all challenges
start start challenge_id
stop close challenge_id
submit submit Config: env BENCHMARK_BASE_URL + BENCHMARK_TOKEN, or .sapper/arena.json. |
| sapper_kbB | Shared offline knowledge base (like Actions: add target=title; description/detail/tags/commands/source opts search target=query (first tag filters; limit applies) show target=kb id (e.g. kb001) -> full entry list browse entries (tags filter) import target=.md file or dir -> one entry per file root print the kb root dir |
| sapper_dispatchC | Run one commander/executor step via the agent CLI
(like |
| sapper_autoC | Drive a graph toward its goal autonomously: reason -> explore ->
optional verify, looping until max-steps, the goal, or the deadline
(like |
| sapper_brainstorm_pickB | Pick one brainstorm option; siblings from the same batch are
concluded with a rejection fact (like |
| sapper_cliB | Run any bundled |
| sapper_setupB | Opt a project IN: create .sapper/ + register Claude Code hooks in
<project_dir>/.claude/settings.json (like |
| sapper_teardownB | Remove sapper hooks + its AGENTS.md from a project. purge=True also deletes the .sapper/ graph data (destructive). |
| sapper_peersC | Discover tmux panes and manage user-authorized AI peers
(like |
| sapper_sendC | Send a message to a user-authorized tmux peer via load-buffer/
paste-buffer (like |
| sapper_captureC | Capture recent output from an authorized tmux peer
(like |
| sapper_fleetB | Manage the tmux worker fleet (like action: init | up | down | status | hire | fire | workers hire/fire take target=; hire also minutes/max_steps/ extra_args. |
| sapper_commandC | Field commander loop: LLM allocates the next work slice across
per-challenge graphs under |
| sapper_sweepB | Round-robin driver: every challenge graph under |
| sapper_benchB | TSecBench end-to-end driver: list -> start -> solve -> submit ->
close per challenge (like |
| sapper_viewB | Render the interactive HTML graph visualization (like
|
| sapper_boardB | One-line status per challenge graph under |
| sapper_reportB | Generate a markdown engagement report from the graph: summary,
flag ledger, typed findings (hosts/services/creds/vulns/loot), work
log, timeline, hints. Writes |
| run_commandC | Run a shell command and return stdout, stderr and exit code. |
| run_argvB | Run a program with an argument list (no shell interpretation). Safer than run_command for arguments containing shell metacharacters. |
| start_shell_sessionA | Start a persistent interactive PTY session and return its id. With command=None spawns an interactive shell. With a command, runs
|
| write_to_sessionC | Write input to a PTY session's stdin. |
| read_session_outputA | Read output from a PTY session. Returns only new output since the last read unless all_output=True. |
| list_shell_sessionsB | List all active PTY sessions. |
| close_shell_sessionC | Terminate a PTY session (SIGTERM then SIGKILL). |
| list_directoryB | List directory contents with type, size, mode and mtime per entry. |
| read_file_textB | Read a text file by lines. |
| read_file_base64B | Read a (binary) file as base64. Capped at 20MB by default. |
| write_file_textB | Write text to a file. Creates parent dirs by default. |
| write_file_base64C | Write base64-decoded bytes to a file. |
| copy_pathC | Copy a file or directory tree. |
| move_pathC | Move/rename a file or directory. |
| delete_pathA | Delete a file or directory. Directories need recursive=True. Destructive: cannot be undone. Protected system paths are refused. |
| create_directoryB | Create a directory (and parents). mode is octal like '755'. |
| path_existsC | Check whether a path exists. |
| get_path_infoC | Detailed stat info: type, size, owner, permissions, times, symlink target, access flags. |
| set_permissionsC | chmod/chown a path. |
| search_filesC | Search files under a path by name glob and/or literal content. |
| list_processesB | List running processes with pid, name, cpu%, mem%, status, cmdline. |
| get_process_infoB | Detailed info for one pid: exe, cmdline, cwd, threads, memory, cpu times, open files, network connections. |
| find_processes_by_nameA | Find processes by name (substring on name/cmdline, or exact match). |
| start_processA | Start a detached background process (shell command line). For interactive processes or output capture, use start_shell_session. |
| kill_processB | Terminate a process. SIGTERM by default, escalating to SIGKILL after timeout. force=True sends SIGKILL immediately. |
| kill_processes_by_nameC | Kill all processes matching a name. Returns per-pid results. |
| send_signalC | Send a signal by name (TERM, KILL, INT, HUP, USR1, STOP, CONT, ...) to a process. |
| wait_for_processC | Block until a process exits (or timeout). |
| process_treeC | Show a process and all its descendants. |
| get_system_infoA | Overall system snapshot: OS/distro, kernel, uptime, CPU model and load, memory, swap, root disk, logged-in users. |
| get_cpu_usageB | CPU usage percent (samples over |
| get_memory_infoA | Memory and swap details (total/available/used/cached/buffers). |
| get_disk_usageA | Disk usage for the filesystem containing |
| list_disksB | Mounted partitions with fstype, usage and IO counters. |
| get_network_infoB | Network interfaces with IPs, state, speed, IO counters, default route and DNS servers. |
| list_listening_portsC | Listening TCP/UDP ports with owning pid and process name. |
| get_environment_variablesA | Environment variables of the linuxmcp process. mask_secrets redacts vars whose name contains KEY/TOKEN/SECRET/ PASSWORD/PWD - set False to see raw values. |
| get_hardware_infoB | Hardware details via lscpu, lsusb, lspci, lsblk when available. |
| list_servicesC | List systemd service units with load/active/sub state. |
| get_service_statusB | Detailed unit status: ActiveState/SubState, MainPID, memory, enablement, plus last status output lines. |
| manage_serviceC | Control a systemd unit. |
| get_service_logsC | Journal logs for one unit. |
| read_journalC | Query the systemd journal (journalctl). |
| read_log_fileB | Read a log file. tail=True returns the last |
| list_log_filesC | List log files under /var/log (or another dir), newest first. |
| package_searchB | Search available packages by name (apt-cache search). |
| package_infoB | Package details: version, dependencies, description, install status, candidate version (apt-cache show/policy). |
| package_list_installedB | List installed packages (dpkg). filter = name substring. |
| package_installB | Install packages via apt-get install -y (sudo). |
| package_removeA | Remove packages (apt-get remove -y). purge=True also removes config files. |
| package_updateC | Refresh package lists (apt-get update, sudo). |
| package_upgradeB | Upgrade installed packages (apt-get upgrade -y, sudo). full=True runs dist-upgrade. Potentially long-running. |
| package_filesC | List files owned by an installed package (dpkg -L). |
| package_ownerB | Which package owns a file (dpkg -S). |
| gsettings_getB | Read a gsettings value, e.g. schema org.gnome.desktop.interface, key gtk-theme. |
| gsettings_setB | Write a gsettings value. value uses GVariant syntax: true/false, 42, 'quoted-string', ['a','b']. |
| gsettings_resetC | Reset a gsettings key to its default. |
| gsettings_list_schemasA | List installed gsettings schemas, optionally substring-filtered (e.g. 'gnome', 'zora', 'desktop'). |
| gsettings_list_keysC | List keys in a gsettings schema. |
| gsettings_describeB | Describe a gsettings key and its allowed range/values. |
| dconf_readC | Read a dconf key, e.g. /org/gnome/desktop/interface/gtk-theme. |
| dconf_writeC | Write a dconf key (GVariant syntax value). |
| dconf_listB | List keys/subdirs under a dconf path (must end with '/'). |
| get_desktop_statusA | Desktop session diagnostics: X11 vs Wayland vs headless, which helper tools are installed (xdotool/wmctrl/xclip/...), and what capabilities are available. Call this first if desktop tools fail. |
| capture_screenA | Capture the whole screen; returns a PNG image. |
| capture_screen_regionB | Capture a screen region (x,y top-left, width/height px); returns a PNG image. |
| capture_screen_to_fileA | Save a screenshot to a PNG file. Region optional (all four of x/y/width/height required to be used). |
| get_screen_dimensionsB | Screen pixel dimensions and per-monitor geometry. |
| list_windowsA | List all windows: id, desktop, pid, geometry, wm_class, title. X11 only (wmctrl). |
| get_active_windowA | The currently focused window (id, title, geometry). X11 only. |
| focus_windowB | Raise and focus a window by id (0x...) or title substring. |
| close_windowC | Close a window gracefully by id or title substring. |
| move_windowC | Move/resize a window by id or title substring. |
| maximize_windowB | Maximize a window by id or title substring. |
| minimize_windowC | Minimize (iconify) a window by id or title substring. |
| restore_windowB | Unmaximize/restore a window to normal state. |
| fullscreen_windowC | Toggle fullscreen state of a window. |
| find_windows_by_titleB | Find windows whose title contains the substring (case-insensitive). |
| find_windows_by_processB | Find windows owned by a pid or process-name substring. |
| type_textB | Type text as keyboard input (xdotool/wtype). Focus the target window first if needed. |
| press_keyB | Press a key or combo (xdotool names: Return, Tab, Escape, F5, 'ctrl+c', 'alt+F4'). See key_reference for valid names. |
| send_key_comboB | Send a key combination like 'ctrl+alt+t' or 'alt+F4'. |
| key_referenceA | List valid key names and combo examples for press_key. |
| move_mouseA | Move the mouse pointer to absolute screen coordinates. |
| get_mouse_positionA | Current mouse position (X11 only). |
| clickB | Click a mouse button, optionally at coordinates (moves first). button: left | middle | right |
| double_clickC | Double-click, optionally at coordinates. |
| drag_mouseB | Drag with a button held from (x1,y1) to (x2,y2). X11 only. |
| scroll_mouseB | Scroll the mouse wheel up/down, optionally at coordinates. X11 only. |
| get_clipboardA | Read clipboard text (wl-paste/xclip/xsel). |
| set_clipboardC | Write text to the clipboard. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 127 tools
While most tools map to a distinct resource/action, several clusters have genuinely unclear boundaries: the autonomous drivers (sapper_auto, sapper_command, sapper_sweep, sapper_bench, sapper_dispatch) all 'advance a graph toward the goal,' and sapper_pick vs sapper_claim vs sapper_frontier vs sapper_brainstorm_pick overlap on selection. Duplicated pairs like press_key/send_key_combo and list_windows/find_windows_by_title/find_windows_by_process, plus the all-encompassing sapper_cli and run_command vs run_argv, force an agent to reason about escaping/indirection before choosing.
Everything is snake_case and the sapper_/package_/gsettings_ prefixes group families sensibly, but conventions within families are mixed: some tools are verb_noun (get_process_info, list_windows, capture_screen), others are noun-only or bare verbs (click, double_click, sapper_status, sapper_board, sapper_report, package_info), and vague verbs like manage_service and sapper_handle-style catch-alls break the predictiveness.
127 tools is far past the point where an agent can reliably select the right one, even though the surface spans several legitimately distinct domains (system/process admin, packages, desktop automation, file IO, the sapper graph, PTY sessions). The breadth partly justifies the size, but the count should be split into separate servers or collapsed behind fewer parameterized tools.
Coverage is unusually thorough: file CRUD plus metadata/permissions, full process and service lifecycle, package management, desktop input/capture/clipboard, PTY sessions, and a complete fact/intent graph lifecycle with validation, reporting, and visualization. Minor gaps remain (no graph fact/intent edit or delete, no kb entry update/delete, no append-file primitive, no image clipboard), but agents can work around them.