Webhook icon
Schedule icon
Parallel icon
Sequential icon
Request icon
Loop icon
Query icon
If icon
Log icon
SlackIncomingWebhook icon
Fail icon

MCP Server Supply-Chain Audit with OSV, the MCP Registry and DuckDB

Check pinned MCP servers against OSV.dev and the official MCP Registry, rank CVEs and version drift in DuckDB, alert Slack, and gate CI changes.

Categories
AI

MCP servers run with the same permissions as the AI agent that calls them: file system access, shell, tokens for GitHub or your cloud. They ship as ordinary npm, PyPI and Go packages, and several of the most used ones have had high and critical advisories (path traversal in the reference filesystem server, OS command injection in mcp-remote, DNS rebinding and session injection in the Python SDK). This flow keeps an inventory of the MCP servers your team allows, with the exact versions you pinned, and checks it against OSV.dev and the official MCP Registry every day and whenever the agent configuration changes.

How it works

  1. Triggers. A Webhook trigger (on_mcp_config_change) lets a CI job POST the inventory parsed from .mcp.json or your agent config whenever it changes. A daily Schedule re-audits the same inventory, because advisories get published against versions you already run.
  2. collect (Parallel) runs two independent branches:
    • vulnerabilities (Sequential): osv_batch sends one OSV.dev querybatch request for every pinned package, then the advisories Loop fetches the full advisory for each distinct vulnerability id to get its severity, CVE alias and fixed versions.
    • registry (Loop): for each server that has a registry name, latest_release asks the official MCP Registry for its latest release and status (active, deprecated, deleted).
  3. build_report uses DuckDB to join the inventory, the OSV batch answer, the advisories and the registry answers into one row per server: advisory count, worst severity, CVE list, the lowest version that fixes all of them, the registry's latest version, and a verdict (VULNERABLE, DEPRECATED, OUTDATED, OK).
  4. has_findings (If) logs the findings, posts them to Slack when notify_slack is true, and fails the execution through gate when any server reaches the fail_on_severity threshold. When everything is clean it logs a single all-clear line.

What you get

  • One table of every MCP server your agents can start, with real CVE ids and the version to upgrade to.
  • Version drift against the official MCP Registry, and a flag for deprecated or deleted servers.
  • A Slack message listing only the servers that need attention.
  • An optional CI gate: a webhook caller gets a failed execution when a CRITICAL or HIGH advisory is present.
  • No API keys needed for the audit itself: OSV.dev and the MCP Registry are public.

Who it's for

  • Security and platform teams rolling out Claude Code, Cursor, Copilot or in-house agents that load MCP servers.
  • AI platform engineers who maintain an approved list of MCP servers.
  • DevSecOps teams who want MCP servers covered by the same dependency scanning as application code.

Why orchestrate this with Kestra

  • Event-driven and scheduled runs share one flow, so a config change and a new advisory are caught by the same logic.
  • Parallel branches and Loops make the HTTP fan-out declarative, with per-iteration outputs visible in the UI.
  • DuckDB keeps the ranking and verdict rules in plain SQL that a security engineer can read and change.
  • Executions keep a history of every audit, and the Slack webhook URL stays masked as a secret.

Prerequisites

  • Kestra 2.0 with the DuckDB (plugin-jdbc-duckdb) and Slack (plugin-slack) plugins.
  • Outbound HTTPS to api.osv.dev and registry.modelcontextprotocol.io.
  • A Slack incoming webhook if you want alerts.

Secrets

  • SLACK_WEBHOOK_URL: Slack incoming webhook that receives the findings (required only when notify_slack is true).
  • MCP_AUDIT_WEBHOOK_KEY: key that guards the webhook URL your CI calls (required for the webhook trigger).

Quick start

  1. Create the SLACK_WEBHOOK_URL and MCP_AUDIT_WEBHOOK_KEY secrets.
  2. Replace the default inventory with the MCP servers your agents use and the versions you pinned. The defaults are real packages at old versions so the first run shows findings.
  3. Click Execute. Set notify_slack to false for a dry run that only logs.
  4. From CI, POST {"inventory": [...]} to /api/v1/main/executions/webhook/company.security/mcp-server-supply-chain-audit/<MCP_AUDIT_WEBHOOK_KEY> whenever .mcp.json changes, and set fail_on_severity to HIGH or CRITICAL in the flow defaults to block risky changes.

How to extend

  • Open a GitHub issue or pull request per vulnerable server with the upgrade version.
  • Store each report in a warehouse table to track mean time to patch per server.
  • Add an AI task that reads the advisory details and explains whether your configuration is exposed.
  • Read the inventory straight from a Git repository with the Git plugin instead of the input.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.