Key takeaways
- Use
mcp-creatorfor an automated path, or set up manually withpyproject.toml+uv build+uv publish - Name your package with the
-mcpsuffix for discoverability on PyPI - Push to GitHub and submit to MCP Marketplace to get security-scanned and listed
Why publish to PyPI
You built a Python MCP server. It works on your machine. Now you want other people to use it.
PyPI (the Python Package Index) is where pip install pulls packages from. When your server is on PyPI, anyone can install it with a single command:
pip install your-server-name
No cloning repos. No manual setup. One command and it works. This is the standard way to distribute Python MCP servers, and it is what MCP Marketplace expects when generating install instructions for your users.
This guide covers Python servers distributed via PyPI (pip install). Publishing a TypeScript server to npm? See How to build an MCP server or use mcp-creator-typescript for the automated path. There is also a third option: remote hosted servers where users connect to a URL and nothing is installed locally.
Not sure how to build the server itself? Start with How to build an MCP server first, then return here to publish it.
Two paths: automated or manual
There are two ways to go from idea to published MCP server:
- Automated with mcp-creator-python: install one tool, tell your AI assistant what you want to build, and it handles the scaffolding, building, and publishing for you. Good for speed and for people new to Python packaging.
- Manual: you set up the project structure, write the config files, build, and publish yourself. Full control, good for learning.
Both paths produce the same result: a properly structured Python MCP server on PyPI that anyone can install.
Path A: Use mcp-creator-python (recommended for beginners)
mcp-creator-python is an MCP server that helps you create other MCP servers. Install it, add it to your AI assistant, and describe what you want to build in plain English.
pip install mcp-creator-python
claude mcp add mcp-creator-python -- mcp-creator-pythonThen just tell your AI what to build:
"I want an MCP server that checks the weather for any city"
It handles everything: checks the PyPI name, scaffolds the project, builds, publishes to PyPI, creates a GitHub repo, and generates a marketplace submission checklist. You fill in your real logic in the services/ folder.
See the full MCP Creator guide for a detailed walkthrough.
Path B: Manual setup
If you prefer full control or want to understand what's happening under the hood, here is the step-by-step manual process.
What you need
- A working Python MCP server (if you do not have one yet, read How to build an MCP server)
- Python 3.11+
- A free PyPI account
- uv (recommended) or pip and build
This guide uses uv because it handles building and publishing in two commands. If you prefer pip and twine, the concepts are identical.
Step 1: Structure your project
PyPI packages need a specific layout. Here is the standard structure for a Python MCP server:
my-mcp-server/
├── pyproject.toml # Package metadata and dependencies
├── README.md # What users see on PyPI
├── .gitignore
├── src/
│ └── my_mcp_server/ # Your Python module (underscores, not hyphens)
│ ├── __init__.py
│ ├── server.py # MCP server definition and entry point
│ ├── tools/ # Tool implementations
│ │ ├── __init__.py
│ │ └── my_tool.py
│ └── services/ # Business logic, API clients
│ ├── __init__.py
│ └── my_service.py
└── tests/
└── test_my_tool.py
Two things to note:
- Source code goes in
src/<module_name>/. This is called the "src layout" and it prevents import issues during development. - The module name uses underscores (
my_mcp_server), even if the package name uses hyphens (my-mcp-server). Python does not allow hyphens in import names.
Step 2: Configure pyproject.toml
This is the single file that tells PyPI everything about your package. Here is a working example:
[project]
name = "my-mcp-server"
version = "0.1.0"
description = "One-line description of what your server does"
readme = "README.md"
requires-python = ">=3.11"
license = { text = "MIT" }
dependencies = [
"mcp[cli]>=1.0.0",
# Add your other dependencies here
]
[project.scripts]
my-mcp-server = "my_mcp_server.server:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/my_mcp_server"]
The key sections:
- name: What users type after
pip install. Use hyphens for readability. - version: Start at
0.1.0. Bump it every time you publish an update. - dependencies: Everything your server needs to run. The
mcp[cli]package is required for all MCP servers. - [project.scripts]: This creates the CLI command. After installing, users can run
my-mcp-serverdirectly from their terminal. - [tool.hatch.build.targets.wheel]: Points to your source code directory.
Step 3: Create a PyPI account and API token
- Go to pypi.org/account/register and create a free account.
- After signing in, go to Account settings and scroll to API tokens.
- Click Add API token. Name it anything (e.g., "MCP servers"). Set the scope to Entire account for your first publish. You can create project-scoped tokens later.
- Copy the token. It starts with
pypi-and you will only see it once.
Store the token so uv publish can use it. Add this line to your shell profile:
macOS / Linux (zsh):
echo 'export UV_PUBLISH_TOKEN="pypi-your-token-here"' >> ~/.zshrc
source ~/.zshrc
macOS / Linux (bash):
echo 'export UV_PUBLISH_TOKEN="pypi-your-token-here"' >> ~/.bashrc
source ~/.bashrc
This persists across terminal sessions. You only need to do this once.
Step 4: Build your package
From your project root:
uv build
This creates two files in dist/:
dist/
├── my_mcp_server-0.1.0.tar.gz # Source distribution
└── my_mcp_server-0.1.0-py3-none-any.whl # Wheel (what pip installs)
If the build fails, check that your pyproject.toml paths match your actual directory structure.
Step 5: Publish to PyPI
uv publish
That is it. Your package is now live on PyPI. Anyone in the world can install it:
pip install my-mcp-server
Visit https://pypi.org/project/my-mcp-server/ to see your listing.
Step 6: Push to GitHub
MCP Marketplace requires a repository URL when you submit your server: submitted servers go through an automated security scan before being listed. Create a GitHub repo and push your code:
git init
git add .
git commit -m "Initial commit"
gh repo create my-mcp-server --public --source . --push --description "Description of your MCP server"
This uses the GitHub CLI. If you don't have it, install it with brew install gh (macOS) and run gh auth login to authenticate.
Step 7: Tell users how to use it
Your README should include the MCP config snippet so users know exactly how to add your server to their AI assistant:
{
"mcpServers": {
"my-mcp-server": {
"command": "my-mcp-server"
}
}
}
If your server requires environment variables (API keys, tokens), include those too:
{
"mcpServers": {
"my-mcp-server": {
"command": "my-mcp-server",
"env": {
"MY_API_KEY": "your-key-here"
}
}
}
}
Publishing updates
When you make changes:
- Bump the version in
pyproject.toml(e.g.,0.1.0to0.1.1) - Run
uv buildagain - Run
uv publish
PyPI does not allow overwriting an existing version. You must bump the version number every time.
Package naming tips
PyPI has strict naming rules. A few things to know:
- Name collisions: PyPI will reject your package if the name is too similar to an existing one. Check pypi.org first: or use mcp-creator-python's
check_pypi_nametool. - Use the
-mcpsuffix: Names likeweather-mcporfinance-mcpare clear, descriptive, and unlikely to collide. This also makes your package discoverable when people search PyPI for MCP servers. - Hyphens vs underscores: Use hyphens in the package name (
my-mcp-server) and underscores in the module name (my_mcp_server). Python normalizes them, but hyphens are the convention for PyPI.
Common issues
"The name is too similar to an existing project": Pick a more specific name. Adding -mcp as a suffix usually resolves this.
"403 Forbidden" on publish: Your API token is missing or expired. Check that UV_PUBLISH_TOKEN is set in your shell (echo $UV_PUBLISH_TOKEN). If empty, re-add it to your shell profile and run source ~/.zshrc.
"File already exists" on publish: You are trying to upload the same version twice. Bump the version in pyproject.toml, rebuild, and publish again.
Build fails with "package not found": Make sure the packages path in pyproject.toml matches your actual directory. If your code is at src/my_mcp_server/, the config should be packages = ["src/my_mcp_server"].
Submit to MCP Marketplace
Once your package is on PyPI and your code is on GitHub, submit it to MCP Marketplace to get it listed, security-scanned, and discoverable. You will need your PyPI package name and GitHub repository URL for the submission.
Browse MCP Marketplace to see what other creators have built.
Want to charge for your server? Read How to monetize your MCP server.