How do you package and distribute an MCP server?
Quick Answer
Package a Python server as a normal PyPI package runnable via pip install + an entry-point script, or make it directly runnable via uvx <package-name> for zero-install execution. Package a Node/TypeScript server as an npm package runnable via npx <package-name>, which is the most common distribution pattern for community servers since it needs no separate install step — a host's config just points at the npx command. For servers with heavier dependencies (native binaries, specific runtime versions) or ones meant to run remotely, a Docker container is common, with the host launching docker run as its subprocess command (for local use) or the image deployed as a standalone service (for remote/HTTP use). Whichever path you choose, pin dependency versions, document required environment variables clearly, and keep startup fast, since many hosts launch the server fresh on every session start.
Detailed Answer
How you distribute a server determines how frictionlessly other people can actually adopt it — this is often as important as the server's functionality itself.
npm (most common for TypeScript/Node servers)
// package.json
{ "name": "@you/weather-mcp-server", "bin": { "weather-mcp-server": "./dist/index.js" } }
// Host config just needs npx, no separate install step
{ "mcpServers": { "weather": { "command": "npx", "args": ["-y", "@you/weather-mcp-server"] } } }
PyPI / uvx (common for Python servers)
uvx weather-mcp-server # runs directly from PyPI with no separate `pip install` step
{ "mcpServers": { "weather": { "command": "uvx", "args": ["weather-mcp-server"] } } }
Docker (heavier dependencies, or remote deployment)
FROM python:3.12-slim
COPY . /app
WORKDIR /app
RUN pip install -e .
CMD ["python", "server.py"]
{ "mcpServers": { "weather": { "command": "docker", "args": ["run", "-i", "--rm", "weather-mcp-server"] } } }
The -i flag matters here — it keeps stdin open so Docker's stdio properly bridges to the container's stdio transport.
Distribution checklist
- Pin dependency versions so a user's install today behaves the same as one six months from now.
- Document every required environment variable and what happens if it's missing. Ideally: a clear startup error, not a silent failure.
- Keep startup latency low. Many hosts spawn the server process fresh each session, or even more often. A server with a slow cold start — heavy imports, a large model load — makes every new session feel sluggish.
- Avoid bundling secrets into the published package. Credentials belong in the consumer's own environment/config, never baked into the artifact you publish.