How to publish an MCP server to PyPI using token or OIDC auth
Gabriel Mahia walks through two GitHub Actions workflows for publishing a Python MCP server to PyPI — one using an API token stored as a secret, and one using keyless OIDC (Trusted Publisher) authentication — illustrated with packages from the East Africa AI Stack.
Score breakdown
The article provides a concrete, error-annotated reference for the two officially supported PyPI publishing paths for MCP servers, including the keyless OIDC method that removes the need to store long-lived API tokens in GitHub secrets.
- 01Two publishing methods are covered: API token (stored as a GitHub Actions secret) and OIDC Trusted Publisher (keyless, no stored credentials).
- 02OIDC authentication requires `permissions: id-token: write` in the workflow and a one-time Trusted Publisher registration on the PyPI project settings page.
- 03Both workflows use `pypa/gh-action-pypi-publish@release/v1` and trigger on `push: tags: ["v*"]`.
Gabriel Mahia presents a step-by-step guide for distributing a Python MCP (Model Context Protocol) server on PyPI, covering two distinct publishing approaches. An MCP server is described as a Python package that exposes tools to AI assistants like Claude; once installed via `pip`, any MCP-compatible AI can call those tools. The article uses four packages from the East Africa AI Stack — `bima-mcp`, `mkopo-mcp`, `soko-mcp`, and `sifa-mcp` — as concrete examples of the pattern.
Both workflows run on `push: tags: ["v*"]` and build with `python -m build` using Python 3.11.
The **token method** involves generating an API token at `pypi.org/manage/account/#api-tokens`, storing it as a GitHub Actions secret named `PYPI_API_TOKEN`, and referencing it via `password: ${{ secrets.PYPI_API_TOKEN }}` in the `pypa/gh-action-pypi-publish@release/v1` action. The **OIDC method** eliminates stored credentials entirely: the publisher is registered once on the PyPI project settings page (supplying the GitHub owner, repo name, workflow filename, and optional environment name), and the workflow gains `permissions: id-token: write` — no `password:` line is needed. Both workflows run on `push: tags: ["v*"]` and build with `python -m build` using Python 3.11.
The article also covers the recommended project layout (`src/{package_name}/` with `__init__.py` and `main.py`), the correct `pyproject.toml` build-backend (`setuptools.build_meta` — explicitly not `setuptools.backends.legacy:build`), a `[project.scripts]` entry so the server runs as a CLI command after `pip install`, and a troubleshooting table mapping common errors (403, 400, `ModuleNotFoundError`, OIDC 403) to their causes and fixes. All 12 packages in the East Africa AI Stack are stated to use this pattern.
Key facts
- 01Two publishing methods are covered: API token (stored as a GitHub Actions secret) and OIDC Trusted Publisher (keyless, no stored credentials).
- 02OIDC authentication requires `permissions: id-token: write` in the workflow and a one-time Trusted Publisher registration on the PyPI project settings page.
- 03Both workflows use `pypa/gh-action-pypi-publish@release/v1` and trigger on `push: tags: ["v*"]`.
- 04The correct build-backend is `setuptools.build_meta` — the article explicitly warns against using `setuptools.backends.legacy:build`.
- 05The recommended project layout uses a `src/` directory; missing it causes a `ModuleNotFoundError` at runtime.
- 06A `[project.scripts]` entry in `pyproject.toml` exposes the MCP server as a CLI command after `pip install`.
- 07All 12 packages in the East Africa AI Stack use this pattern; full source is at gabrielmahia.github.io.
Topics
Summary and scoring are generated automatically from the original article. We always link back to the publisher and never republish images or paywalled content. Last processed Jun 9, 2026 · 17:05 UTC. How this works →