Introducing OpenACA: Agent Composition Analysis
Your dependency scanner can't see your agent stack. OpenACA is an open-source scanner that inventories the MCP servers, plugins, skills, and dependencies your AI agents pull in — and matches them against known security advisories.
An account executive on your team wires up an AI assistant. To make it useful for closing deals, they connect it to a few MCP servers — one for the CRM, one for the data warehouse, one they found in a Slack thread that “just works.” They add a skill that drafts follow-up emails and a connector for the shared drive.
None of it went through review. There is no pull request for an agent’s configuration. No one signed off on the MCP server that now holds a token to the CRM and can reach the data warehouse. It runs on a laptop that also has the VPN.
It’s not just engineers anymore. The people wiring AI agents into company systems now include sales, support, ops, and finance — and the surface area of who can introduce a risky component grew with them. This is normal. It is also invisible to every tool you currently run.
Why now
The number of operators went up. So did the number of components — and almost none of it is reviewed.
A March 2026 study of 177,000 MCP tools found that the share of action-capable tools rose from 27% to 65% over the 16-month period it sampled.
In April 2026, Censys counted 12,520 internet-accessible MCP servers; a separate measurement study found roughly 40% of remote MCP servers expose their tools with no authentication at all. When researchers pointed one automated auditing tool at nearly 40,000 open-source MCP-server repositories, it surfaced 106 confirmed vulnerabilities — with 67 CVE IDs assigned to date — in a single run. The supply is large, growing fast, and largely unaudited.
Your dependency scanner can’t see this
Software Composition Analysis (SCA) is now a standard part of the security
stack. Your scanner reads package.json, requirements.txt, the lockfiles,
resolves the transitive tree, and matches every package against known
advisories. It works because the composition is declared in a place the scanner
knows how to read.
Agents compose themselves differently. An agent’s “dependencies” are MCP
servers declared in mcp.json, plugins declared in a marketplace manifest,
skills that are just markdown-plus-frontmatter, hooks wired into settings, and —
underneath all of that — ordinary npm and PyPI packages. Your SCA tool reads
exactly one of those surfaces, and only when the agent’s components happen to
ship a lockfile.
The shape of the problem is the same as SCA. The surfaces are new:
| Software Composition Analysis | Agent Composition Analysis | |
|---|---|---|
| Reads | package.json, lockfiles | mcp.json, plugin manifests, skills, hooks, settings |
| Unit | library / package | MCP server, plugin, skill, hook, dependency |
| Identity | name@version from a registry | often no registry: npx one-liners, uvx unpinned, local binaries |
| How risk enters | a transitive dependency | a plugin that bundles an MCP server that shells out |
| Matches against | CVE / GHSA / OSV | the same advisories — plus agent-specific records |
That last row needs a caveat. For components that resolve to packages — MCP servers on npm or PyPI, and their dependencies — the advisories already exist; what’s missing is the layer that reads the agent’s surfaces and connects what’s installed to what’s known. For skills, hooks, and plugins, advisory coverage barely exists yet. So the work is twofold: match the packaged components to the advisories that already cover them, and for everything else, start with visibility and an open corpus to fill the gap.
That layer is what we’re releasing today. We call it Agent Composition Analysis, and the open-source scanner is OpenACA.
What OpenACA does
OpenACA runs in four steps, each building on the last.
1. Identity resolution. Agent components rarely arrive as a clean
name@version. An MCP server might be an npx -y @scope/pkg one-liner, a
uvx invocation with no pin, or a path to a local binary. OpenACA resolves
these into stable, matchable identities — so a component you can’t cleanly name
still shows up in the inventory, and one you can name becomes a coordinate to
match advisories against.
2. Composition graph. It maps the whole stack — host → plugin → MCP server / skill / hook / dependency — so you see what’s actually wired into the agent, not just the top-level names someone typed into a config.
3. Risk attribution. When a finding lands, OpenACA tells you what introduced it. A vulnerable package pulled in by a plugin gets attributed to that plugin, so the fix has an owner.
4. Advisory intelligence. Components are matched against OSV.dev (CVE / GHSA / PYSEC / malicious-package records) at scan time, enriched with an open overlay corpus of agent-context metadata.
And it runs where components actually get added: as a CLI, a Claude Code plugin, and a GitHub Action that can fail a pull request the moment it introduces a component with an advisory-backed finding — so a risky MCP server gets caught in review, not six months later.
Here’s a real scan of a small project with one known-vulnerable MCP server:
$ openaca scan repo --target ./my-agent-repo
Inventory
repo ./my-agent-repo
└── direct components/
└── MCPs/ (4)
├── @cyanheads/[email protected] (stdio via npx) (from mcp.json) [! GHSA-3q26-f695-pp76]
├── custom-mcp-server (stdio, args hidden) (from mcp.json)
├── sketchy-mcp (stdio via uvx, unpinned) (from mcp.json)
└── [email protected] (stdio via uvx) (from mcp.json)
Findings
@cyanheads/git-mcp-server 1.1.0
location: ./my-agent-repo/mcp.json
fix: upgrade to >=2.1.5
HIGH GHSA-3q26-f695-pp76 fixed in 2.1.5 @cyanheads/git-mcp-server vulnerable to command injection in several tools [osv.dev]
Summary
Scanned 1 manifest, 4 components · advisories: 1 · posture: skipped
sources: osv.dev
Four MCP servers declared, all surfaced — including custom-mcp-server (whose
args are hidden) and sketchy-mcp (unpinned, so there’s nothing to match it
against, but you can still see it). The one pinned to a version with a known
command-injection advisory gets a HIGH finding with the fix version inline.
Try it
Install with one line:
curl -fsSL https://openaca.dev/install.sh | sh
Then point it at an agent config — a repo, or your local Claude setup:
openaca scan endpoint # scans ~/.claude by default
openaca scan repo --target . # scans a project's agent manifests
openaca bom repo --target . # emit an Agent BOM as JSON
The Claude Code plugin (/openaca:scan, /openaca:bom, /openaca:explain)
and the GitHub Action are both thin wrappers around this same CLI. The
quickstart has the
details.
What OpenACA is not
The limits matter as much as the capabilities:
- It’s not another content scanner. OpenACA doesn’t read the body of a skill or the implementation of an MCP server and apply rule-based or LLM heuristics to guess whether it’s malicious. It resolves each component’s identity and matches it against advisories that already exist — OSV.dev records plus a human-reviewed overlay corpus, each with cited evidence. The upside: a finding is a real, attributable match, not a verdict you have to second-guess. The flip side: a brand-new malicious component that nobody has reported yet has no advisory to match, so OpenACA won’t flag it on content alone. Heuristic content scanners cover that case — they’re complementary to this, not competitors.
- It reads what’s declared, not what runs. OpenACA inventories the components your config declares; it does not watch what an agent does at runtime, intercept tool calls, or block anything. It’s a map, not a fence — it tells you what’s installed and what’s known-risky, and acting on that is your call.
- A finding needs a matchable coordinate. A component OpenACA can pin to a
name and version gets matched against advisories. One that can’t — an
unpinned
uvxinvocation, a local binary — still shows up in the inventory, but there may be nothing to match it against. Visibility first; matching where the coordinates exist. - It reads the surfaces it knows today. V0 parses MCP, Claude Code plugin, skill, hook, command, and agent manifests. Other agent ecosystems are on the roadmap, not in the box yet.
What’s next
The near-term work is expanding coverage: more parsed ecosystems, deeper transitive composition, and a growing overlay corpus.
We also want OpenACA to be a place where evidence from specialized MCP and skill scanners can land in a common shape, tied back to the component that triggered it. The scanner ecosystem is moving quickly; the useful thing is not one more isolated verdict, but a shared inventory and attribution layer.
For teams that want this running continuously across many developer machines rather than ad hoc on a laptop, OpenACA Cloud is in private design-partner preview.
The open scanner is the foundation, and it’s available now.
The ask
Run OpenACA on your own stack — the real one, with the MCP server you added six months ago and forgot about.
If it misses something, tell us: an identity it couldn’t resolve, a finding that doesn’t make sense, a surface your agents actually use that it didn’t parse. Open an issue — that feedback is how the coverage gets better.
And if you’re trying to get your arms around this inside a team — what agents people are using, what components they pull in, what should be reviewed before it spreads — would love to compare notes. Reach us at [email protected].
- Scanner: github.com/open-agent-security/openaca
- Docs: openaca.dev/docs
- Issues: github.com/open-agent-security/openaca/issues