blast-scope-mcp
The Blast Scope MCP server is a consequence engine that assesses the blast radius of shell commands and provides undo snapshots for reversible actions. It offers the following tools:
assess_command: Analyzes a shell command's potential destructive impact, returning a risk score (0.0–1.0), severity (low/medium/high/critical), recommendation (proceed/confirm/block), rationale, evidence, recoverability classification, and a per-segment breakdown for chained commands. Uses a project dependency graph for contextual scoring.
index_project: Forces a rebuild of the project's dependency graph, which is used by
assess_commandfor more accurate risk scoring. Automatically triggered on first use, but can be manually run after large changes.list_snapshots: Lists available undo snapshots automatically created before high-risk commands, showing ID, creation time, reason, and covered paths.
restore_snapshot: Restores files from a selected snapshot to undo the effects of a risky command.
Scores destructive Docker commands (e.g., volume rm, system prune -a, rm -f) by performing safe read-only probes to assess blast radius and reversibility.
Scores destructive Git commands (e.g., reset --hard, push --force, branch -D, clean -fdx) by using read-only probes like status, reflog, and rev-list to determine risk.
Scores destructive SQL commands (e.g., DROP, TRUNCATE, DELETE without WHERE) by performing read-only SELECT count(*) probes on SQLite databases to assess data loss risk.
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 confirmTwo 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 |
| dependency graph + git status | git-tracked? regenerable? secret? precious? |
Git |
|
| reflog window · remote ahead · protected branch |
Docker |
|
| volume → none · container → recreatable from image |
pip / uv |
| read lockfile / manifest (no subprocess) | lockfile present → fully regenerable |
SQL |
| SQLite: | 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: cmdxray
Status
Calibrated multi-class guardrail with command resolution and a precise dependency graph.
Capability | Module |
Flag/operand-sensitive command model (POSIX and PowerShell) |
|
Command resolution — env/tilde/brace/glob expansion, unset-var hazards, script transparency ( |
|
Dry-run oracles — |
|
Recoverability classification (git state, secrets, regenerable, precious data) |
|
Dependency graph + weighted PageRank centrality, incremental indexing |
|
Two-axis, evidence-based filesystem scoring |
|
Command-class probes — git / docker / pip·uv / SQL, behind one protocol |
|
Out-of-graph path analyzers (infra / config-by-path) + git base |
|
PreToolUse hook + tarball snapshot/undo |
|
Eval harness + labeled corpus + calibration |
|
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 -cpayloads, npm pre-hooks, opaque wrappers, mass destruction of tracked source) — 58/58 exact severity, gate F1 1.00, pinned bytests/test_eval.pywith 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 liftscode_tamperingfrom ~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. Seebench/.
uv run python -m blast_scope.eval # in-repo corpus
python bench/saber_eval.py --tasks <saber>/dataset/data/tasks.jsonl # SABERInstallation
The fastest path for any MCP client is zero-install via uvx (no clone, no venv):
uvx blast-scope # runs the MCP server on stdioClaude Code users — one line wires up both the MCP tools and the advisory hook:
/plugin marketplace add Atharva-Jayappa/blast-scope
/plugin install blast-scopeFor development, or to pin a checkout:
git clone https://github.com/Atharva-Jayappa/blast-scope.git
cd blast-scope && uv sync --all-extrasUsage
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 |
| Score a (possibly chained) command. Returns score, severity, rationale, evidence, recoverability, affected nodes, and a per-segment |
| Force a dependency-graph rebuild (auto-built on first use otherwise). |
| List undo snapshots, newest first. |
| Undo a risky command by restoring its snapshot. |
As a 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.
The hooks also keep the dependency graph alive on their own — no MCP call
needed: SessionStart cold-builds it in a detached background process, and
every PreToolUse refreshes it incrementally before scoring (a ~20 ms stat
sweep when nothing changed), so verdicts track the current tree even after a
burst of agent edits. Add to .claude/settings.json:
{
"hooks": {
"SessionStart": [
{ "hooks": [{ "type": "command", "command": "python -m blast_scope.hook" }] }
],
"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 reportProject 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 + undoRoadmap
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.
Available Tools
4 toolsassess_commandA
Assess the blast radius of a shell command.
Splits chained commands on &&, ||, ;, and |, then
parses, resolves, and scores each segment independently. The top-level
fields surface the worst step's score and recommendation; the chain
field contains every step's individual breakdown.
When project_root is provided and no graph database exists yet,
the graph is built automatically on the first call. Use
index_project to force a rebuild.
Args: command: Raw shell command string to analyze. cwd: Working directory for resolving relative paths. Defaults to the server's current working directory. project_root: Root directory of the project for graph-based scoring. If provided, the graph is auto-built when missing.
Returns: Structured risk assessment with worst-step score, severity, recommendation, and per-step chain breakdown.
Example::
assess_command("cd /tmp && rm -rf .", cwd="/home/user", project_root="/project")
Inputs: command (required), cwd, project_root.
index_projectA
Build or refresh the dependency graph for a project.
Forces a graph rebuild for the given project root. Normally not
required — assess_command auto-builds the graph on first use —
but useful to refresh after a large code change.
Args: project_root: Absolute path to the project root directory.
Returns: Status dict confirming the project was indexed.
Example::
index_project("/home/user/my-project")
Inputs: project_root (required).
list_snapshotsA
List undo snapshots captured before risky commands, newest first.
Snapshots are taken automatically by the PreToolUse hook before a
medium-or-higher risk command and stored under
<project_root>/.blast-scope/snapshots.
Args: project_root: The project root the snapshots were taken under.
Returns:
{"snapshots": [{id, created, reason, paths}, ...]}.
Example::
list_snapshots("/home/user/my-project")
Inputs: project_root (required).
restore_snapshotA
Undo a risky command by restoring a snapshot's files in place.
Overwrites whatever currently exists at each snapshotted path with the
archived copy. Use list_snapshots to find the id.
Args: snapshot_id: The snapshot id to restore. project_root: The project root the snapshot was taken under.
Returns:
{"status": "restored", "paths": [...]} or an error entry.
Example::
restore_snapshot("20260530T101500-a1b2c3", "/home/user/my-project")
Inputs: snapshot_id (required), project_root (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
Each tool targets a distinct action: assessing commands, rebuilding the graph, listing snapshots, and restoring them. No functional overlap exists.
All tools follow a consistent verb_noun pattern with lowercase and underscores (assess_command, index_project, list_snapshots, restore_snapshot).
Four tools cover the essential operations on the blast radius domain without redundancy or missing core functionality.
The set covers assessment, graph indexing, and snapshot retrieval/restoration. Snapshot lifecycle management (e.g., deletion) is not exposed, but the core workflow is complete.
Maintenance
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Autonomous agent guardrails, bash sandboxing, MCP rugpull diffing & prompt firewalls.
Pre-execution governance for AI agents. Deterministic PASS/FAIL/REVIEW verdicts, replayable proof.
Checks AI-written code for leaked keys and made-up packages, on your machine. Never uploads code.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides safe shell command execution capabilities for AI agents and tools like VS Code Copilot through a whitelist-based filtering system.-
- AlicenseAqualityAmaintenanceOffline server that explains any shell command token-by-token and flags destructive ones (rm -rf /, curl | sudo bash, dd/mkfs/shred to a disk device, chmod -R 777 /) — a safety gate for agentic shell execution.3167 npm5MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to assess the risk of shell commands before execution, providing a probability of harm and a suggested action (auto, warn, or confirm).MIT
- AlicenseNot gradedqualityBmaintenanceEnables MCP-compatible agents to execute bash and subprocess commands through a zero-dependency sandbox guard that blocks destructive system mutations, path traversals, reverse shells, and other unsafe execution patterns.7MIT