Production packaging answers one question: can a clean machine start your MCP server from the artifact alone?
The three packaging shapes
| Shape | Best for | You provide | Typical consumers |
|---|---|---|---|
| Git repo | Active development, reviewable builds | Source + install/build/run | Platform Git deploys, internal teams |
| Docker image | OS deps, custom runtimes | Image URL + digest | Strict prod, multi-cloud |
| Package URL | Published modules | npm/PyPI/Go coordinates | Quick installs, registry metadata |
MCPLambda supports all three (deployment strategies). The official MCP Registry stores metadata pointing at packages/images/remotes — it does not replace good packaging.
Decision guide
Changing code weekly? → Git (+ mcplambda.yaml)
Need apt packages / weird system libs? → Docker
Publishing a public community server? → Package + registry metadata
Private proprietary logic? → Git or private image (not public registry)
Official registry does not support private-only servers (registry about).
Universal production checklist
Regardless of shape:
- Starts from environment variables only (no laptop paths)
- Required secrets documented; values never in git
- Completes initialize (lifecycle)
-
tools/listreturns expected tools with valid schemas (tools) - Transport chosen deliberately: stdio vs Streamable HTTP (transports)
- Logging safe for transport (stdio → stderr only) (build server)
- Tool inputs validated; rate limiting considered (tools security)
- Lockfiles / pinned versions committed
- Health story: process stays up under a simple
tools/call
Git packaging (deep dive)
Repository layout
my-mcp/
mcplambda.yaml # recommended for MCPLambda Git deploys
package.json / pyproject.toml / go.mod
src/
README.md # env vars, run instructions
mcplambda.yaml example
build_strategy: npm
install_command: npm ci
build_command: npm run build
run: node dist/index.js
transport: streamable-http
Full field list and override rules: mcplambda.yaml docs and production yaml guide.
Git tips
- Prefer
npm ci/ frozen lockfiles over floating installs - Compile TypeScript in
build_command; run the compiled entrypoint - Monorepos: make
run/buildpaths explicit from repo root
Docker packaging (deep dive)
- Multi-stage builds to keep final image small
- Non-root user when possible
ENTRYPOINTstarts MCP correctly for your transport- Tag with semver and digest for prod
- Never
ENVreal secrets into the image - For Streamable HTTP: ensure the process listens on the port the platform expects
Package URL packaging
- Clear bin entry / module path
- Document Node/Python version requirements
- Great for
npx:///uvx://style installs - Less ideal for private business logic
Transport packaging implications
| Transport | Packaging note |
|---|---|
| stdio | Entrypoint must speak newline-delimited JSON-RPC on stdio; no banners on stdout |
| Streamable HTTP | Process must serve the MCP endpoint; prefer this for remote multi-client (transports, architecture) |
Hosts like MCPLambda may proxy stdio to a URL — that is product behavior. New remote designs should still prefer Streamable HTTP when you control the code.
Definition of done (smoke)
- Deploy from artifact with no manual SSH steps
tools/listvia Inspector or client matches README- One successful
tools/call - Auth enabled for remote
- A second engineer can redeploy from docs alone
Security packaging checklist
- No secrets in layers or repo history
- SBOM / dependency audit in CI (org standard)
- Least-privilege upstream credentials
- Sanitize tool outputs (tools security)
- Remote: authentication + Origin considerations (transports, security best practices)
Worked scenario: Second engineer deploys without a call
You hand a teammate only a repo URL. They deploy via Git using mcplambda.yaml, set three secrets from README, and get a working tools/list without asking you which start command to use.
That is the packaging bar. When OS libraries are required, you switch that server to a Docker image with a pinned digest. When you publish a community tool, you publish a package and registry metadata—not a zip on Drive.
Checklist for this topic
- Cold checkout/start documented and automated
- Choose Git vs Docker vs package deliberately
- Pin versions (lockfile or image digest)
- Transport-safe logging and entrypoint
- Secrets externalized
- Smoke: initialize, tools/list, tools/call
Topic-specific failure modes
| Failure | Likely cause | Fix |
|---|---|---|
| Works only on author machine | Hardcoded paths | Env-based portable start |
| :latest in prod | Mutable tags | Digest pins |
| Private server on public registry | Wrong distribution channel | Private host/image |
| Stdout breaks stdio | Logging misconfigured | stderr only for app logs |
Related guides
mcplambda.yaml · CI/CD · Securing remote
Packaging decision tree (short)
Need custom OS packages? → Docker digest
Publishing public installer? → language package + registry metadata
Internal active development? → Git + mcplambda.yaml
Revisit when any answer changes; do not freeze a demo packaging choice for a year by accident.
Sources
- Transports — 2025-11-25
- Build an MCP server
- Tools — 2025-11-25
- Lifecycle — 2025-11-25
- Architecture
- MCP Registry about
- MCP Inspector
- MCPLambda deployment strategies · mcplambda.yaml