The release checklist for mcp-modal. A release lands in three places β keep them in
sync: PyPI (the package), the
MCP Registry (server.json), and
Glama (auto-indexed from GitHub).
One-time setup (the PyPI trusted publisher, claiming the Glama listing) is already done and intentionally not repeated here β see Automated publishing for what that setup is.
Publishing is automated. Just bump the version and push a tag β GitHub Actions does PyPI and the MCP Registry; Glama re-indexes from the push:
# bump the version in the 3 spots below, then:
git commit -am "Release vX.Y.Z: β¦" && git tag -a vX.Y.Z -m "vX.Y.Z" && git push --follow-tagsUse an annotated tag (
git tag -a).git push --follow-tagsonly pushes annotated tags β a lightweightgit tag vX.Y.Zwould stay local and the workflow would never fire. (Or push the tag explicitly:git push origin vX.Y.Z.)
The .github/workflows/publish.yml workflow fires on the
vX.Y.Z tag, builds with uv, and publishes to PyPI (Trusted Publishing / OIDC) and the
MCP Registry (mcp-publisher login github-oidc) β no tokens stored anywhere. You can also
run it manually from the Actions β Publish β Run workflow button (workflow_dispatch),
which is what you do for a tag that was pushed before the workflow existed.
The manual uv publish / mcp-publisher publish commands below remain valid as a fallback.
.github/workflows/publish.yml releases to PyPI and the MCP Registry on every v* tag (or
manual dispatch), authenticating entirely through GitHub Actions OIDC. The one-time setup it
depends on:
- PyPI Trusted Publishing β at
pypi.org/manage/project/mcp-modal/settings/publishing,
add a publisher with: owner
george-bobby, repositorymcp-modal, workflowpublish.yml, and leave the environment field blank (the workflow runs in the default context β no GitHub environment to create). If you later want a manual approval gate before each publish, create a GitHub environment, put its name in both the PyPI publisher and thepypijob'senvironment:key.
With that in place, a tag push (or manual run) publishes both registries. The registry job
needs: pypi, so the MCP Registry is only updated after the PyPI version is live.
The version lives in three places and they must all match (the registry rejects a
server.json whose packages[].version isn't on PyPI yet):
- pyproject.toml β
version = "X.Y.Z" - server.json β top-level
"version"andpackages[0].version
rm -rf dist # avoid re-uploading stale artifacts from a previous release
uv build # writes dist/mcp_modal-X.Y.Z-py3-none-any.whl + .tar.gz
uv publish # uploads dist/* to PyPIuv publish reads the token from UV_PUBLISH_TOKEN (or ~/.pypirc). To pass it inline:
uv publish --token pypi-β¦. Re-publishing an existing version fails β bump first.
mcp-publisher publishes the server.json in the current directory.
mcp-publisher validate # optional: sanity-check server.json before pushing
mcp-publisher login github # re-auth when the session has expired
mcp-publisher publish # push server.json to the registryThe PyPI release from step 2 must already be live, since the registry validates the referenced package version.
Glama re-indexes from the GitHub repo automatically β there's no separate publish command.
Just push to main:
git commit -am "release vX.Y.Z" && git tag -a vX.Y.Z -m "vX.Y.Z"
git push --follow-tags # --follow-tags only pushes annotated tags; use `git tag -a`glama.json only needs editing when maintainers change. If the listing looks stale after a push, trigger a manual refresh from the Glama dashboard.
uvx [email protected] # pulls the fresh version from PyPI in a clean env; Ctrl-C to exit the stdio server
claude mcp get mcp-modal # confirm the client still connects