Blog · · Vinod Kone

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 AnalysisAgent Composition Analysis
Readspackage.json, lockfilesmcp.json, plugin manifests, skills, hooks, settings
Unitlibrary / packageMCP server, plugin, skill, hook, dependency
Identityname@version from a registryoften no registry: npx one-liners, uvx unpinned, local binaries
How risk entersa transitive dependencya plugin that bundles an MCP server that shells out
Matches againstCVE / GHSA / OSVthe 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 uvx invocation, 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].