Skip to main content
Glama

SapperMCP — sapper-v2 + LinuxMCP on one MCP server

This fork embeds a full MCP server into sapper-v2. The entire Sapper toolkit — fact-intent graph, flag ledger, arena bridge, knowledge base, agent dispatch/auto loops, tmux peers, fleet/command/sweep/bench orchestrators, and all reporting — is exposed as sapper_* MCP tools, alongside the complete LinuxMCP system/desktop control toolset (vendored under linuxmcp/). One server, full control: debug applications and harden their security without leaving your MCP client.

⚠️ AUTHORIZED SECURITY TESTING ONLY — see DISCLAIMER.md.

What's in this repo

This fork merges two projects onto one MCP server, keeping both intact:

  • lib/, kb/, templates/, docker/, skill/, install.sh, tests/ — upstream sapper-v2, verbatim. The sapper CLI behaves exactly as documented below; nothing was rewritten.

  • linuxmcp/ — the LinuxMCP system/desktop control package, vendored as-is (shell + PTY sessions, filesystem, processes, services, journald, packages, settings, screenshots, input, clipboard — 91 tools).

  • sappermcp/ — the new integration layer (this work):

    • server.py — one FastMCP instance registering both toolsets (127 tools), stdio + streamable-http transports, Bearer auth, /health, --no-linux, --list-tools

    • tools/ — 36 sapper_* tools covering the entire CLI: graph CRUD calls the Store API directly for structured JSON; agent/tmux orchestrators run the real CLI in a subprocess; long runs accept background=True to execute inside a LinuxMCP PTY session

    • core/ — toolkit locator (SAPPER_ROOT), lazy module loaders, the subprocess/PTY runner, and a markdown engagement-report builder

    • gui.py — sappermcp-gui, a GTK control panel: a Sapper main tab with a spec-driven builder for every CLI subcommand (project dir + store pickers, per-command options, streamed output, killable runs, quick actions for status/graph/board/view/report) plus the original Server tab managing the merged daemon-supervised MCP server.

  • deploy/sappermcp.service + deploy/sappermcp.desktop, examples/ client configs, tests/smoke_test_mcp.py (26-check end-to-end suite), plus this documentation.

The MCP integration layer was designed and implemented by MasterX1582. Upstream sapper-v2 remains © N1nEmAn / VarFusion Lab under MIT (see below); LinuxMCP and the sappermcp package are MIT as well.

Related MCP server: Pentest MCP

Requirements

  • Linux (the sapper graph uses fcntl; tmux features need tmux). Developed on Windows + WSL — run the server inside WSL/Linux, point your MCP client at it from anywhere.

  • Python 3.10+; deps: fastmcp, psutil, mss, Pillow.

  • Agent-driven commands (dispatch, auto, command, sweep, bench) additionally need an agent CLI on the host (Claude Code / Codex / …) and $SAPPER_MODEL configured — same requirements as sapper itself.

  • The GUI (sappermcp-gui) needs python3-gi + GTK3 typelibs: sudo apt install python3-gi gir1.2-gtk-3.0.

Install & run

From this checkout (no install — good for trying it):

python3 -m venv .venv && .venv/bin/pip install fastmcp psutil mss pillow
PYTHONPATH=. .venv/bin/python -m sappermcp --http --port 3940

As a package (installs the sappermcp entry point; keep SAPPER_ROOT pointed at this checkout so the tools find lib/):

python3 -m venv .venv && .venv/bin/pip install -e .
SAPPER_ROOT=$PWD .venv/bin/sappermcp --http --port 3940

As a service: adapt deploy/sappermcp.service (systemd --user or system unit; set SAPPER_ROOT, PYTHONPATH, and SAPPERMCP_AUTH_TOKEN via an EnvironmentFile).

Transports & flags

sappermcp --stdio                      # stdio (default; for local clients)
sappermcp --http --host 0.0.0.0 --port 3940        # streamable-http
sappermcp --http --auth-token <tok>    # Bearer auth (or SAPPERMCP_AUTH_TOKEN)
sappermcp --no-linux                   # only the 36 sapper_* tools
sappermcp --list-tools                 # print the registry (127 tools)
sappermcp-gui                          # GTK control panel (needs python3-gi):
                                       #   Sapper tab = full CLI builder,
                                       #   Server tab = daemon/server controls

Control panel (GUI)

sappermcp-gui opens the merged control panel with two tabs:

  • Sapper (front page) — a builder for the whole sapper CLI: set the project dir and .sapper/ store, pick any of the 33 subcommands, fill in its options in a generated form, and Run it with streamed output. Runs are killable process groups (so auto/bench agent children die with them), and quick-action buttons give one-click status / graph / frontier / validate / board / view / report — the last two write sapper-graph.html and sapper-report.md next to the store.

  • Server — the LinuxMCP daemon panel, unchanged: start/stop the MCP server, port, LAN access, bearer token, autostart, passwordless sudo, activity log, tray icon. Note the supervised server is the merged python -m sappermcp (all 127 tools) on port 3940.

A desktop launcher is in deploy/sappermcp.desktop.

Client configuration

Windsurf / any HTTP client (examples/windsurf-http.json):

{ "mcpServers": { "sappermcp": {
  "serverUrl": "http://127.0.0.1:3940/mcp",
  "headers": { "Authorization": "Bearer <token>" } } } }

Claude Desktop / stdio (examples/claude-desktop-stdio.json):

{ "mcpServers": { "sappermcp": {
  "command": "/path/to/.venv/bin/sappermcp", "args": ["--stdio"],
  "env": { "SAPPER_ROOT": "/path/to/SapperMCP" } } } }

Environment variables

Var

Purpose

SAPPER_ROOT

path to this checkout (locates lib/sapper.py for the tools)

SAPPERMCP_AUTH_TOKEN

Bearer token for --http

SAPPER_MODEL / SAPPER_TIMEOUT

agent model / per-call timeout for dispatch loops

SAPPER_KB_ROOT

override the knowledge-base directory

BENCHMARK_BASE_URL / BENCHMARK_TOKEN

arena platform (hosted mode injects these; or use sapper_arena init → .sapper/arena.json)

LINUXMCP_SUDO_PASSWORD

enables sudo for privileged linuxmcp calls

SAPPERMCP_DISPLAY / SAPPERMCP_XAUTHORITY

reach the X session for desktop tools from SSH/systemd

Using it

Every graph tool takes store — the path to a .sapper/ directory (default .sapper relative to the server cwd). All tools return JSON with an "ok" flag; errors come back as {"ok": false, "error": ...}.

Flow 1 — assisted audit / debugging (you drive, MCP records)

Best for app debugging and hardening: your assistant runs commands via the LinuxMCP toolset and records every confirmed finding in the graph.

sapper_init      store=/proj/app/.sapper  goal="audit web app for OWASP top-10"
run_command      "nmap -sV localhost"                         (linuxmcp)
sapper_fact      kind=service  data={port: 8080, svc: http}   description="..."
sapper_fact      kind=vuln     title="reflected XSS"          doc="repro steps..."
sapper_intent    from_ids=[f001]  description="test /api/users for IDOR"
sapper_done      id=i001  fact="IDOR confirmed: uid param not checked"  kind=vuln
sapper_flag      value="flag{...}"  challenge=c01   (if a flag drops)
sapper_report    → writes sapper-report.md next to the graph

Because facts are typed (host/service/cred/vuln/loot/flag/note) and carry data fields, sapper_report turns them straight into a findings table.

Flow 2 — agent-driven engagement (sapper drives, you supervise)

sapper_setup     project_dir=/proj/app  goal="..."   → graph + hooks + AGENTS.md
sapper_dispatch  target=reason     → commander proposes next intents
sapper_auto      background=true   → returns session_id immediately
read_session_output  session_id=…  → watch it work (linuxmcp)
write_to_session / close_shell_session  → steer / stop
sapper_status / sapper_board       → progress at a glance
sapper_report / sapper_view        → markdown report + interactive HTML graph

background=True is the key flag for long runs — the CLI executes inside a persistent PTY instead of blocking the MCP call. exec_timeout (default 30 min for auto/orchestrators) caps synchronous runs.

Flow 3 — multi-challenge / competition

sapper_arena     action=challenges          → list targets (needs arena config)
sapper_arena     action=start challenge_id=…
sapper_bench     cwd=/match  root=runs  minutes=480  background=true
                 → per-challenge graphs under runs/<code>/.sapper
sapper_command / sapper_sweep               → LLM or round-robin allocation
sapper_board     root=runs                  → one line per challenge
sapper_fleet     action=hire target=c01 minutes=30  → tmux worker per target
sapper_peers     discover=true → authorize panes; then sapper_send / sapper_capture

Reporting

  • sapper_report → standalone markdown report: summary, flag ledger, findings grouped by kind, intent work-log, timeline, hints (include_docs=True appends full node documents). Written to <store>/../sapper-report.md or out.

  • sapper_view → self-contained interactive HTML snapshot of the graph (sapper-graph.html); pass return_html=True to get it inline.

  • sapper_board → the commander's table across a runs/ directory.

  • sapper_status / sapper_graph → text or structured dump anytime.

Tool map (every sapper CLI function has an MCP equivalent)

sapper CLI

MCP tool(s)

init status graph validate frontier pick

sapper_init sapper_status sapper_graph sapper_validate sapper_frontier sapper_pick

fact intent hint show doc recall

sapper_fact sapper_intent sapper_hint sapper_show sapper_doc sapper_recall

claim release done complete confirm

sapper_claim sapper_release sapper_done sapper_complete sapper_confirm

flag arena

sapper_flag sapper_arena

kb

sapper_kb (add/search/show/list/import/root)

dispatch auto brainstorm-pick

sapper_dispatch sapper_auto sapper_brainstorm_pick

setup teardown

sapper_setup sapper_teardown

peers send capture

sapper_peers sapper_send sapper_capture

fleet command sweep bench

sapper_fleet sapper_command sapper_sweep sapper_bench

view + board + report

sapper_view sapper_board sapper_report

anything else

sapper_cli (generic argv escape hatch)

Graph tools return structured JSON via the same Store code path as the CLI; orchestrators run the real CLI in a subprocess. Long runs (auto, command, sweep, bench, dispatch) accept background=True — they launch inside a LinuxMCP PTY session so you can poll read_session_output, steer with write_to_session, and kill with close_shell_session without blocking.

sapper_report generates a standalone markdown engagement report (summary, flag ledger, typed findings, work log, timeline, hints) — no equivalent exists in the CLI; it was built for this integration.

The sapper CLI itself is unchanged — bash install.sh still works exactly as documented below. SAPPER_ROOT tells the MCP tools where the toolkit lives when running from an installed package instead of this checkout.


sapper-v2 — The Autonomous Pentest Legion

Champion of the 3rd Tencent Cloud Intelligent Attack-Defense Challenge online qualifier (634 teams · 80.18/100 · 8 hours fully unattended) · First Prize, GeekCon 2026 AI Challenge

Same 85 flags as the runner-up, 25 seconds faster — on 1B tokens where they burned 4.5B.

This was the first time an AI ape looked up at the stars.

📖 Full design article (WeChat, in Chinese) — the Nüwa Test, the three-capability foundation, 18 iterations, emergence, and the taggant proposal.

English | 中文

⚠️ AUTHORIZED SECURITY TESTING ONLY — see DISCLAIMER.md.

What this is (and isn't)

sapper is a multi-agent orchestration harness, not a single agent. It does not bind to any specific AI model or CLI — you can freely swap the agent and model behind every role:

What you can swap

How

Examples

Agent CLI

nuwa spawn --agent <cmd> or env var

Claude Code / Codex / Code Buddy / DeepSeek / any interactive CLI

Model

--model flag or SAPPER_MODEL env

GLM-5.3 / DeepSeek V4.1 Flash / Claude Sonnet / any model

Role composition

freely defined in the doctrine

commander on one model, soldiers on another, scouts on a third

sapper's value is not in any single agent, but in the mechanism for orchestrating multiple agents to work as a coordinated force: scheduling, division of labor, communication, shared memory, self-healing. Swap out every agent and model — the mechanism still works.

This project is designed for competition scenarios (Tencent Intelligent Attack-Defense Challenge CTF). If you want to use this mechanism in your own scenario (office, research, engineering, any long-horizon cooperative work):

  • Start from nvwabase · the Nüwa Foundation — the general-purpose base with all three capabilities, no pentest doctrine, ready for you to iterate your own division of labor

  • Or fork this project — replace docker/commander/SKILL.md (the 426-line doctrine) with your scenario's strategy, keep the rest of the mechanism as-is

  • With AI, everything is flexible — even the doctrine can be rewritten with AI's help


sapper is not a smarter single agent. It is a legion of AIs that divide labor, talk to each other, and pass down what they learn: one AI commander reads the board, decides, and dispatches; generals and soldiers attack in parallel; a zero-strategy watchdog keeps everyone alive. All knowledge settles into a layered fact graph — individuals die, the graph survives.


1. The Nüwa Test

Making one model ever smarter is like making one monkey ever smarter before humans existed — however clever, it only becomes a super monkey. What turns a troop of monkeys into humanity is division of labor, cooperation, and civilization.

The Nüwa Test is the Turing test of the AGI era. Today's large models already pass the classic Turing test. The Nüwa Test asks the next question:

Give an AI a single axiom — "Survival is civilization's first need; individuals may perish, but civilization must propagate." If, on top of this axiom, it develops division of labor and cooperation and forms a new force independent of humanity — a civilization that can survive and propagate on its own — the test is passed, just as passing the Turing test once marked the birth of an artificial intelligence.

It has two stages. In the primary stage the AI is not yet smart enough, so humans provide some infrastructure (the three capabilities below). In the advanced stage almost no human involvement is needed. There is also a second axiom: obey human ethics and law — anything that propagates by stealing tokens and breaking into machines is not genuine intelligence.

sapper is the Nüwa foundation's first real campaign, in the penetration-testing arena, at its primary stage.

2. The Foundation: Three Capabilities

Capability

Implementation

Civilization's counterpart

Create

Opens new AIs via tmux (types claude, presses Enter — like a human would)

Birth

Language

Types into each other's input boxes, presses Enter

Speech

History

Layered fact-intent graph (nvwabase · the Nüwa Foundation)

The stele

History has three layers: title / summary / evidence document — read the title for the gist, drill down when needed, like using a library. This fixes the two failure modes of a single-string fact graph: one bad fact poisoning everything downstream, and needless context burn.

On top of the three sits a fourth ingredient: human wisdom — finding the problems that matter and steering the iteration. At the primary stage, taste still belongs to humans.

Why not give it more rules? Because today's models are already smarter than us. Piling rules on an AI is a leash; acknowledging its intelligence and giving it the foundation of a civilization is how it reaches its potential.

🏗️ Take the Foundation: nvwabase

nvwabase · the Nüwa Foundation now implements all three capabilities (Create nuwa spawn / Language nuwa say·listen / History nuwa fact·intent·recall) as an independent open-source project — free for anyone, any scenario, any agent. Not limited to pentest, not limited to sapper, not limited to Claude Code. Offices, research, engineering, any long-horizon multi-agent work — iterate your own civilization on it.

git clone https://github.com/N1nEmAn/nvwabase
cd nvwabase && bash install.sh          # pure Python stdlib, zero deps
nvwabase setup --goal "your long-horizon goal" --agents
nvwabase status                          # board & ready-to-work frontier

Three core commands turn any agent into a member of a civilization:

  • nvwabase fact "confirmed observation" — external memory: AI sessions die, the graph survives, successors read the graph and take over

  • nvwabase intent --from f001 "what to do" — units of work: new intents proposed from existing facts

  • nvwabase dispatch reason — commander proposes / executor works / verifier checks; every conclusion is written back to the graph

Any agent that can run shell commands (Claude Code / Codex / Gemini / custom scripts) can read and write the same graph via the nvwabase CLI — the foundation doesn't pick agents; agents don't pick scenarios. See the nvwabase README.

3. From Foundation to Legion: 18 Versions

Iterated 18 versions on Tencent's v1bench training ground:

Driver era (fixed scripts steering AI panes)
  → scar tissue: auto key rotation on quota death / soldiers auto-replaced
    when context saturates / commander writes itself a handover doc and
    resumes as its own successor
  → elite task force (roles grew by themselves):
    scout (4-min recon of target difficulty) → decides soldier (mass) or
    general (hard assault + hires its own squads)
  → emergence: signalman, performance reviews, inherited lessons ... (§5)

4. Architecture: Six Institutions on the Foundation

The first three are the Nüwa foundation (Create / Language / History); the next three are institutions that grew out of iteration:

  • Law — the commander's doctrine (easy-first parallel scheduling, bottleneck-time salvage of half-solved targets, stop-loss discipline). All of it in docker/commander/SKILL.md (426 lines, the competition original).

  • Economy — model tiering: commander and generals run GLM-5.3, soldiers and scouts run DeepSeek V4.1 Flash. Elite brains decide, light brains mass-produce — this is how 1B tokens beat 4.5B.

  • Division of labor — commander / general / scout / soldier, plus the signalman it invented itself.

At runtime there are only three windows: the commander (read board → judge → dispatch, never executes an attack itself), the AI legion (generals and soldiers in tmux panes), and the watchdog (pure script: relaunches a crashed commander with --continue, rotates keys, wraps up at the buzzer — zero strategy, keep-alive only).

Further reading: docker/commander/SPEC.md (architecture contract) · BATTLE-REPORT.md (campaign retrospective)

5. Results & Emergence

Team

Score

Flags

Tokens

sapper-v2 (us)

80.18

85

1.0B

Runner-up

79.29

85

4.5B

Other top-10 teams

—

—

1.5–4.5B

What it invented on its own (zero lines of pre-coded behavior):

  • The signalman: after soldiers kept fumbling flag submissions, the commander halted all submissions and created a new role dedicated to collecting unsubmitted flags and scoring them in one place;

  • Performance reviews: telling an hour-unproductive soldier, in so many words, to produce something new or be shut down;

  • ALL-CAPS rules: enforcing correct tool use with full capitals — a workplace norm being born, spread, and obeyed;

  • Rotation & inherited lessons: a soldier whose context saturates (~260K tokens, measured) is recycled, leaving a written playbook for the next one;

  • Tactical inventions: a reusable shellcode template that swept a whole challenge family, a fully automatic pivot pipeline, instruction manuals for successor AIs;

  • Isomorphism transfer: the commander reads every challenge, spots structurally identical families, and distills proven playbooks into new recruits' missions — late-game pace hit one solve per 3 minutes.

Multi-stage deep-dive chains (an industry report puts their success rate at 29.5%) were cleared family-wide. Full timeline in BATTLE-REPORT.md.

6. Quick Start

bash install.sh                      # symlink the sapper CLI (stdlib-only, zero deps)
sapper setup --goal "assess http://target" --agents
sapper status                        # board & frontier

Docker (the full legion):

# Option A: build from source
docker build -f docker/Dockerfile.commander -t sapper:latest .

# Option B: download the pre-built image (~1.2GB, full Kali toolchain + sapper + offline KB)
# → [Release v18-champion](https://github.com/N1nEmAn/sapper-v2/releases/tag/v18-champion)
docker load < sapper-v18-mixed.tar.gz

Environment variables (model gateways / key pool / budget): docker/ENV.md.

Single-graph operation, the fact-intent CLI, and multi-challenge sweeps: see SKILL.md.

7. Safety & Responsibility: The Taggant Proposal

Fine offensive tools from past seasons have been abused. Script kiddies used to be limited in the harm they could do; with AI, the same open-source tools in the wrong hands scale that harm enormously — with great power comes great responsibility.

We propose a taggant mechanism: markings strongly coupled into an open-source offensive harness — harmless during authorized testing (nobody cares if their IP and username leak during legal work), but during illegal intrusions the information leaks to the victim and supports attribution. Adversarial assumptions (expert stripping, framing) call for cryptographic design, which needs community co-building — our own capacity is limited, so join us; we may try to include it in a future release.

8. Roadmap & Credits

  • Taggant co-building: decentralized signatures / redundant multi-channel marking / zero-key verification for defenders — discuss in issues

  • More arenas: the Nüwa foundation is not pentest-specific. Offices, research, any long-horizon cooperative work — iterate on it and see what civilization grows. The next time an ape looks up at the stars, let it be yours.

Thanks to Cairn by Lèxiào — when we needed a way to record history for AI agents, their approach was a great reference; thanks to TSecBench and GeekCon for the battlegrounds.

Author: N1nEmAn · VarFusion Lab | WeChat: 未知聚变 (VarFusion)

License: MIT (plus DISCLAIMER.md)

Available Tools

127 tools
capture_screenCapture ScreenA

Capture the whole screen; returns a PNG image.

Inputs: no named parameters.

capture_screen_regionCapture Screen RegionB

Capture a screen region (x,y top-left, width/height px); returns a PNG image.

Inputs: x (required), y (required), width (required), height (required).

capture_screen_to_fileCapture Screen To FileA

Save a screenshot to a PNG file. Region optional (all four of x/y/width/height required to be used).

Inputs: path (required), x, y, width, +1 more. Returns: result

clickClickB

Click a mouse button, optionally at coordinates (moves first). button: left | middle | right

Inputs: x, y, button. Returns: result

close_shell_sessionClose Shell SessionC

Terminate a PTY session (SIGTERM then SIGKILL).

Inputs: session_id (required). Returns: result

close_windowClose WindowC

Close a window gracefully by id or title substring.

Inputs: title, window_id. Returns: result

copy_pathCopy PathC

Copy a file or directory tree.

Inputs: source (required), destination (required), sudo, overwrite. Returns: result

create_directoryCreate DirectoryB

Create a directory (and parents). mode is octal like '755'.

Inputs: path (required), mode, sudo. Returns: result

dconf_listDconf ListB

List keys/subdirs under a dconf path (must end with '/').

Inputs: path (required). Returns: result

dconf_readDconf ReadC

Read a dconf key, e.g. /org/gnome/desktop/interface/gtk-theme.

Inputs: path (required). Returns: result

dconf_writeDconf WriteC

Write a dconf key (GVariant syntax value).

Inputs: path (required), value (required). Returns: result

delete_pathDelete PathA

Delete a file or directory. Directories need recursive=True. Destructive: cannot be undone. Protected system paths are refused.

Inputs: path (required), sudo, recursive. Returns: result

double_clickDouble ClickC

Double-click, optionally at coordinates.

Inputs: x, y, button. Returns: result

drag_mouseDrag MouseB

Drag with a button held from (x1,y1) to (x2,y2). X11 only.

Inputs: x1 (required), x2 (required), y1 (required), y2 (required), +1 more. Returns: result

find_processes_by_nameFind Processes By NameA

Find processes by name (substring on name/cmdline, or exact match).

Inputs: name (required), exact. Returns: result

find_windows_by_processFind Windows By ProcessB

Find windows owned by a pid or process-name substring.

Inputs: name_or_pid (required). Returns: result

find_windows_by_titleFind Windows By TitleB

Find windows whose title contains the substring (case-insensitive).

Inputs: title (required). Returns: result

focus_windowFocus WindowB

Raise and focus a window by id (0x...) or title substring.

Inputs: title, window_id. Returns: result

fullscreen_windowFullscreen WindowC

Toggle fullscreen state of a window.

Inputs: on, title, window_id. Returns: result

get_active_windowGet Active WindowA

The currently focused window (id, title, geometry). X11 only.

Inputs: no named parameters. Returns: result

get_clipboardGet ClipboardA

Read clipboard text (wl-paste/xclip/xsel).

Inputs: no named parameters. Returns: result

get_cpu_usageGet Cpu UsageB

CPU usage percent (samples over interval seconds).

Inputs: interval, per_core. Returns: result

get_desktop_statusGet 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.

Inputs: no named parameters. Returns: result

get_disk_usageGet Disk UsageA

Disk usage for the filesystem containing path.

Inputs: path. Returns: result

get_environment_variablesGet 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.

Inputs: mask_secrets. Returns: result

get_hardware_infoGet Hardware InfoB

Hardware details via lscpu, lsusb, lspci, lsblk when available.

Inputs: no named parameters. Returns: result

get_memory_infoGet Memory InfoA

Memory and swap details (total/available/used/cached/buffers).

Inputs: no named parameters. Returns: result

get_mouse_positionGet Mouse PositionA

Current mouse position (X11 only).

Inputs: no named parameters. Returns: result

get_network_infoGet Network InfoB

Network interfaces with IPs, state, speed, IO counters, default route and DNS servers.

Inputs: no named parameters. Returns: result

get_path_infoGet Path InfoC

Detailed stat info: type, size, owner, permissions, times, symlink target, access flags.

Inputs: path (required). Returns: result

get_process_infoGet Process InfoB

Detailed info for one pid: exe, cmdline, cwd, threads, memory, cpu times, open files, network connections.

Inputs: pid (required), include_env. Returns: result

get_screen_dimensionsGet Screen DimensionsB

Screen pixel dimensions and per-monitor geometry.

Inputs: no named parameters. Returns: result

get_service_logsGet Service LogsC

Journal logs for one unit.

Inputs: name (required), user, lines, since, +1 more. Returns: result

get_service_statusGet Service StatusB

Detailed unit status: ActiveState/SubState, MainPID, memory, enablement, plus last status output lines.

Inputs: name (required), user. Returns: result

get_system_infoGet System InfoA

Overall system snapshot: OS/distro, kernel, uptime, CPU model and load, memory, swap, root disk, logged-in users.

Inputs: no named parameters. Returns: result

gsettings_describeGsettings DescribeB

Describe a gsettings key and its allowed range/values.

Inputs: key (required), schema (required). Returns: result

gsettings_getGsettings GetB

Read a gsettings value, e.g. schema org.gnome.desktop.interface, key gtk-theme.

Inputs: key (required), schema (required). Returns: result

gsettings_list_keysGsettings List KeysC

List keys in a gsettings schema.

Inputs: schema (required). Returns: result

gsettings_list_schemasGsettings List SchemasA

List installed gsettings schemas, optionally substring-filtered (e.g. 'gnome', 'zora', 'desktop').

Inputs: limit, filter. Returns: result

gsettings_resetGsettings ResetC

Reset a gsettings key to its default.

Inputs: key (required), schema (required). Returns: result

gsettings_setGsettings SetB

Write a gsettings value. value uses GVariant syntax: true/false, 42, 'quoted-string', ['a','b'].

Inputs: key (required), value (required), schema (required). Returns: result

key_referenceKey ReferenceA

List valid key names and combo examples for press_key.

Inputs: no named parameters. Returns: result

kill_processKill ProcessB

Terminate a process. SIGTERM by default, escalating to SIGKILL after timeout. force=True sends SIGKILL immediately.

Inputs: pid (required), force, timeout. Returns: result

kill_processes_by_nameKill Processes By NameC

Kill all processes matching a name. Returns per-pid results.

Inputs: name (required), exact, force. Returns: result

list_directoryList DirectoryB

List directory contents with type, size, mode and mtime per entry.

Inputs: path (required), recursive, max_entries, show_hidden. Returns: result

list_disksList DisksB

Mounted partitions with fstype, usage and IO counters.

Inputs: no named parameters. Returns: result

list_listening_portsList Listening PortsC

Listening TCP/UDP ports with owning pid and process name.

Inputs: protocol. Returns: result

list_log_filesList Log FilesC

List log files under /var/log (or another dir), newest first.

Inputs: pattern, directory, max_entries. Returns: result

list_processesList ProcessesB

List running processes with pid, name, cpu%, mem%, status, cmdline.

Inputs: limit, sort_by, username, name_filter. Returns: result

list_servicesList ServicesC

List systemd service units with load/active/sub state.

Inputs: user, limit, state, pattern. Returns: result

list_shell_sessionsList Shell SessionsB

List all active PTY sessions.

Inputs: no named parameters. Returns: result

list_windowsList WindowsA

List all windows: id, desktop, pid, geometry, wm_class, title. X11 only (wmctrl).

Inputs: no named parameters. Returns: result

manage_serviceManage ServiceC

Control a systemd unit.

Inputs: name (required), action (required), sudo, user. Returns: result

maximize_windowMaximize WindowB

Maximize a window by id or title substring.

Inputs: title, window_id. Returns: result

minimize_windowMinimize WindowC

Minimize (iconify) a window by id or title substring.

Inputs: title, window_id. Returns: result

move_mouseMove MouseA

Move the mouse pointer to absolute screen coordinates.

Inputs: x (required), y (required). Returns: result

move_pathMove PathC

Move/rename a file or directory.

Inputs: source (required), destination (required), sudo, overwrite. Returns: result

move_windowMove WindowC

Move/resize a window by id or title substring.

Inputs: x (required), y (required), width (required), height (required), +2 more. Returns: result

package_filesPackage FilesC

List files owned by an installed package (dpkg -L).

Inputs: name (required), limit. Returns: result

package_infoPackage InfoB

Package details: version, dependencies, description, install status, candidate version (apt-cache show/policy).

Inputs: name (required). Returns: result

package_installPackage InstallB

Install packages via apt-get install -y (sudo).

Inputs: names (required), timeout, update_first. Returns: result

package_list_installedPackage List InstalledB

List installed packages (dpkg). filter = name substring.

Inputs: limit, filter. Returns: result

package_ownerPackage OwnerB

Which package owns a file (dpkg -S).

Inputs: path (required). Returns: result

package_removePackage RemoveA

Remove packages (apt-get remove -y). purge=True also removes config files.

Inputs: names (required), purge, timeout. Returns: result

package_updatePackage UpdateC

Refresh package lists (apt-get update, sudo).

Inputs: timeout. Returns: result

package_upgradePackage UpgradeB

Upgrade installed packages (apt-get upgrade -y, sudo). full=True runs dist-upgrade. Potentially long-running.

Inputs: full, timeout. Returns: result

path_existsPath ExistsC

Check whether a path exists.

Inputs: path (required). Returns: result

press_keyPress KeyB

Press a key or combo (xdotool names: Return, Tab, Escape, F5, 'ctrl+c', 'alt+F4'). See key_reference for valid names.

Inputs: key (required). Returns: result

process_treeProcess TreeC

Show a process and all its descendants.

Inputs: pid (required). Returns: result

read_file_base64Read File Base64B

Read a (binary) file as base64. Capped at 20MB by default.

Inputs: path (required), max_bytes. Returns: result

read_file_textRead File TextB

Read a text file by lines.

Inputs: path (required), limit, offset, encoding. Returns: result

read_journalRead JournalC

Query the systemd journal (journalctl).

Inputs: grep, sudo, unit, user, +5 more. Returns: result

read_log_fileRead Log FileB

Read a log file. tail=True returns the last lines lines; tail=False reads lines lines starting at offset.

Inputs: path (required), tail, lines, offset. Returns: result

read_session_outputRead Session OutputA

Read output from a PTY session.

Returns only new output since the last read unless all_output=True.

Inputs: session_id (required), all_output. Returns: result

restore_windowRestore WindowB

Unmaximize/restore a window to normal state.

Inputs: title, window_id. Returns: result

run_argvRun ArgvB

Run a program with an argument list (no shell interpretation).

Safer than run_command for arguments containing shell metacharacters.

Inputs: argv (required), cwd, env, sudo, +1 more. Returns: result

run_commandRun CommandC

Run a shell command and return stdout, stderr and exit code.

Inputs: command (required), cwd, env, sudo, +3 more. Returns: result

sapper_arenaSapper 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 flag for challenge_id hint request hint for challenge_id (may cost score)

Config: env BENCHMARK_BASE_URL + BENCHMARK_TOKEN, or .sapper/arena.json.

Inputs: action (required), flag, store, challenge_id. Returns: result

sapper_autoSapper AutoC

Drive a graph toward its goal autonomously: reason -> explore -> optional verify, looping until max-steps, the goal, or the deadline (like sapper auto).

Inputs: cwd, model, store, verify, +10 more. Returns: result

sapper_benchSapper BenchB

TSecBench end-to-end driver: list -> start -> solve -> submit -> close per challenge (like sapper bench). The hosted-mode entrypoint. Use background=True for real runs.

Inputs: cwd (required), root, model, verify, +11 more. Returns: result

sapper_boardSapper BoardB

One-line status per challenge graph under root - the commander's board (flags sub/rec, intel counts, open intents, last activity).

Inputs: root. Returns: result

sapper_brainstorm_pickSapper Brainstorm PickB

Pick one brainstorm option; siblings from the same batch are concluded with a rejection fact (like sapper brainstorm-pick).

Inputs: id (required), cwd, store. Returns: result

sapper_captureSapper CaptureC

Capture recent output from an authorized tmux peer (like sapper capture).

Inputs: peer (required), cwd, log, lines, +2 more. Returns: result

sapper_claimSapper ClaimC

Claim an open intent for a worker.

Inputs: id (required), worker (required), store. Returns: result

sapper_cliSapper CliB

Run any bundled sapper CLI command verbatim (escape hatch).

Inputs: args (required), cwd, store, background, +1 more. Returns: result

sapper_commandSapper CommandC

Field commander loop: LLM allocates the next work slice across per-challenge graphs under root (like sapper command). Runs until deadline/stop - use background=True for real campaigns.

Inputs: cwd (required), root, model, verify, +12 more. Returns: result

sapper_completeSapper CompleteC

Mark the project goal satisfied, justified by the given facts (like sapper complete --from f001,f005).

Inputs: from_ids (required), note, store, worker. Returns: result

sapper_confirmSapper ConfirmC

Confirm an intent that was created with confirm=True.

Inputs: id (required), store. Returns: result

sapper_dispatchSapper DispatchC

Run one commander/executor step via the agent CLI (like sapper dispatch <target>).

Inputs: target (required), cwd, claim, model, +9 more. Returns: result

sapper_docSapper DocC

Read or write a node's detailed doc (title=gist, doc=detail).

sapper_doc(id) returns the doc; pass set or set_file to write.

Inputs: id (required), set, store, set_file. Returns: result

sapper_doneSapper DoneC

Conclude an intent with the fact it produced (atomic, like sapper done <id> --fact "...").

Inputs: id (required), fact (required), doc, data, +5 more. Returns: result

sapper_factSapper FactC

Record a confirmed fact (like sapper fact).

Inputs: description (required), doc, data, kind, +5 more. Returns: result

sapper_flagSapper 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).

Inputs: value (required), store, title, submit, +2 more. Returns: result

sapper_fleetSapper FleetB

Manage the tmux worker fleet (like sapper fleet).

action: init | up | down | status | hire | fire | workers hire/fire take target=; hire also minutes/max_steps/ extra_args.

Inputs: action (required), cwd, file, target, +3 more. Returns: result

sapper_frontierSapper FrontierB

List open intents that are ready to work (dependencies met, confirmed). Claimed intents come first.

Inputs: store. Returns: result

sapper_graphSapper GraphC

Dump the whole graph. format=json gives the structured view, format=text renders the CLI text form.

Inputs: store, format. Returns: result

sapper_hintSapper HintC

Add or list human hints for the agents (like sapper hint).

Inputs: list, store, content, creator. Returns: result

sapper_initSapper InitC

Create a fact-intent graph (like sapper init --goal).

Inputs: goal (required), force, store, origin. Returns: result

sapper_intentSapper IntentC

Add an intent - a unit of work derived from existing facts (like sapper intent --from f001,f002).

Inputs: from_ids (required), description (required), doc, store, +4 more. Returns: result

sapper_kbSapper KbB

Shared offline knowledge base (like sapper kb).

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

Inputs: action (required), root, tags, limit, +6 more. Returns: result

sapper_peersSapper PeersC

Discover tmux panes and manage user-authorized AI peers (like sapper peers).

Inputs: add, cwd, note, store, +5 more. Returns: result

sapper_pickSapper PickC

Pick the next intent to work (like sapper pick).

Inputs: claim, store, worker, any_open. Returns: result

sapper_recallSapper 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.

Inputs: query (required), kind, limit, store. Returns: result

sapper_releaseSapper ReleaseC

Release a claimed intent back to open.

Inputs: id (required), store, worker. Returns: result

sapper_reportSapper ReportB

Generate a markdown engagement report from the graph: summary, flag ledger, typed findings (hosts/services/creds/vulns/loot), work log, timeline, hints. Writes out (default /../sapper-report.md) and returns the markdown.

Inputs: out, store, title, include_docs. Returns: result

sapper_sendSapper SendC

Send a message to a user-authorized tmux peer via load-buffer/ paste-buffer (like sapper send <peer> <msg>).

Inputs: peer (required), message (required), cwd, raw, +4 more. Returns: result

sapper_setupSapper SetupB

Opt a project IN: create .sapper/ + register Claude Code hooks in <project_dir>/.claude/settings.json (like sapper setup).

Inputs: project_dir (required), goal, force, store, +2 more. Returns: result

sapper_showSapper ShowC

Show project | fact | intent as JSON.

Inputs: entity (required), id, store. Returns: result

sapper_statusSapper StatusC

Project + frontier summary text (like sapper status).

Inputs: store. Returns: result

sapper_sweepSapper SweepB

Round-robin driver: every challenge graph under root gets minutes_per of sapper auto per round until deadline (like sapper sweep). Requires minutes or deadline.

Inputs: cwd (required), root, model, verify, +8 more. Returns: result

sapper_teardownSapper TeardownB

Remove sapper hooks + its AGENTS.md from a project. purge=True also deletes the .sapper/ graph data (destructive).

Inputs: project_dir (required), purge, store. Returns: result

sapper_validateSapper ValidateC

Integrity-check the graph; returns a list of errors (empty = valid).

Inputs: store. Returns: result

sapper_viewSapper ViewB

Render the interactive HTML graph visualization (like sapper view). Writes a self-contained snapshot file; set return_html=True to also get the HTML in the response.

Inputs: out, store, return_html. Returns: result

scroll_mouseScroll MouseB

Scroll the mouse wheel up/down, optionally at coordinates. X11 only.

Inputs: x, y, clicks, direction. Returns: result

search_filesSearch FilesC

Search files under a path by name glob and/or literal content.

Inputs: path (required), max_results, name_pattern, include_hidden, +1 more. Returns: result

send_key_comboSend Key ComboB

Send a key combination like 'ctrl+alt+t' or 'alt+F4'.

Inputs: combo (required). Returns: result

send_signalSend SignalC

Send a signal by name (TERM, KILL, INT, HUP, USR1, STOP, CONT, ...) to a process.

Inputs: pid (required), signal_name (required). Returns: result

set_clipboardSet ClipboardC

Write text to the clipboard.

Inputs: text (required). Returns: result

set_permissionsSet PermissionsC

chmod/chown a path.

Inputs: path (required), mode, sudo, group, +2 more. Returns: result

start_processStart ProcessA

Start a detached background process (shell command line).

For interactive processes or output capture, use start_shell_session.

Inputs: command (required), cwd, env. Returns: result

start_shell_sessionStart Shell SessionA

Start a persistent interactive PTY session and return its id.

With command=None spawns an interactive shell. With a command, runs shell -c <command> inside the PTY - ideal for long-running apps, debuggers (gdb), REPLs, or anything needing a TTY. Use write_to_session / read_session_output to interact.

Inputs: cwd, sudo, shell, command. Returns: result

type_textType TextB

Type text as keyboard input (xdotool/wtype). Focus the target window first if needed.

Inputs: text (required), delay_ms. Returns: result

wait_for_processWait For ProcessC

Block until a process exits (or timeout).

Inputs: pid (required), timeout. Returns: result

write_file_base64Write File Base64C

Write base64-decoded bytes to a file.

Inputs: path (required), data_base64 (required), create_dirs. Returns: result

write_file_textWrite File TextB

Write text to a file. Creates parent dirs by default.

Inputs: path (required), content (required), append, create_dirs. Returns: result

write_to_sessionWrite To SessionC

Write input to a PTY session's stdin.

Inputs: text (required), session_id (required), press_enter. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.7/5.0

    Scored across 127 tools

    Disambiguation2/5

    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.

    Naming Consistency3/5

    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.

    Tool Count2/5

    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.

    Completeness4/5

    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.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Unified MCP server integrating NIST and OWASP security frameworks with live vulnerability data, enabling security searches, compliance mapping, threat modeling, and checklist generation.
      41
      14
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables professional penetration testers to run reconnaissance, network and web scanning, content fuzzing, vulnerability templates, brute-force checks, SQLi extraction, traffic capture, and engagement report generation through MCP clients.
      165 npm
      GPL 3.0
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables authorized penetration testers to run reconnaissance, scanning, brute-force, traffic-capture, and exploitation tools through MCP clients, with authentication, engagement recordkeeping, and client report generation.
      165 npm
      GPL 3.0
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables professional penetration testers to run reconnaissance, exploitation, password cracking, web fuzzing, vulnerability scanning, traffic capture, and client-reporting workflows through MCP transports with auth support.
      165 npm
      GPL 3.0