Publish an MCP server: provenance and CI
Publishing is where most of a server’s trust score is won or lost. The code can be excellent, but if the published artifact can’t be tied back to a source commit, or ships without a lockfile or a licence, VerifyMCP has no way to distinguish it from something an attacker rebuilt. A high score comes down to five things: a declared source repository and licence, a committed lockfile, no install scripts, and releases cut from CI with build provenance attached. This guide covers those cross-cutting concerns, which apply to every ecosystem. The language-specific mechanics (which files to write, which publish command to run) live in the per-ecosystem package guides.
Declare the source and licence
Two fields do a disproportionate amount of work. A verifiable source repository in your manifest is what lets a reader move from the published artifact to the code that produced it, and it underpins the lockfile, licence and security-policy checks. An OSI-approved licence tells users they can actually use what you shipped. Set both before your first release:
- Declare a repository so the artifact points at real, browsable source.
- Declare a licence with a recognised SPDX identifier, not a bespoke string.
Ship a lockfile, skip install scripts
A committed lockfile pins your full dependency tree,
so installs are reproducible and tampering is detectable. Publish it alongside
the manifest rather than gitignoring it. Separately, avoid
install-time scripts: code that runs on
npm install (or the equivalent) is arbitrary code execution on every
consumer’s machine, and it costs you points for good reason.
Build provenance from CI
Build provenance (SLSA-style attestations) cryptographically ties the artifact you publish to the exact commit and build that produced it. The cheapest way to get it is to stop publishing from a laptop and publish from CI instead, with the attestation generated in the same job.
The shape is the same across ecosystems: a GitHub Actions workflow that triggers
on a version tag, builds the artifact, and publishes with provenance enabled.
Grant the job id-token: write and contents: read, use the registry’s native
provenance flag (for example npm publish --provenance), and let the OIDC token
from Actions sign the attestation. No long-lived signing key to rotate or leak.
Do I have to publish from CI?
For provenance, effectively yes. You can publish from a laptop, but a repo-bound attestation can only be produced by a build whose identity a verifier trusts, which in practice means CI signing with a short-lived OIDC token. Publishing from a local machine gives you no way to prove the artifact matches the source, so the provenance signal stays at zero. The lockfile, licence and repository signals don’t need CI; provenance is the one that does.
A publishing checklist
Before you tag a release, confirm:
- Manifest declares a public source repository.
- An OSI licence is present and SPDX-identified.
- A lockfile is committed and published.
- No install scripts run on install.
- The release is cut from CI with build provenance attached.
None of this is extra work for a careful maintainer. Build these habits into your first release and you avoid the far larger job of reworking a published package later, and explaining a low score while you do.