Submitting a Server
This page walks you through getting your MCP server into the Gig'MCP registry: from tagging a release in your own repo to seeing it published in the signed index.json that gateways install from.
:::note Aggregator policy
Your server's source code lives in your repo. The registry holds only your manifest (and, rarely, a custom Dockerfile). CI rejects any PR that adds source code, examples/ directories, or .go files outside schema/ and cmd/.
:::
How the pipeline works
- You tag a release of your server's source repo.
- You open a PR against the registry adding one file:
manifests/<name>/<version>.yaml. - CI lints the manifest with registryctl: schema validation, egress allowlist rules, denylisted exfil domains, and path/name consistency.
- A maintainer dispatches the
build-imagesworkflow, which builds your image from your tagged source using the builder named in your manifest and prints the resulting linux/amd64 image-manifest digest. - You update your PR to pin that digest in
image.digest. - On owner review and merge, CI compiles all manifests into
index.json, signs it (ed25519), and republishes it as the rollinglatestrelease. Gateways verify the signature before trusting any entry.
What was approved in the PR is exactly what runs: the gateway pulls the image by digest, so the build can never drift from the reviewed manifest.
Step 1: Tag a release
Tag a release of your MCP server's source repo. The registry builds from that tag — never from a branch tip.
Step 2: Write the manifest
Add manifests/<name>/<version>.yaml. The path must match the manifest's name and version fields — CI rejects mismatches. See the manifest reference for every field; the essentials:
| Field | Rule |
|---|---|
source.repo / source.tag | The tagged source to build from (your repo) |
source.package | Subdirectory containing the server's main package; omit or leave blank to build from the repo root (.) |
image.builder | Selects the build recipe (images/<builder>/Dockerfile); omit or set to go-static for static Go binaries (the default) |
image.entrypoint | Must be /app/server — every builder places the server there |
entitlements.egress | Exact hostnames or *.suffix (≥2 labels) only |
credentials[].inject | header + format for sealed tier, or env for entrusted tier |
tools[].default | Mark the curated subset default: true — only default tools are exposed to clients; a manifest with no default tools exposes nothing |
A real example from the catalog (manifests/cloudflare/0.1.0.yaml, abridged):
schemaVersion: 1
name: cloudflare
version: 0.1.0
source:
repo: github.com/gigmcp/toolpack
tag: v0.1.0
image:
ref: ghcr.io/gigmcp/cloudflare-mcp
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
entrypoint: /app/server
builder: toolpack
tier: sealed
entitlements:
egress:
- api.cloudflare.com
credentials:
- id: cloudflare_token
type: api_key
provider: cloudflare
inject:
header: Authorization
format: "Bearer {token}"
tools:
- name: list_zones
default: true
- name: create_dns_record
default: false
:::warning Builder availability
The node and python builders are prepared but not yet installable — they require the gateway's rootfs sandbox extension, which is designed but not yet shipped. Use go-static (the default) for static Go binaries, or toolpack for declarative HTTP tool mappings. See builders.
:::
If your manifest uses builder: toolpack, you must also add a paired toolspecs/<name>/<version>.yaml — see toolspecs. CI runs registryctl lint-toolspecs and fails if a toolpack manifest has no spec.
If your server requires an unusual build (custom CGO flags, a non-Go toolchain, pre-built assets), you may add images/<name>/Dockerfile — but this is the exception, not the rule. The generic images/go-static/Dockerfile handles standard static Go servers.
Step 3: Open the PR
Open a PR adding your one manifest file (plus a toolspec or custom Dockerfile if applicable). Lint CI runs on every PR:
registryctl lint ./manifests -denylist denylist/exfil-domains.txtregistryctl lint-toolspecs ./toolspecs ./manifests- The aggregator-policy check (no server source in the registry)
You can run the same lint locally before pushing — see registryctl.
Step 4: Pin the digest
Use a placeholder digest (sha256:0000…) in your initial PR. A maintainer dispatches the build-images workflow with your server's name (version optional, defaults to latest). The workflow:
- Resolves build args from your manifest (
registryctl build-args). - Builds and pushes
ghcr.io/gigmcp/<name>-mcp:<version>from your tagged source. - Prints the linux/amd64 image-manifest digest to pin.
Update your PR to set image.digest to the printed value. Manifests with placeholder digests are not installable.
Step 5: Merge and publish
After owner review and merge, the publish-index workflow runs automatically on main: it lints, builds index.json from all manifests, signs it with the registry's ed25519 key, and republishes index.json + index.json.sig as the rolling latest release. No manual publish step.
:::note Version bumps force re-consent Manifest changes on a version bump force re-consent in every gateway that has the server installed. Users see exactly what changed before the new version can run. :::
Checklist
Before opening your PR:
- Your server's source repo is public and has a tagged release.
- Your PR adds exactly one file:
manifests/<name>/<version>.yaml(plus a toolspec ifbuilder: toolpack). - The file path matches the manifest's
nameandversionfields. -
image.entrypointis/app/server. - Egress entries are exact hostnames or
*.suffixwith at least 2 labels — no broad wildcards. - Credentials match your tier: sealed →
inject.header+formatcontaining{token}; entrusted →inject.envonly. - The tools you want exposed are marked
default: true. -
registryctl lintpasses locally. - No source code,
examples/, or stray.gofiles in the PR.
After CI builds your image:
-
image.digestis updated to the digest printed bybuild-images(no placeholder).
See also
- registryctl CLI reference — run the same lint CI runs
- Registry overview — trust chain and signing
- Manifest reference — every field, validated rules
- Builders —
go-static,toolpack,node,python