Skip to content

Migrate Your MCP Server

You have an MCP server on GitHub. Users clone it, install dependencies, and configure paths manually. Let’s fix that in 10 minutes.

You need:

  • A working MCP server in a GitHub repository
  • The server must run via Python, Node.js, or a compiled binary
  • Admin access to the repo (to add a workflow and create releases)

No mpak account is needed. Your GitHub identity is your mpak identity.

Create a manifest.json at the root of your repository:

{
"name": "@yourorg/your-server",
"version": "1.0.0",
"description": "What your server does",
"server": {
"type": "python",
"entry_point": "your_package.server",
"mcp_config": {
"command": "python",
"args": ["-m", "your_package.server"]
}
}
}

Key requirements for Python:

  • Use module execution (-m) to handle relative imports correctly
  • Your server must have a if __name__ == "__main__" block:
    if __name__ == "__main__":
    mcp.run()

Replace @yourorg with your GitHub org or username (lowercased). See Naming Conventions.

Create .github/workflows/release.yml:

name: Release
on:
release:
types: [published]
permissions:
contents: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: NimbleBrainInc/mcpb-pack@v2

That’s it. The action handles:

  • Installing dependencies
  • Vendoring them into the bundle
  • Building the .mcpb file
  • Uploading it to your GitHub Release
  • Announcing it to the mpak registry (with OIDC provenance)

Before publishing, verify your server works correctly:

Terminal window
# Make sure your server starts and responds to MCP messages
# For Python:
python -m your_package.server
# For Node.js:
node dist/index.js
Terminal window
# Tag the release
git tag v1.0.0
git push origin v1.0.0

Then go to your GitHub repository and create a release from the v1.0.0 tag. The GitHub Action will trigger automatically.

Watch the Actions tab to see the build progress. When it completes:

  • The .mcpb file appears as a release asset
  • The bundle is registered on mpak.dev
Terminal window
# Search for your package
mpak bundle search your-server
# View full details
mpak bundle show @yourorg/your-server
# Run it
mpak bundle run @yourorg/your-server

Your server is now installable with a single command by anyone, anywhere.

You added 2 files:

FilePurpose
manifest.jsonDescribes your server and how to run it
.github/workflows/release.ymlBuilds and publishes on each release

No changes to your server code. No new runtime dependencies. No configuration files beyond what you already had.

If you see ModuleNotFoundError when running the bundle, the issue is usually module execution vs script execution:

// ✗ Wrong: script execution doesn't handle relative imports
{ "args": ["src/server.py"] }
// ✓ Correct: module execution handles imports properly
{ "args": ["-m", "your_package.server"] }

MCP uses JSON-RPC over stdio. Any non-JSON-RPC output on stdout breaks the connection. Common culprits:

  • print() statements (Python)
  • console.log() (Node.js)
  • Library banners or startup messages
  • Logging frameworks defaulting to stdout

Fix: redirect all logging to stderr:

import logging
logging.basicConfig(stream=sys.stderr)

Python servers must include this guard:

if __name__ == "__main__":
mcp.run()

Without it, mpak can’t start your server as a module.

Every bundle published to mpak is automatically scanned. Run the scanner locally to catch issues before publishing:

Terminal window
pip install mpak-scanner
mpak-scanner scan .

See Scanning Your Bundle for details.

If your server requires API keys or other user-provided values, add user_config to your manifest:

{
"user_config": {
"api_key": {
"type": "string",
"title": "API Key",
"description": "Your API key from example.com",
"sensitive": true,
"required": true
}
}
}

See User Configuration for the full guide.