Skip to main content

Builders & Images

Registry server images are built by CI (the build-images.yml workflow) from generic builder Dockerfiles under images/ in the registry repo. The builder is selected by the image.builder field in the server's manifest; omitting it selects go-static.

image:
ref: ghcr.io/gigmcp/myserver-mcp
digest: sha256:...
entrypoint: /app/server
builder: node # omit or "go-static" for static Go binaries

Under the hood, registryctl build-args reads the manifest and emits BUILDER=<value> into $GITHUB_ENV; the workflow passes -f "images/${BUILDER}/Dockerfile" to docker buildx build. See registryctl.

The /app/server convention

Every builder places the executable at /app/server inside the image, and the manifest's image.entrypoint should always be /app/server. This is the path the gateway uses when it mounts or runs the server inside the sandbox.

BuilderRuntime image base/app/server artifact
go-staticscratch (no OS)Static ELF binary (CGO_ENABLED=0)
toolpackscratch (no OS)Static toolpack engine + baked-in /app/manifest.yaml and /app/toolspec.yaml
nodenode:22-bookworm-slimesbuild-bundled JS with #!/usr/bin/env node shebang
pythonpython:3.13-slim-bookwormshiv zipapp with #!/usr/local/bin/python3 shebang

go-static (default)

The default builder for standalone Go MCP servers.

  • source.repo — the Go module root, or any git repo with Go source.
  • source.package — the directory containing the main package (e.g. a subdirectory of the author's repo); defaults to . (repo root).
  • The builder runs CGO_ENABLED=0 go build -trimpath -o /out/server . in that directory and copies the result into a FROM scratch image. No OS layer, no shell, no libc — the smallest possible attack surface.

toolpack

Builds the generic toolpack engine and bakes the server's spec into the image.

  • source.repo / source.tag — the generic engine (github.com/gigmcp/toolpack); built exactly like go-static.
  • Additionally copies manifests/<name>/<version>.yaml and toolspecs/<name>/<version>.yaml from the registry repo (the build context) into the image as /app/manifest.yaml and /app/toolspec.yaml. The workflow passes NAME/VERSION build args to select them.
  • At runtime the engine reads the manifest for the credential-inject contract and the toolspec for the tool→HTTP mappings. registryctl lint-toolspecs enforces their coherence in CI, and lint requires a toolspec to exist for every manifest that selects this builder.

node

  • source.repo / source.tag — a git repo whose checkout contains a package.json at source.package (defaults to repo root).
  • The package.json must declare either a bin entry (string, or object with exactly one entry) or a main entry pointing to the server's JS/TS entry point.
  • esbuild bundles everything into a single self-contained CJS file with a #!/usr/bin/env node shebang at /app/server, on a node:22-bookworm-slim base.

python

  • source.repo / source.tag — a git repo containing a pyproject.toml at source.package (defaults to repo root).
  • The pyproject.toml must declare exactly one [project.scripts] entry; shiv uses that entry's name as the console-script entrypoint and bundles the project plus all dependencies into a single executable zipapp at /app/server, on a python:3.13-slim-bookworm base.

:::warning node and python images are not yet installable The Gig'MCP gateway sandbox currently mounts a single static binary from a scratch-based image. Running node or python images requires a full runtime rootfs (OS layer, interpreter on PATH), which depends on the gateway's rootfs sandbox extension — designed but not yet shipped.

The node and python builders exist so manifests can already declare builder: node or builder: python and CI can build the images today; those images become installable once the gateway extension ships. Until then, only go-static and toolpack images are runnable. :::

Custom per-server Dockerfiles

For servers that don't fit any generic builder (unusual CGO flags, pre-built assets, multi-step toolchains), you may add images/<name>/Dockerfile to the registry repo. This overrides the generic builder — point image.builder at the directory name that matches your custom Dockerfile. Note that the manifest schema currently whitelists only the four generic builder values, so a custom builder name also requires extending the schema's builder whitelist (coordinate in your PR).

Custom Dockerfiles are the exception; prefer the generic builders when possible. See submitting a server for the full contribution flow.