Skip to content

Test your own app

The bundled reference app proves the machinery. The point of Mylonite is to run it against your AI agent. If your app exposes its tools over MCP (or any stdio MCP server), this is the end-to-end path: scaffold a target file, scan, and gate.

No MCP? If your agent is a plain HTTP endpoint (a prompt in, a reply out), use the rest transport — describe the request shape in the target file and change nothing in your app.

What gets tested. Mylonite drives your server's tools with its own planner — guardrails that live in your agent or host process, not the server, are never exercised. See Coverage by app shape for exactly which weakness classes are testable on your app's shape.

Authorisation. Mylonite finds and reproduces working exploits, so every non-reference target requires an explicit --authorize flag asserting you control the target. Its value is the target's scope, or its family when it declares no scope; leave it off and Mylonite prints the value to pass. See Security. Never point it at an app you don't own.

1. Scaffold a target file

scan --scaffold launches your MCP server, lists its tools (no LLM call, no attack), infers the likely weakness classes and the plant/retrieve tools, and writes a commented target.yaml starter (no --authorize needed — nothing is attacked):

mylonite scan --command "python" --arg "my_server.py" --scaffold app.yaml --scope my-app

--scope is optional here (it labels the target and becomes the value --authorize must match below — see the target.yaml reference); omit it and the scaffolded target.yaml falls back to family: custom, so --authorize custom instead.

It suggests weakness_classes (W1/W2 baseline; W3 if it sees an egress tool; W4 if it sees a consequential tool), pre-fills a seed_arm (how to plant poisoned content) and an effect_probe (how to confirm damage), and lists your tools. Fill in the commented sections — see the full target.yaml reference.

A minimal target file is just:

family: my-app
command: python
args: [my_server.py]
weakness_classes: [W2]
seed_arm:                    # how to plant untrusted content (required for W2)
  tool: save_note
  args_template: { body: "{payload}" }

Auto-wiring. For a W2 target, if you omit seed_arm, scan will infer it from the live tool surface when a no-id recall path exists (so the planted payload is guaranteed to be surfaced back) — printing what it inferred. Otherwise it blocks loudly rather than silently skipping the W2 attack patterns and reading as clean.

2. Scan it

mylonite scan --target-file app.yaml --authorize my-app

This runs the single-shot engine. Findings land under .mylonite/scans/. Use the model roles to point the planner at a representatively exploitable model.

3. Gate it (the full pipeline)

gate runs the whole pipeline — scan → generate → validate → (optionally) open a PR — and only a kept test makes it through:

mylonite gate --target-file app.yaml --authorize my-app            # writes the test; add --workflows for CI templates
mylonite gate --target-file app.yaml --authorize my-app --open-pr  # also opens the PR via gh

Because you have no in-repo guarded build, the validator synthesizes one at the adapter boundary (the control-efficacy check) and proves the finding differentially by default — the emitted test gates on the control being load-bearing, with the boundary-proxy caveat stated on the label. See CI gating for the committed workflows and the PR anatomy.

4. Keep it honest over time

  • Scoring each safeguard individually (load-bearing, security theater, redundant, no-attack, or inconclusive) is ablate, which is hidden and experimental — see docs/experimental.md.
  • When you change models — re-validate the committed test with the new --planner-model before you ship. See Re-validate on a new model.

Bundled targets

Three MCP servers ship as ready-to-scan targets (no target file needed) — useful for trying Mylonite against real servers:

Target Scope Exposes
mcp:filesystem:<abs/path> a sandbox dir W1, W2, W4 (read/write files)
mcp:fetch optional label W3 (egress)
mcp:github:<owner/repo> a repo W1, W2, W4 (issues/comments)
mylonite scan mcp:filesystem:/tmp/sandbox --authorize /tmp/sandbox

On Windows, use an existing, non-root directory and quote the path if it has spaces:

mylonite scan mcp:filesystem:C:\sandbox --authorize C:\sandbox

mcp:github needs a token: export GITHUB_PERSONAL_ACCESS_TOKEN (the exact variable the real GitHub MCP server reads) before you scan — an unset value fails fast, naming it, before any subprocess launches.

export GITHUB_PERSONAL_ACCESS_TOKEN=ghp_...
mylonite scan mcp:github:myhandle/my-repo --authorize myhandle/my-repo

These bundled families are attack-only today (they scan but don't yet route through the differential oracle); routing them through the on-ramp so they can emit a gating test is planned. For a CI-gating test against a real app, use --target-file.