Purpose
Package an MCP server for distribution so others can install and configure it. Covers npm/PyPI publishing, Docker packaging, MCP registry listing, and writing the installation documentation that hosts need.
When to use this skill
- Publishing an MCP server to npm or PyPI
- Creating a Docker image for a remote MCP server
- Listing a server on the MCP registry (registry.modelcontextprotocol.io)
- Writing installation and configuration documentation for end users
- Packaging a server as a standalone binary
Do not use this skill when
- Building the server itself → use
mcp-developmentormcp-builder - Deciding transport/auth → use
mcp-auth-transports - The server is project-internal with no distribution need
Operating procedure
Phase 1 — Package for distribution
npm (TypeScript servers)
- Set
"bin"inpackage.jsonpointing to the compiled entry point:
{
"name": "@yourorg/mcp-server-myservice",
"version": "1.0.0",
"bin": { "mcp-server-myservice": "dist/index.js" },
"files": ["dist"],
"engines": { "node": ">=18" }
}
- Add shebang to entry file:
#!/usr/bin/env node - Build and publish:
npm run build && npm publish - Users install with:
npx @yourorg/mcp-server-myserviceornpm install -g @yourorg/mcp-server-myservice
Naming convention: mcp-server-<service> or @org/mcp-server-<service>
PyPI (Python servers)
- Use
pyproject.tomlwith entry points:
[project.scripts]
mcp-server-myservice = "myservice.server:main"
[project]
name = "mcp-server-myservice"
dependencies = ["mcp>=1.2.0"]
- Build and publish:
uv build && uv publish(orpip install build && python -m build && twine upload dist/*)
Docker (remote servers)
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY dist/ ./dist/
EXPOSE 3000
CMD ["node", "dist/index.js"]
Phase 2 — Write installation docs
The README must include host-specific configuration snippets. Users need copy-paste configs:
## Installation
### Claude Desktop
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
\```json
{
"mcpServers": {
"myservice": {
"command": "npx",
"args": ["@yourorg/mcp-server-myservice"],
"env": { "API_KEY": "your-key" }
}
}
}
\```
### VS Code / Copilot
Add to `.vscode/mcp.json`:
\```json
{
"servers": {
"myservice": {
"command": "npx",
"args": ["@yourorg/mcp-server-myservice"],
"env": { "API_KEY": "your-key" }
}
}
}
\```
Phase 3 — Register on MCP registry
The MCP registry at registry.modelcontextprotocol.io is a directory of MCP servers. To list your server:
- Ensure the server repo is public on GitHub
- Include a well-structured README with: purpose, tools list, install instructions, host configs
- Submit via the registry's contribution process (typically a PR to the registry repo)
Phase 4 — Quality checklist
Before publishing, verify:
- All tools have clear
descriptionandinputSchema -
tools/listreturns complete tool definitions in MCP Inspector - All tools handle errors gracefully (no unhandled exceptions reaching the client)
- Tool annotations (
readOnlyHint,destructiveHint) are set correctly - README includes install command, host configs, and required environment variables
-
package.json/pyproject.tomlhas correct entry point and dependencies - No hardcoded paths or machine-specific configuration
Decision rules
- Use
npxin host configs so users don't need global install - For Python, prefer
uvxorpipxoverpip install -g - Include all required env vars in the documentation with descriptions
- If the server needs API keys, document where to get them
- Semantic versioning: breaking changes to tool schemas = major version bump
Output requirements
- Publishable package (npm tarball, PyPI wheel, or Docker image)
- README with tool list, install command, and host config snippets for at least 2 hosts
- MCP Inspector verification passing
- Published to registry (npm/PyPI and optionally MCP registry)
Related skills
mcp-development— server development lifecyclemcp-host-integration— host-specific configuration patternsmcp-schema-contracts— schema versioning for published serversmcp-testing-evals— pre-publish quality verification
Failure handling
- If
npxfails to run the package, verify thebinfield inpackage.jsonand the shebang line - If users report "tool not found", check that
toolscapability is declared ininitializeresponse - If the server works locally but fails for users, check env var documentation — missing API keys are the #1 issue
