blastradius-mcp
Tracks Docker images referenced across repositories, identifies which repositories depend on a given image, and surfaces vulnerability impact before changes are made.
Tracks GitHub Actions used across repositories, including consumer locations and pinning information, to assess cross-repo impact of changes.
Indexes Helm chart dependencies across repositories, enabling cross-repo impact analysis for chart updates and version drift detection.
Monitors npm package dependencies across repositories, reports vulnerability advisories, and helps determine who is affected before bumping a package version.
Indexes Terraform module usage across repositories, showing which repositories consume a module and how tightly pinned they are.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@blastradius-mcpBefore I bump lodash, show me which repos depend on it and their pinned versions."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
BlastRadius
It remembers what every repository you open depends on, tells your agent who else is affected before it changes one, and watches those dependencies for vulnerabilities while nobody is asking.
Not a code graph. Excellent tools already index functions, classes and imports. BlastRadius indexes the other half — Docker images, Terraform modules, GitHub Actions, Helm charts, npm packages — across repository boundaries, and answers the question a single session cannot: if I bump this, who breaks?
What it actually produces
43 advisories from OSV. 9 that apply to your pinned versions.
[CRITICAL] vitest CVE-2026-47429
When Vitest UI server is listening, arbitrary file can be read and executed
reaches: 3.2.4 (installed version)
in: acme/checkout
[HIGH ] lodash CVE-2021-23337
lodash vulnerable to Code Injection via `_.template` imports key names
reaches: 4.17.21, ^4.17.21
in: acme/checkout, acme/notifications, acme/web
[HIGH ] vite CVE-2026-53571
vite: `server.fs.deny` bypass on Windows alternate paths
reaches: 5.4.19 (installed version)
in: acme/web
[MEDIUM ] lodash CVE-2025-13465 (2 advisory records)
lodash vulnerable to Prototype Pollution via array path bypass in `_.unset` and `_.omit`
reaches: 4.17.21, ^4.17.21
in: acme/checkout, acme/notifications, acme/web
critical: 1 high: 2 medium: 4 low: 2
10 advisory record(s) covering 9 distinct vulnerability(ies)Those two lodash entries are the point. They have no fixed version, so even an
exact 4.17.21 pin is still exposed — and three separate repositories carry it.
Nothing in a single-repo scan surfaces that.
Every line above is reproducible: ./verify.sh && ./run-capture.sh && blastradius alerts.
Related MCP server: MCP Workflow Engine
What it does unasked
Open a repo, ask for something ordinary — "bump react to 19" — and before the
agent reads a line of package.json, a hook has already told it:
acme/checkout(a separate repo) also depends onreact@^18.2.0, andlodashhere is shared withacme/notificationsandacme/checkouttoo.
Two repositories that were not open, not mentioned, and have no trace in the working directory. The agent never called a tool to find them.
Why hooks, not just MCP
MCP tools are model-elective — the agent may or may not call them. So the things that must always happen are hooks, which the harness runs whether the model thinks to or not:
Lane | Mechanism | Fires |
Push |
| Agent opens a manifest → cross-repo impact injected unprompted |
Capture |
| Session ends → unindexed manifests flagged for recording |
Pull | MCP tools | Agent asks: |
Watch | Daemon | OSV polling on an interval, with local alerts |
Only the asking is optional.
Extraction is the model's job
BlastRadius ships no manifest parsers. Regex-matching FROM lines gets
multi-stage aliases, templated base images and heredocs wrong; the agent reads
those correctly already. The hook decides when extraction is owed, the model
does it, BlastRadius stores and joins and watches the result.
The one exception is lockfiles, which are machine-generated and schema-stable — no judgement required, so no session required either.
Install
pip install blastradius-mcp
blastradius install # wires hooks + MCP server into Claude Code
blastradius link # puts the CLI on PATH, no venv activation needed
blastradius doctor # verifies it — by running the hooks for realOr as a Claude Code plugin, which wires the hooks and MCP server for you:
/plugin marketplace add harris-ahmad/blastradius-mcp
/plugin install blastradius@blastradiusThe plugin still needs the package — it declares hooks and an MCP server that
shell out to blastradius, so pip install blastradius-mcp comes first either
way. What it saves you is blastradius install and keeping the wiring current.
claude plugin details blastradius@blastradius puts its always-on cost at
~126 tokens per session; the hooks themselves are harness-side and cost
nothing until they fire.
git clone https://github.com/harris-ahmad/blastradius-mcp
cd blastradius-mcp && pip install .
blastradius install && blastradius doctorPrefer a plain install over -e unless you are working on the package itself:
an editable install resolves imports through src/ at runtime, and anything
that disturbs that path produces ModuleNotFoundError while the console script
sits there looking fine.
Then fill the index from the repositories you already have:
blastradius index ~/code # --dry-run first to see what it would readWithout this the tool is correct and completely silent for days. Capture runs
at Stop, after the reads, and cross-repo impact needs a second repository
before it has anything to say — so a fresh install shows you nothing until you
have opened two repos and gone back to the first. index runs one headless
Claude session per repository and lets the same Stop hook do the capture, so a
bootstrapped index is the same index the hooks would have built, only sooner.
On the fixture corpus it scores identically: 39/39 recall, 39/39 specs, 0 traps.
Everything is local: one SQLite file at ~/.blastradius/index.db. No account, no
server, no API key, nothing leaves your machine.
install merges into ~/.claude/settings.json rather than overwriting it —
your other hooks and settings survive, re-running never duplicates, and the
previous file is backed up first. uninstall reverses it cleanly.
Commands
blastradius index <dir> — bootstrap from repos on disk. --dry-run lists what
it would read, --limit N caps it, --force re-reads what is already indexed.
Sessions are read-only: Write, Edit and Bash are denied, so it cannot modify a
repository it was only asked to look at.
Command | Does |
| Who uses it, at which file and line, how tightly pinned |
| Shared artifacts ranked worst-pinned first, flagging version drift |
| Open advisories, which pins they reach, which repos carry them |
| Query OSV now; |
| Read lockfiles, making vulnerability matching exact |
| Poll on an interval, in the foreground |
| Run the watcher in the background, across reboots |
| Pause it, resume it, remove it |
| What injection has spent on context, and what dedupe saved |
| Index and wiring state |
The MCP tools are blast_radius, hygiene and record_dependencies. type
disambiguates names shared across ecosystems: node is both a Docker image and
an npm package, and they are different rows with different blast radii.
Controlling what it does
blastradius config # what is active right now
blastradius config --init # write an example to ~/.blastradius/config.json{
"inject": {
"enabled": true,
"max_artifacts": 8,
"max_consumers": 5,
"types": ["terraform_module", "github_action"],
"only_when_shared": true,
"min_cve_severity": "medium"
},
"exclude": {
"repositories": ["acme/internal-*"],
"paths": ["vendor/**", "examples/**"],
"artifacts": ["registry.internal.*"]
}
}Injection spends context on every matching read, so it is tunable: narrow it to the artifact types you care about, raise the severity floor, or turn it off.
Because it is capped, what gets cut matters more than what fits. Artifacts
are ranked before truncation — an open advisory dominates, then breadth of use,
then version drift — so a package.json with fifty dependencies surfaces the
two that matter rather than the first eight alphabetically. Ranking costs two
batched queries, because this runs inside a five-second hook timeout.
The injected block is terse on purpose. Measured across the fixture corpus,
the compact format is 58% smaller than prose for identical facts — 202
characters per injection against 475. Three savings, largest first: the trailing
"call blast_radius before making a change" instruction is dropped entirely, since
it is identical every time and the bundled skill already teaches it; consumers go
inline rather than one indented line each; and a consumer's file path is
shortened against the file being read, because every repo's Dockerfile is
called Dockerfile.
blastradius .github/workflows/ci.yml
actions/checkout L5 → 5 repos: acme/checkout main UNPINNED deploy.yml:7 ·
acme/legacy-cron main UNPINNED nightly.yml:5 · acme/payments v4 partial
actions/setup-node L6 → 1 repo: acme/checkout v4 partial deploy.yml:8Set "format": "verbose" for the original prose form.
Repeats within a session are suppressed for dedupe_minutes (default 120).
An agent re-reads the same manifest constantly — before an edit, after an edit,
when re-checking — and the second injection tells it nothing the first did not.
Suppression expires rather than lasting forever, because a session id cannot be
fully trusted to be unique: six separate claude -p runs were observed sharing
one. Without the window, a single early injection would silence that file
permanently.
Injection needs the file to already be indexed, so a repo's first visit captures and the visits after it enrich. On a corpus BlastRadius has never seen, pass one records and pass two starts speaking.
blastradius cost shows what the tool is actually spending:
4 injection(s) across 2 session(s)
1,270 characters ≈ 334 tokens
318 characters each ≈ 84 tokens
4 repeat(s) suppressed within a session
≈ 334 tokens not spent re-telling the same thing
Most expensive files
736 ch 2x acme/web:package.jsonToken figures are estimates — Claude's tokenizer is not available locally, so this uses ~3.8 characters per token, which suits paths and version strings better than the usual prose ratio. The character counts are exact.
Exclusions govern capture as well as injection. Dependency names are usually dull, but a private repository name or an internal registry hostname is not, so excluded repositories, paths and artifacts are never written to the index in the first place. Every setting has a working default — an absent config file behaves exactly as if this section did not exist, and a malformed one falls back to defaults rather than breaking a session.
The plugin also ships a skill that teaches when consulting the index is worth it — before a version bump, when pinning or removing a shared dependency — and how to read pinning quality, since a SHA-pinned consumer will not receive your change at all while an unpinned one gets it immediately.
How the alert filtering works
Advisories are matched against what your pins can actually resolve to.
Your pin | Advisory fixed in 4.17.21 | Why |
| not affected | exact, at the fix |
| affected | may still resolve to |
| not affected | floor already fixed |
| kept | unknowable — see below |
Lockfiles make it exact. A manifest says ^5.2.0, which permits 5.2.0 and
therefore every advisory affecting it. package-lock.json says 5.4.19, which
permits none of them. On the fixture corpus that is the difference between 13
vite alerts and 6. Reads package-lock.json (v1 and v2/v3) and yarn.lock;
pnpm needs a YAML parser and is not covered.
Uncertainty keeps the alert. A floating tag, a digest, a git ref, or an advisory with no usable range data all resolve to unknown, and unknown is treated as affected. Hiding a possible vulnerability is a far worse failure than showing one that turns out not to apply.
Severity comes from the CVSS v3.1 vector computed with the real formula, because OSV reports a vector far more often than a number. Only ecosystems OSV genuinely covers are monitored — GitHub Actions and npm. Docker images, Terraform modules and Helm charts are indexed but never reported as "no known CVEs", which would be a lie.
Extraction quality is measured, not asserted
Since extraction is delegated to a model, quality is the thing worth proving.
fixtures/ builds six local repositories that share artifacts and pin them
inconsistently, with the hard cases planted on purpose: multi-stage stage
aliases, ARG-templated bases, a FROM inside a heredoc, a registry with a
port, local module sources, workspace: and github: protocols, and redis
appearing as three different artifact types across three repos.
./fixtures/make-fixtures.sh
./run-capture.sh # six headless sessions via `claude -p`
python3 fixtures/grade.pyrecall 39/39 (100%)
specs 39/39 (100% kept intact)
traps 0 false positive(s)recall — of the artifacts genuinely present, how many were found
traps — stage aliases, local paths and heredoc text wrongly recorded
specs — how many version strings survived intact
specs is the one that matters. A model that quietly normalises ^18.2.0 to
18.2.0 scores full recall while destroying the exact signal the tool reports
on. grade.py exits non-zero on a miss, a trap, or a stripped operator —
all three, because the number that only gets printed is the number that stops
being read.
Scoring a real run needs Claude, so it stays a local step. What CI does check
is everything around it: fixtures/check-corpus.py generates the corpus and
fails if make-fixtures.sh and expected.json have drifted apart, and
tests/test_grader.py scores a synthetic index built from the ground truth so
the grader cannot quietly start reporting a number nobody can check.
Limitations
npm cross-repo impact is weaker than infrastructure. Packages install independently per repo, so a shared npm dependency is a drift and CVE-exposure signal rather than a breakage signal. Terraform modules, Actions and base images are where a shared artifact genuinely is the same thing.
pnpm lockfiles are not read.
The index only knows repos you have opened with BlastRadius installed.
Status
Early, but complete across all four lanes and verified end to end on two machines. 322 tests, run on Python 3.11–3.13 in CI, which also builds the distributions and installs the wheel on a machine that has never seen the source.
Next: pnpm lockfiles, and measuring what capture costs in context the way injection already is.
Deliberately not built: a web viewer. The read-side UI is what made the original BlastRadius something you had to deploy, and a local tool that answers through the agent does not need one.
Development
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
python -m pytest -q # `python -m` beats a global pytest shadowing the venv
python scripts/check-packaging.py # version agrees across all three manifests
python fixtures/check-corpus.py # generator and ground truth still match
claude plugin validate . # marketplace + plugin manifestsReleases are cut by tag. The version lives in three files — pyproject, the plugin manifest, and the marketplace entry, whose version is what gates a plugin update — so bump all three at once and let CI check they agree:
python scripts/check-packaging.py --set-version 0.2.0
git commit -am "Release 0.2.0" && git tag v0.2.0 && git push origin main v0.2.0The workflow checks the tag against the packaged version before it builds, and publishes through a PyPI trusted publisher. There is no API token anywhere in the repo. PyPI never lets a version be re-used, so a number spent is spent.
Two things that bite, both now detected automatically:
After git pull, run pip install . again. A plain install copies the
package, so pulling updates the source and leaves the running code untouched —
silently. doctor detects this and run-capture.sh refuses to run against a
stale build.
Prefer a plain install over editable when testing. An editable install puts
only a .pth in site-packages and resolves imports through src/ at runtime, so
anything disturbing that path produces ModuleNotFoundError: No module named 'blastradius' while the console script sits there looking fine.
When a hook stays quiet — which it does by design — BLASTRADIUS_DEBUG=1
narrates every decision to stderr rather than passing through silently.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityAmaintenanceDependency intelligence for AI agents. CVE scanning, health checks, upgrade planning.95172Apache 2.0
- FlicenseNot gradedqualityDmaintenanceProvides AI coding agents with dependency analysis, impact detection, and build verification tools.
- AlicenseAqualityCmaintenanceEnables AI agents to map cross-repository dependencies, detect breaking changes in API contracts, and assess impact across services.10MIT

coderadiusofficial
AlicenseNot gradedqualityAmaintenanceEnables AI agents to query architecture context, data contracts, and blast radius to prevent cross-repo architectural breakage before merging.30Apache 2.0
Related MCP Connectors
Software component catalog: search your org's services, docs, APIs, dependencies, and ownership.
Package intelligence for AI agents across npm, PyPI, crates.io and deps.dev. No API keys.
Generate SBOMs, scan vulnerabilities, and analyze dependencies from local projects or Git repos.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/harris-ahmad/blastradius-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server