Skip to content

Releasing

Releases are driven by GitHub releases. Publishing a release with a tag like v1.2.3 triggers the Release workflow. That workflow builds the Docker image for linux/amd64 and linux/arm64 and pushes it to ghcr.io/mattoddie/unifi-mcp. Nothing is published by merging to main alone.

The project follows Semantic Versioning. Its public API is the set of tool names, their arguments and the environment variables:

Change Bump Examples
Breaking major (2.0.0) Renaming or removing a tool, argument or variable; changing a default so that more is allowed
New features minor (1.3.0) New tools, toolsets, arguments or prompts
Fixes patch (1.2.4) Bug fixes, compatibility fixes, docs, dependency updates

While the version is 0.x, minor bumps may contain breaking changes. Call them out in the release notes.

The version comes from the tag. package.json stays at 0.0.0-dev in the repository, and release builds stamp the tag’s version into the image. The server reports it to MCP clients and prints it on its first log line.

  1. Check main is green on CI.

  2. Update the changelog. In a small PR, move the Unreleased entries in CHANGELOG.md under a new heading, ## [1.2.0] - YYYY-MM-DD, and update the comparison links at the bottom. Merge it.

  3. Publish the release. Use either the CLI or the web UI.

    With the CLI:

    Terminal window
    gh release create v1.2.0 --target main --title "v1.2.0" --generate-notes

    Or in the web UI: Releases → Draft a new release → Choose a tag → type v1.2.0 → Create new tag on publish, target main. Click Generate release notes, edit them as needed, then Publish release.

  4. Watch the workflow. Open Actions → Release. It takes a few minutes. When it finishes, the release notes gain a Container image section with the pull command, digest and tags.

  5. Check the image: docker pull ghcr.io/mattoddie/unifi-mcp:1.2.0.

Release notes are generated from merged PR titles and grouped by label. The groups are set in .github/release.yml. Label PRs breaking, enhancement, new-tool, bug, compatibility, documentation or dependencies to sort them, or skip-changelog to leave a PR out.

To test a release candidate, use a pre-release tag and tick Set as a pre-release:

Terminal window
gh release create v1.3.0-rc.1 --target main --prerelease --generate-notes

Pre-releases are published only under their exact version (ghcr.io/mattoddie/unifi-mcp:1.3.0-rc.1). They never move latest, 1 or 1.3.

Step Detail
Validate the tag Must match vMAJOR.MINOR.PATCH with an optional -prerelease suffix, otherwise the workflow fails before building.
Build docker buildx for linux/amd64 and linux/arm64. The test suite runs inside the build, so failing tests mean no image.
Tag X.Y.Z always. For stable releases also X.Y, X (from 1.0.0 on) and latest.
Push To ghcr.io/mattoddie/unifi-mcp using the workflow’s GITHUB_TOKEN. No personal tokens are needed.
Supply chain Attaches an SBOM and SLSA provenance to the image, and pushes a signed build provenance attestation (gh attestation verify).
Release notes Appends the pull command, digest and tags.
  • The workflow failed for a transient reason: re-run it from the Actions tab. It’s safe to re-run, and it pushes the same tags again.
  • The release was wrong (bad code or wrong tag): don’t move or reuse a published tag, because people may already have pulled it. Fix the problem on main and publish the next patch version. You can delete the bad GitHub release and mark it as such in the changelog, but leave the image tag alone.
  • Wrong tag format (e.g. 1.2.0 without the v): delete the release and tag (gh release delete 1.2.0 --cleanup-tag) and publish again with the right tag.

Two rulesets protect the repository. You can view and edit them under Settings → Rules → Rulesets.

Protect main (the default branch):

  • Changes land only through pull requests. Nobody can push directly, force-push or delete the branch, and there are no bypasses.
  • The CI checks Test (Node 22), Test (Node 24) and Docker image must pass, and the branch must be up to date with main.
  • Review threads must be resolved before merging. The only merge method is squash.
  • No approving review is required yet, because GitHub doesn’t let authors approve their own pull requests and the project has a single maintainer. Raise this when there are more maintainers.

Protect release tags (v*):

  • Only repository admins can create, move or delete version tags, so only maintainers can publish releases. Published versions can’t be re-pointed.

New GHCR packages normally start private, and GitHub doesn’t offer an API to change this. This package became public automatically because it’s linked to this public repository. If a new package ever starts private, open the package page (Your profile → Packages → unifi-mcp → Package settings) and choose Change visibility → Public under Danger Zone.

The package links to the repository automatically through the image’s org.opencontainers.image.source label, which makes it show in the repository sidebar.