14,000 Python Developers Installed My Go Binary via pip. Here's How.
How to distribute a Go binary on PyPI and npm so Python and Node developers can install it with pip/npx. Platform-specific wheels, optionalDependencies, and a one-tag release pipeline. 12x download multiplier from distribution alone.
- categories
- Go Tools Open-Source
- published

Your Go binary is on GitHub Releases. Congratulations. Go developers will find it with go install. Everyone else won’t.
Python developers search PyPI. Node developers search npm. They don’t browse GitHub Releases pages. If your tool isn’t where they look, it doesn’t exist to them.
I put a Go binary on PyPI. It gets 14,234 downloads. The same binary on GitHub Releases: 2,111. A 12x multiplier from distribution alone.
Here’s the entire technique.
The Numbers
| Channel | Downloads |
|---|---|
| pip (mcp-assert) | 14,234 |
| pip (pytest plugin) | 5,285 |
| npm CLI | 1,862 |
| npm vitest/jest/bun plugins | 2,865 |
| GitHub Releases | 2,111 |
| Docker | 306 |
| Total | 25,663 |
GitHub Releases alone: 2,111. Adding pip and npm: 25,663. Same binary. Same tool. Different shelf.
PyPI: Go Binary in a Python Wheel
A Python wheel is just a zip file with metadata. It doesn’t have to contain Python code. It can contain a binary and a 36-line script that runs it.
The Python “package” (36 lines)
| |
That’s it. Locate the binary. Run it. Pass through args. Exit with its code.
The pyproject.toml
| |
The [project.scripts] entry means pip install mcp-assert creates a mcp-assert command that calls your main() function. The user types mcp-assert in their terminal and gets your Go binary.
Building platform-specific wheels
This is the key trick. You build one wheel per platform, each containing the correct binary:
| |
Each wheel is tagged with its platform (macosx_11_0_arm64, manylinux2014_x86_64, etc.). When a user runs pip install mcp-assert, pip downloads only the wheel matching their platform. They get a native binary without knowing it’s not Python.
Upload
| |
Six wheels go up. pip handles the rest.
npm: Platform-Specific optionalDependencies
npm has a different mechanism but the same result.
The parent package
| |
Each platform package
| |
The os and cpu fields tell npm to only install this package on matching systems. The user runs npm install -g @blackwell-systems/mcp-assert and gets only the binary for their platform.
The Release Pipeline
One git tag triggers everything:
git tag v0.2.0 && git push --tags
That fires a GitHub Actions workflow that:
- GoReleaser builds binaries for 6 platforms, creates GitHub Release
- pypi-publish job downloads binaries, builds 6 wheels, uploads to PyPI
- npm-publish job copies binaries into platform packages, publishes to npm
- winget job submits manifest to microsoft/winget-pkgs
- snap job builds and publishes to Snap Store
- homebrew job updates the tap formula
Zero manual steps. Tag, push, walk away. Every package manager gets the new version.
Why This Works
Go compiles to a static binary. No runtime dependency. No interpreter. No virtual environment. The binary IS the distribution. You’re just putting it on a shelf where people already shop.
Python developers don’t care that mcp-assert is written in Go. They care that pip install mcp-assert gives them a working mcp-assert command. The implementation language is invisible.
The 12x Multiplier
If your Go tool is only on GitHub Releases:
- Go developers find it (go install)
- Everyone else doesn’t
If your Go tool is on pip + npm + Homebrew + winget + Docker + GitHub Releases:
- Go developers find it
- Python developers find it
- Node developers find it
- macOS users find it
- Windows users find it
- CI/CD pipelines find it
Same tool. Same binary. 12x the reach.
Scripts
The full implementation (50 lines of bash for PyPI, 30 for npm):
The tool this powers: mcp-assert (deterministic testing for MCP servers). The technique works for any Go binary.
MIT license. Open source. Steal the scripts.