Supply Chain · Transparency

MCP server SBOM security

A Software Bill of Materials (SBOM) is a machine-readable inventory of every package in your MCP server's dependency tree. For buyers evaluating whether to install a community MCP server, an SBOM provides a verifiable record of what they are getting — every package, every version, every license — before they run a single line of code.

What an SBOM contains

A CycloneDX or SPDX SBOM lists every component in your software, including transitive dependencies, with:

This makes it possible for buyers, security teams, and directory reviewers to evaluate your dependency tree without running npm install themselves.

Generating an SBOM for a Node.js MCP server

# CycloneDX format (JSON) — most widely supported
npx @cyclonedx/cyclonedx-npm \
  --output-format JSON \
  --output-file sbom.json \
  --package-lock-only

# SPDX format (for tooling that prefers SPDX)
npx @cyclonedx/cyclonedx-npm \
  --output-format XML \
  --output-file sbom.xml

# Inspect the SBOM component count
cat sbom.json | node -e "
  let d = '';
  process.stdin.on('data', c => d += c);
  process.stdin.on('end', () => {
    const sbom = JSON.parse(d);
    console.log('Components:', sbom.components?.length);
    const licenses = new Set(sbom.components?.flatMap(c =>
      c.licenses?.map(l => l.license?.id || l.expression) || []
    ));
    console.log('Unique licenses:', [...licenses].join(', '));
  });
"

Generating an SBOM for a Python MCP server

# Using CycloneDX for Python
pip install cyclonedx-bom
cyclonedx-py environment --output-format json --output-file sbom.json

# Or using Syft (supports both npm and pip)
syft dir:. --output cyclonedx-json=sbom.json

Where to commit and publish the SBOM

Commit sbom.json to the root of your repository. Update it on every release by adding a step to your release workflow:

name: Release
on:
  push:
    tags: ['v*']

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - name: Regenerate SBOM
        run: |
          npx @cyclonedx/cyclonedx-npm \
            --output-format JSON \
            --output-file sbom.json
          git config user.name "github-actions"
          git config user.email "actions@github.com"
          git add sbom.json
          git diff --staged --quiet || git commit -m "chore: regenerate SBOM for ${{ github.ref_name }}"
      - name: Create GitHub Release with SBOM
        uses: softprops/action-gh-release@v2
        with:
          files: sbom.json

How buyers use your SBOM

A security-conscious team lead evaluating your MCP server can load your SBOM into a vulnerability scanner to check for known CVEs without installing anything:

# Check SBOM against the OSV vulnerability database
npm install -g @google/osv-scanner
osv-scanner --sbom sbom.json

# Or using Grype
grype sbom:sbom.json

Teams with internal allowlisting policies can also verify that your dependency tree contains no packages on their blocklist before approving the MCP server for internal use.

SBOM diffing between releases

One of the most valuable uses of committed SBOMs is diffing between releases to understand exactly what changed in the dependency tree — not just in your code:

# Compare SBOMs between two releases
git show v1.2.0:sbom.json > sbom-v1.2.0.json
git show v1.3.0:sbom.json > sbom-v1.3.0.json

# Find added or changed packages
node -e "
  const old = JSON.parse(require('fs').readFileSync('sbom-v1.2.0.json'));
  const new_ = JSON.parse(require('fs').readFileSync('sbom-v1.3.0.json'));
  const oldMap = Object.fromEntries(old.components.map(c => [c.name, c.version]));
  const newMap = Object.fromEntries(new_.components.map(c => [c.name, c.version]));
  for (const [name, ver] of Object.entries(newMap)) {
    if (!oldMap[name]) console.log('ADDED:', name, ver);
    else if (oldMap[name] !== ver) console.log('CHANGED:', name, oldMap[name], '->', ver);
  }
  for (const name of Object.keys(oldMap)) {
    if (!newMap[name]) console.log('REMOVED:', name);
  }
"

Anthropic's Skills Directory now accepts CycloneDX SBOM files as supporting evidence for security review submissions. Providing a current SBOM reduces review turnaround time because reviewers can run automated dependency analysis rather than installing and auditing manually.

SkillAudit findings

MEDIUM No sbom.json or sbom.xml file found in repository root — buyers cannot evaluate dependency tree without installing
MEDIUM SBOM present but older than the most recent release — dependency tree may have changed without SBOM update
MEDIUM SBOM does not include transitive dependencies — only direct dependencies listed, full tree not auditable

Run a SkillAudit scan on your MCP server to check SBOM presence, currency, and completeness. SkillAudit also cross-references your SBOM components against the OSV vulnerability database. See also: MCP server supply chain audit and supply chain risk deep-dive.