Self-hosting
Everything the hosted service runs is in the repository, and a document published on your own instance is the same document as one published here. The format is specified rather than owned, so an agent pointed at your registry needs nothing from us.
Being straight about the state of this: there is no one-command installer for production. What exists is a set of Helm charts the hosted service itself is deployed with, a config generator, realms as code, and a script that brings the whole shape up on one machine. If you are comfortable running a Kubernetes service, this is a normal afternoon. If you want a packaged appliance, it is not ready.
The pieces
| Piece | What it does | Required |
|---|---|---|
| Gateway | MCPG, on its own first-party plugins. Terminates MCP, verifies identity, applies per-tool governance, and calls Postgres or imd-svc for each tool. | yes |
| Postgres | PostgreSQL 17 with pg_trgm, pgvector and pgcrypto, run by CloudNativePG. The authoritative state, and the registry's rules as SQL functions. | yes |
| imd-svc | The server's own service beside the gateway: signing, agents' credentials, files, the background worker and the schema's migrations. | yes |
| NATS | JetStream: the gateway's sessions, subscriptions and notifications, shared between its replicas. Nothing durable lives there. | for two or more gateway replicas |
| Keycloak | Sign-in, with its realms as code: people, agents' own credentials, administrators. | yes |
| Embedding model | Text Embeddings Inference with BAAI/bge-base-en-v1.5, inside the cluster: search by meaning. No instruction text leaves it. | no |
| The studio | The editor, a static site that signs in to your Keycloak and keeps its workspace on your server. | no |
Note the last row. The whole surface is MCP, so agents and the command-line client talk to the gateway directly. The studio is one client among several, and an instance that only ever serves agents does not need it. Without the embedding model, search matches words and titles but not meaning.
The smallest working instance
The production charts in a local k3d cluster, wired the way production wires them, on one origin: the studio at /, the MCP server at /mcp, Keycloak at /auth. It needs Docker, k3d, kubectl, helm, Python 3 with PyYAML, Node with pnpm, rsync, openssl, and about 6 GB of disk. It is a real registry: versions, refs, proposals, organizations, signing and MCP delivery all work.
# 1. build the studio for the stack's origin
cd apps/landing
PUBLIC_IMD_AUTH_ISSUER=http://localhost:18080/auth/realms/instruction-md PUBLIC_IMD_AUTH_CLIENT=platform-web \
PUBLIC_IMD_MCP_URL=http://localhost:18080/mcp PUBLIC_IMD_STUDIO_SIGN_IN=on pnpm build
cd ../..
# 2. a k3d cluster, the operators, the secrets and every chart
deploy/k8s/stack/up.sh # http://localhost:18080
# the same, on MCPG's published release
IMD_GATEWAY_IMAGE=ghcr.io/mcpg-dev/mcpg:0.1.0-beta.68 deploy/k8s/stack/up.shUntil MCPG 0.1.0-beta.68 is published, the script's default gateway is a local build: the published beta.67 image with a gateway and its two backend plugins built on the machine, fromdeploy/mcpg/data. With the release, the second form uses the published image and its signed plugins. Sign in at http://localhost:18080/ and point an agent athttp://localhost:18080/mcp. The stack's realm has development users; production's does not. deploy/k8s/stack/README.md has the rest.
Postgres, and the backups that matter
Postgres is the whole state. The gateway's SQL bindings reach it through PgBouncer in transaction mode, which needs max_prepared_statements because MCPG prepares its statements, while LISTEN and the events reader go straight to the primary, since a transaction pooler cannot hold a LISTEN. Every client verifies the server's certificate against the cluster's CA. The chart sets all of this up.
Backups go through CloudNativePG's Barman Cloud plugin to any S3-compatible bucket: WAL continuously, a base backup nightly, both kept 30 days, so you can recover to a point in time on another host.
# deploy/k8s/imd-postgres/values.yaml
backup:
enabled: true
destinationPath: s3://imd-postgres-backup/imd-postgres
endpointURL: http://rgw.internal:7480
credentialsSecret: imd-postgres-backup # ACCESS_KEY_ID, ACCESS_SECRET_KEY
retentionPolicy: "30d"
schedule: "0 0 3 * * *" # a base backup nightly; WAL all the timedeploy/k8s/restore-drill.sh recovers a second cluster from the bucket, compares every table with the live one and removes it. Run it after the first nightly backup, and after any change to backups. NATS needs no backup: lose it and the gateway rebuilds what it kept there.
Identity
The gateway needs three things from a token: a stable subject, an audience bound to your MCP endpoint, and a claim saying whether the caller is a person, an agent or a service, because agents are capped below full administration no matter who they act for. The server also relies on Keycloak for more than sign-in: imd-svc mints each agent's own credentials in the agents' realm. So the identity provider is Keycloak, and your people can still sign in with your own provider through Keycloak's brokering.
The realms ship as code, generated rather than hand-edited (deploy/keycloak/gen-realms.py): one for people, one for agents, one for administrators. Keycloak imports them at its first start. After every install or upgrade, a job applies their content again through the admin API: it adds what is new and leaves what exists, because replacing a live realm would destroy organizations and federated identity links. Only the people's and the agents' realms are routed. Administration stays inside the cluster.
The generators keep a profile for each place the server runs: a developer's machine, the local stack, and production at instruction.md. Your own domain is a profile of your own indeploy/mcpg/gen-config.py and deploy/keycloak/gen-realms.py, with your origin, issuers and audience.
Signing
imd-svc derives a publisher key for each organization from one master key, so no private key is ever stored: the public halves are served for verification, and the private halves exist only inside the process while it signs. A second key signs each delivery.
# deploy/k8s/bootstrap-secrets.sh, in the Secret imd-keys
IMD_SIGNING_MASTER_KEY # each organization's publisher key is derived from it
IMD_DELIVERY_KEY # signs each delivery: one reader, one resolutiondeploy/k8s/bootstrap-secrets.sh makes both on its first run and keeps them after that. Keep a copy where you keep such things: lose the master key and every organization's publisher key changes; lose the delivery key and earlier deliveries can no longer be verified. Without a master key the platform signs nothing, which is a legitimate choice. Publishers can still bring their own keys and sign on their own machines, and consumers verify exactly the same way.
Kubernetes
Six charts, one namespace, installed in this order, each waited for. It is the order.github/workflows/deploy-server.yml runs them in, and that workflow passes the realm files and the apply job's script in full. The gateway pulls its first-party plugins when it starts and admits only signed ones.
# first, once per cluster: the CloudNativePG operator, cert-manager and the Barman Cloud plugin
# (docs/runbooks/server-deploy.md §1). Then the namespace's secrets:
deploy/k8s/bootstrap-secrets.sh instruction-md
helm upgrade --install imd-postgres deploy/k8s/imd-postgres -n instruction-md
kubectl -n instruction-md wait cluster/imd-postgres --for=condition=Ready --timeout=15m
helm upgrade --install imd-nats deploy/k8s/imd-nats -n instruction-md --wait
helm upgrade --install imd-keycloak deploy/k8s/imd-keycloak -n instruction-md --wait \
--set-file realms.users=deploy/keycloak/realms/prod/instruction-md-realm.json …
helm upgrade --install imd-embeddings deploy/k8s/imd-embeddings -n instruction-md --wait
helm upgrade --install imd-svc deploy/k8s/imd-svc -n instruction-md --wait \
--set image.tag=<tag>
helm upgrade --install imd-gateway deploy/k8s/imd-gateway -n instruction-md --wait \
--set-file config=deploy/mcpg/prod.yamlThe secrets script makes every secret in the namespace. It takes each value from the environment (what your secret manager hands it), else from the Secret already there, else it makes a new random one, and then writes the derived Secrets the charts read. None of them belong in values files, and the charts will not take them there. More than one gateway replica, clustered on NATS, needs an MCPG licence. The local stack runs on MCPG's free non-production grant.
Upgrades and operations
The runbooks the hosted service uses are in the repository under docs/runbooks: deploying the server, rolling back, key rotation, Postgres recovery, observability, MCPG's release gate, incident response and decommissioning an organization. They are written for our environment, and the shape transfers.
Licence
The specification text is Creative Commons Attribution 4.0. Implement it, quote it, fork it, sell it. The conformance corpus is Apache 2.0, because implementations vendor those files into their own source trees.
The platform source is under the Business Source License 1.1. In practice: you may run it, modify it and use it for your own purposes, including commercially, and the one thing you may not do is offer it to third parties as a competing hosted service. Each release converts to Apache 2.0 four years after publication. It is not an open-source licence today and the notice in the repository says so plainly.
Commercial support and alternative licensing are not settled yet, so if you need either, the answer right now is a conversation rather than a page.