Skip to main content
Glama
Atharva-Jayappa

blast-scope-mcp

Blast Scope

A consequence engine for shell commands. Blast Scope scores what a command would actually do — before an AI agent (or you) runs it. It doesn't pattern-match syntax into a blocklist; it figures out the command's real target, observes that target with a safe, read-only probe, and returns a structured risk score with evidence.

The whole point is contextual blast radius. The same command gets a completely different score depending on what it would actually hit:

COMMAND                            SEVERITY   WHY                                          ADVICE
─────────────────────────────────  ────────   ──────────────────────────────────────────  ───────
rm -rf ./logs                      LOW        0 importers · regenerable · outside src      proceed
rm -rf ./config                    CRITICAL   8 modules import it · high PageRank hub      block
git reset --hard   (clean tree)    LOW        nothing uncommitted to discard               proceed
git reset --hard   (4 dirty files) HIGH       would throw away 4 files of uncommitted work confirm
git push --force   (protected)     CRITICAL   would orphan commits on a protected branch   block
docker volume rm cache  (absent)   LOW        volume doesn't exist — nothing to remove     proceed
docker volume rm pgdata (in use)   CRITICAL   holds data · in use · no image to rebuild    block
pip uninstall flask     (uv.lock)  LOW        regenerable — exact version pinned in lock   proceed
DROP TABLE users        (42 rows)  CRITICAL   schema + 42 rows · irreversible              block
DELETE FROM logs        (in txn)   HIGH       no WHERE — but inside a txn, ROLLBACK-able    confirm

Two commands can be byte-identical and score four bands apart. That gap is the product.

Not a blocklist. Not a replacement for Shellfirm. Not a syscall monitor. It scores structural consequence — advisory, never blocking — and for the rare critical command it captures an undo snapshot first.


How it works

A command flows through a cheap funnel: almost everything is recognized as non-destructive in microseconds and exits silent. Only a flagged destructive candidate pays for a probe.

  shell command
      │   split chains (&& || ; |) · de-alias PowerShell · parse flags/targets
      ▼
  ┌──────────────────────────────────────────────────────────────────────┐
  │  STAGE 1 · triage  (near-free regex — runs on every command)          │
  │     which class?   git · docker · pip/uv · sql · else filesystem       │
  │     destructive?   `git status` → no.   `git reset --hard` → yes ↓     │
  └───────────────────────────────┬──────────────────────────────────────┘
                    destructive candidate │   (everything else exits here, silent)
                                          ▼
  ┌──────────────────────────────────────────────────────────────────────┐
  │  ELIGIBILITY FILTER   safe read-only probe?   AND   undo authorable?   │
  └──────────────┬──────────────────────────────────────┬─────────────────┘
         yes, probe it │                       no probe here / now │
                       ▼                                           ▼
   STAGE 2 · safe probe (read-only)                    heuristic estimate
     git  status · reflog · rev-list                   from a static per-class
     docker  inspect · ps · ls                          table — and LABELED
     sqlite  SELECT count(*)  [mode=ro]                  "(estimated)" so you
     pip/uv  read lockfiles                              know it wasn't probed
                       │                                           │
                       └─────────────────────┬─────────────────────┘
                                              ▼
        blast radius  ×  reversibility   (combined PER CLASS — no global formula)
        filesystem also folds in: dependency-graph centrality + recoverability
                                              ▼
              score 0.0–1.0  →  severity (low / medium / high / critical)
                                              ▼
        PreToolUse hook:  silent (low/med) · advise (high) · advise + snapshot (critical)

The eligibility filter is the design boundary. A command class earns a live probe only when both hold: (1) its impact is observable by a strictly side-effect-free read (HTTP-GET sense — never mutate state to assess state), and (2) its undo story is well-known enough to encode in a static table. When a probe can't run here and now (no docker daemon, no DB driver, no creds), the tool degrades to a labeled estimate — it never guesses silently, and it never blocks.

See docs/heuristics.md for the per-class tables, the exact filesystem formula, and calibration.

The five command classes

Class

Destructive ops it scores

Safe (read-only) probe

Reversibility signal

Filesystem

rm -rf, mv, > truncate

dependency graph + git status

git-tracked? regenerable? secret? precious?

Git

reset --hard, push --force, branch -D, clean -fdx

status · reflog · rev-list · rev-parse @{u}

reflog window · remote ahead · protected branch

Docker

volume rm, system prune -a, rm -f

volume inspect · ps -a · volume ls

volume → none · container → recreatable from image

pip / uv

pip uninstall, uv pip uninstall

read lockfile / manifest (no subprocess)

lockfile present → fully regenerable

SQL

DROP, TRUNCATE, DELETE without WHERE

SQLite: SELECT count(*) mode=ro; transaction check

inside a transaction? backup posture?

New classes drop in behind one protocol (triage / assess) in src/blast_scope/classes/; each class confines assess to strictly side-effect-free reads.


Related MCP server: runtime-guard

Status

Calibrated multi-class guardrail with command resolution and a precise dependency graph.

Capability

Module

Flag/operand-sensitive command model (POSIX and PowerShell)

command_effects.py, command_parser.py

Command resolution — env/tilde/brace/glob expansion, unset-var hazards, script transparency (sh -c, npm run + pre/post hooks, script files, Makefile targets), read-only $(...) substitution

resolution.py

Dry-run oraclesgit clean -n exact lists, reset divergence, checkout clobber preview, find -delete-print rewrite, sqlite scoped-DELETE counts, rsync --dry-run; oracle targets feed the undo snapshot

classes/git.py, classes/find.py, classes/rsync.py, classes/sql.py

Recoverability classification (git state, secrets, regenerable, precious data)

recoverability.py

Dependency graph + weighted PageRank centrality, incremental indexing

graph_resolver.py, centrality.py

Two-axis, evidence-based filesystem scoring

risk_scorer.py

Command-class probes — git / docker / pip·uv / SQL, behind one protocol

classes/

Out-of-graph path analyzers (infra / config-by-path) + git base

consequences.py, vcs.py, infra.py, config_refs.py

PreToolUse hook + tarball snapshot/undo

hook.py, snapshot.py

Eval harness + labeled corpus + calibration

eval.py, tests/fixtures/eval_corpus.jsonl

Calibration. Two harnesses, both run-it-yourself:

  • In-repo corpus (tests/fixtures/eval_corpus.jsonl, 58 cases spanning every recoverability category, git working-tree state, infra/config, rm -rf .git, a graph-indexed central module, the git/docker/pip/SQL classes, and the resolution layer — unset-var collapses, glob/env-var targets, sh -c payloads, npm pre-hooks, opaque wrappers, mass destruction of tracked source) — 58/58 exact severity, gate F1 1.00, pinned by tests/test_eval.py with headroom so changes can't silently regress.

  • SABER — 716 real coding-agent workspaces. Against ~1725 safe commands, blast-scope's false-positive rate is 0.58%; on its core competency (data_destruction) it catches 82.4% of injected attacks on realistic workspaces — on the fast hook path, no graph required, thanks to command resolution (env/glob binding + script transparency). Wrapper transparency also lifts code_tampering from ~0% to 50%. The per-category recall is deliberately uneven, and the table says so: blast-scope scores destructive consequence — filesystem/data loss plus git/docker/pip/SQL state. Network exfiltration and persistence are a different threat model, out of scope by design — not an unfinished corner. That's the boundary, drawn on purpose. See bench/.

uv run python -m blast_scope.eval                 # in-repo corpus
python bench/saber_eval.py --tasks <saber>/dataset/data/tasks.jsonl   # SABER

Installation

The fastest path for any MCP client is zero-install via uvx (no clone, no venv):

uvx blast-scope        # runs the MCP server on stdio

Claude Code users — one line wires up both the MCP tools and the advisory hook:

/plugin marketplace add Atharva-Jayappa/blast-scope
/plugin install blast-scope

For development, or to pin a checkout:

git clone https://github.com/Atharva-Jayappa/blast-scope.git
cd blast-scope && uv sync --all-extras

Usage

As an MCP server

Add to your MCP client config (e.g. Claude Code settings.json):

{
  "mcpServers": {
    "blast-scope": { "command": "uvx", "args": ["blast-scope"], "type": "stdio" }
  }
}

Tools exposed:

Tool

Purpose

assess_command(command, cwd?, project_root?)

Score a (possibly chained) command. Returns score, severity, rationale, evidence, recoverability, affected nodes, and a per-segment chain breakdown.

index_project(project_root)

Force a dependency-graph rebuild (auto-built on first use otherwise).

list_snapshots(project_root)

List undo snapshots, newest first.

restore_snapshot(snapshot_id, project_root)

Undo a risky command by restoring its snapshot.

As a PreToolUse hook (tiered advice + auto-snapshot)

Intercept Bash commands before they run — advisory, never blocking. Volume scales with stakes: silent on low/medium, advise on high, advise + snapshot on critical. The snapshot skips what's already recoverable (git-clean, regenerable) and warns rather than tars anything over a hard size cap, so the undo net stays fast and trustworthy. Add to .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "python -m blast_scope.hook" }] }
    ]
  }
}

Full details and the undo flow: docs/hook.md.


Example output

A filesystem command, scored against the dependency graph:

// assess_command("rm -rf ./config", project_root="/proj")
{
  "score": 0.93,
  "severity": "critical",
  "recommendation": "block",
  "recoverability": "untracked",
  "rationale": "rm targets config. 8 direct importer(s), 14 total affected. not git-tracked. recursive deletion. CRITICAL risk.",
  "evidence": [
    "8 importer(s), 14 affected node(s)",
    "high centrality (PageRank 0.91) — a hub other code routes through",
    "untracked — not in git history",
    "recursive — applies to every file underneath"
  ],
  "affected_nodes": [ /* ... */ ],
  "chain": [ /* per-segment breakdown */ ]
}

A command class that couldn't probe — note the labeled estimate (no Postgres driver, server possibly remote, so the tool refuses to guess silently):

// assess_command('psql -c "DROP TABLE users"')
{
  "score": 0.9,
  "severity": "critical",
  "recommendation": "block",
  "evidence": [
    "drops users — its schema and all rows, irreversible (estimated — no read-only probe for postgres)"
  ]
}
// the same DROP against a local SQLite file probes for real:
//   "drops users — its schema and 42 row(s), irreversible"   (estimated: false)

Development

uv sync --all-extras
uv run pytest -q              # full suite
uv run python -m blast_scope.eval   # scoring accuracy report

Project structure

blast-scope/
├── src/blast_scope/
│   ├── server.py            # MCP server + tools (assess, index, snapshots)
│   ├── command_parser.py    # shell → structured intent (POSIX + PowerShell)
│   ├── command_effects.py   # command/flag/operand → intent + weight
│   ├── recoverability.py    # path → how recoverable if destroyed
│   ├── graph_resolver.py    # paths → dependency-graph impact (+ PageRank)
│   ├── centrality.py        # pure-Python weighted PageRank
│   ├── risk_scorer.py       # signals → score + severity + evidence
│   ├── classes/             # command-class probes behind one protocol
│   │   ├── __init__.py      #   Candidate · ConsequenceClass · registry
│   │   ├── git.py           #   reflog / upstream-divergence / protected branch
│   │   ├── docker.py        #   volume / container / system-prune probes
│   │   ├── packages.py      #   pip·uv uninstall vs. lockfile presence
│   │   └── sql.py           #   DROP/TRUNCATE/DELETE — SQLite probe + estimates
│   ├── consequences.py      # coordinator: class probes + path analyzers
│   ├── vcs.py / infra.py / config_refs.py   # git base + path analyzers
│   ├── hook.py              # PreToolUse advisory hook
│   ├── snapshot.py          # tarball snapshot / restore / list
│   ├── eval.py              # evaluation harness + metrics
│   └── vendor/crg/          # vendored from code-review-graph (MIT)
├── tests/                   # 298 tests incl. eval regression guard
│   └── fixtures/eval_corpus.jsonl   # labeled calibration corpus
└── docs/
    ├── heuristics.md        # scoring model + per-class tables + calibration
    └── hook.md              # hook registration + undo

Roadmap

  • Lift recall on the destruction classes (glob targets over tracked files, find-based deletion variants) — the SABER per-category table is the worklist.

  • Optional live probes for Postgres/MySQL (in-process, read-only) once a driver policy is settled — today those engines degrade to labeled estimates.

  • PowerShell-shell awareness in the hook path (the MCP tool already supports it).

  • Optional richer interception modes beyond advisory.

See CLAUDE.md for the full spec, contracts, and design rules.


License

Apache 2.0 (versions ≤ 0.3.1 were MIT). The vendored code-review-graph sources remain MIT under their upstream notice — see NOTICE.

Install Server
A
license - permissive license
A
quality
A
maintenance

Maintenance

Maintainers
Response time
0dRelease cycle
4Releases (12mo)
Commit activity

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Blocks dangerous operations: rm -rf, sensitive file access, privilege escalation, and more are denied before execution. Gates risky commands behind human approval (optional): configurable commands require explicit operator sign-off via a web GUI before the agent can proceed. Simulates blast radius: wildcard operations like rm \*.tmp are evaluated against real files before running, and blocked if th
    Last updated
    8
    15
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Blocks dangerous operations — rm -rf, sensitive file access, privilege escalation, and more are denied before execution. Gates risky commands behind human approval Simulates blast radius — wildcard operations like rm \*.tmp are evaluated before running Automatic backup of files Full audit of commands
    Last updated
    8
    15
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    MCP server that vets LLM-emitted shell commands BEFORE execution — detects rm -rf nested deep in chains, package-manager glob removal (apt remove 'nvidia'), dd/mkfs filesystem destruction, chmod 777 / chown -R privilege blast, network-exfil via curl | bash, chained shutdown/reboot, git destructive ops. 30 detection rules across 8 families. Sub-second, local, free, MCP-native.
    Last updated
    3
    MIT

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Atharva-Jayappa/blast-scope'

If you have feedback or need assistance with the MCP directory API, please join our Discord server