Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, email [email protected] and we’ll put it right.

Attest your MCP package's build provenance

What we checked

We looked for build provenance: a signed attestation, published alongside your package, that cryptographically binds the artifact to the source commit and the CI run that built it. The signal passes only when that attestation exists and verifies. The other outcomes (no attestation, an attestation that fails verification, an unpublished version, or an inconclusive check) mean:

Cryptographically verified build provenance (signed and bound to the source repository)
Provenance check failed: no build-provenance attestation is published.
A provenance attestation was published but failed verification
Provenance check failed: the declared version isn't published, so its provenance can't be verified.
Build provenance not yet verified.

Why it matters

A registry account proves who uploaded a package; it doesn’t prove where the bytes came from. Build provenance closes that gap. A signed attestation lets anyone confirm the artifact was built from a specific commit in your public repository, by your CI, and hasn’t been swapped or tampered with since. That defends against a stolen publish token, a compromised maintainer laptop, or a malicious mirror, none of which can forge a valid signature bound to your repo.

How to fix it

Publish from CI and emit a signed attestation as part of the publish step. The mature, turnkey paths today are npm and PyPI, both built on Sigstore and OIDC: no long-lived signing keys to manage.

name: publish
on:
release:
  types: [published]
jobs:
publish:
  runs-on: ubuntu-latest
  permissions:
    contents: read
    id-token: write   # required for provenance (OIDC)
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 20
        registry-url: https://registry.npmjs.org
    - run: npm ci
    # --provenance generates and publishes a signed attestation
    - run: npm publish --provenance --access public
      env:
        NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

For npm, also confirm your package.json repository field points at the same public repo the workflow runs in; the attestation binds to it, and a mismatch means the attestation exists but fails verification.

How we re-check

We re-fetch the attestation for your latest published version on our next crawl. Once a valid, repo-bound attestation is present, the signal flips to verified on the following score refresh.

Give this to your AI

Paste this into Claude Code (or any coding agent) from inside your server's repository. It states the failing signal, the outcome we re-check for, and the format the fix has to take.

Prompt
Context: this repository publishes an MCP server. VerifyMCP's build
provenance check failed, which means the published package carries no
signed attestation binding it to the source commit and CI run that built
it, or the attestation exists but doesn't verify.

Goal: the published artifact carries a valid, repo-bound attestation, so
the next crawl records verified provenance.

Do this:
1. Identify the registry you publish to (npm, PyPI, NuGet, Go modules,
   crates.io, or an OCI container image).
2. For npm: publish from CI with `id-token: write` permission and run
   `npm publish --provenance` (add `--access public` only if the package
   is meant to be public and is not already); confirm the `repository`
   field in `package.json` points at the same public repo the workflow
   runs in, since a mismatch stops the attestation verifying.
3. For PyPI: configure Trusted Publishing (OIDC) and publish with
   `pypa/gh-action-pypi-publish`, which emits PEP 740 attestations.
4. For NuGet, Go, or crates.io: there is no native equivalent of
   repo-bound build provenance today (NuGet package signing proves the
   signer, not the build; Go relies on the `go.sum` checksum database;
   crates.io has no mechanism). Say so plainly rather than
   approximating one.
5. If you ship an OCI container image, sign and attest it with Sigstore
   `cosign` (e.g. `cosign attest`).
6. Prepare the release, then stop and let me run the publish myself, since
   the check reads the published attestation.

Rules:
- Never run the publish command (`npm publish`, `twine upload`, `dotnet nuget
  push`, `cargo publish`, a release tag that triggers one) yourself. A
  published version is permanent and notifies every downstream consumer:
  prepare the change, show me the diff, and let me publish it.
- Never fabricate, hand-craft, or hardcode an "attestation" file; it must
  come from a real signing step tied to the actual CI run and commit.
- If the registry or ecosystem genuinely has no provenance mechanism, say
  so in your report rather than claiming the signal now passes.
- Ask me before changing where or how the package is published (e.g.
  moving publishing into CI) if that touches secrets or release process
  you don't control.

Report back: the workflow files you changed, the registry involved, and
how I can verify the attestation myself (e.g. the provenance link on the
npm package page, or the PyPI attestations tab).

Reference: https://verifymcp.io/docs/packages/build-provenance

Written by Stuart Blackler · Last reviewed 30 June 2026.