ContextForge MCP Gateway on Ubuntu 24.04 on Azure User Guide
Overview
ContextForge MCP Gateway is IBM's open-source gateway, registry and proxy for the Model Context Protocol (MCP) — the standard that lets AI assistants and agents call external tools. It sits in front of many separate MCP servers and presents them as one authenticated endpoint: it keeps a registry of servers and the tools they expose, lets you compose virtual servers from a chosen set of tools, normalises different MCP transports, and manages everything through an admin web interface. Instead of wiring every assistant to every server by hand, your agents connect once and reach your whole MCP tool estate through a single controlled front door.
The cloudimg image installs ContextForge 1.0.5 in a Python virtual environment at /opt/mcpgateway, fronts it with an nginx TLS reverse proxy, and generates unique secrets on the first boot of every VM. Because a gateway with nothing behind it cannot be demonstrated, the image also bundles one real reference MCP server — the official time server — federated automatically at first boot, so a working proxied tool call is available the moment the VM is up. Backed by 24/7 cloudimg support.
What is included:
- ContextForge MCP Gateway 1.0.5 in a Python venv at
/opt/mcpgateway, bound to loopback127.0.0.1:4444 - nginx TLS reverse proxy on
:443(a per-VM self-signed certificate;:80redirects to:443) - A bundled reference MCP time server on loopback
127.0.0.1:8002, registered with the gateway at first boot - A SQLite datastore at
/var/lib/mcpgateway(no external database to run) - Per-VM administrator password, JWT signing secret and encryption secret generated at first boot, written to
/root/mcp-context-forge-credentials.txt mcp-context-forge.service,mcp-timeserver.serviceandnginx.serviceas systemd units, enabled and active- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point; scale up for larger tool estates or more concurrent clients. NSG inbound: allow 22/tcp from your management network and 443/tcp from the clients and agents that need the gateway. The gateway is a credential-aggregation point (it holds the auth for every server it federates), so keep it on a private network or restrict 443/tcp to trusted sources.
Step 1 — Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for ContextForge MCP Gateway by cloudimg, and select Create. On Basics pick your subscription, resource group, region, and size (Standard_B2s or larger); under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTPS (443). Then Review + create → Create.
Step 2 — Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name mcp-context-forge \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name mcp-context-forge --port 443 --priority 1010
Step 3 — Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 — Confirm the services are running
The gateway, the bundled time server and nginx come up automatically on first boot.
systemctl is-active mcp-context-forge.service mcp-timeserver.service nginx.service
ss -tln | grep -E ':443 |:4444 |:8002 '
curl -sk -o /dev/null -w 'gateway health: HTTP %{http_code}\n' https://127.0.0.1/health
The gateway (4444) and the bundled time server (8002) are bound to loopback and are never exposed directly; only nginx on :443 is reachable from the network.

Step 5 — Retrieve the per-VM administrator credentials
Every VM generates its own administrator password, JWT signing secret and encryption secret on first boot — there is no shared default login. The credentials are written to a root-only file:
sudo cat /root/mcp-context-forge-credentials.txt
The file is mode 0600 root:root; note the admin email and password, then keep them somewhere safe.

Step 6 — Sign in to the admin UI
Browse to https://<vm-public-ip>/admin. The image ships a self-signed TLS certificate, so your browser will warn on first visit (replace it with your own certificate — see Step 10). The gateway requires authentication, so you are presented with a sign-in page; enter the administrator email and password from Step 5.

After signing in you land on the System Overview dashboard, which shows the runtime, live counters and an architecture flow. On a fresh VM it already reports 1 registered MCP server and 2 tools — the bundled time server.

Step 7 — The bundled MCP server, federated out of the box
Open MCP Servers in the left-hand navigation. The bundled localtime server is already registered and its status is Active — this is the reference server the image federates at first boot, and it is the proof that the gateway works end to end.

Open Tools to see the federated tool catalogue. The gateway has discovered the tools the localtime server exposes — localtime-get-current-time and localtime-convert-time — and namespaced them by server. Any MCP client that connects to the gateway can now call these tools.

Step 8 — Mint an API token and call a federated tool
The gateway's REST/JSON-RPC API is authenticated with a bearer JWT signed by this VM's own signing secret. Mint a token on the VM, then list the federated servers and invoke a tool through the gateway:
SECRET=$(sudo grep '^JWT_SECRET_KEY=' /etc/mcpgateway/mcpgateway.env | cut -d= -f2-)
TOKEN=$(sudo /opt/mcpgateway/venv/bin/python -m mcpgateway.utils.create_jwt_token \
--username admin@cloudimg.local --exp 10080 --secret "$SECRET" 2>/dev/null | grep -oE 'eyJ[A-Za-z0-9._-]+' | tail -1)
curl -sk -H "Authorization: Bearer $TOKEN" https://127.0.0.1/gateways \
| python3 -c 'import sys,json; d=json.load(sys.stdin); d=d if isinstance(d,list) else d.get("gateways",d); [print(g["name"], g["status"]) for g in d]'
Now invoke the bundled tool. The request goes to the gateway, which proxies it to the localtime server and returns the result — a real federated round-trip:
SECRET=$(sudo grep '^JWT_SECRET_KEY=' /etc/mcpgateway/mcpgateway.env | cut -d= -f2-)
TOKEN=$(sudo /opt/mcpgateway/venv/bin/python -m mcpgateway.utils.create_jwt_token \
--username admin@cloudimg.local --exp 10080 --secret "$SECRET" 2>/dev/null | grep -oE 'eyJ[A-Za-z0-9._-]+' | tail -1)
curl -sk -X POST https://127.0.0.1/rpc -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"localtime-get-current-time","arguments":{"timezone":"Europe/Dublin"}}}'
The response contains the current time for the requested timezone, returned by the bundled server via the gateway.

An unauthenticated request, or one carrying a token signed with any other secret, is refused:
curl -sk -o /dev/null -w 'unauthenticated /tools: HTTP %{http_code}\n' https://127.0.0.1/tools
Step 9 — Register your own MCP server
To federate another MCP server (an SSE or streamable-HTTP endpoint), add it from the MCP Servers page in the UI, or with the API. Replace the URL with your server's endpoint:
curl -sk -X POST https://<vm-public-ip>/gateways \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"my_server","url":"https://my-mcp-server.example.com/sse","transport":"SSE"}'
The gateway connects to the endpoint, discovers its tools, and adds them to the catalogue. By default the gateway blocks loopback and private-network destinations (SSRF protection); the bundled loopback server is allowed via SSRF_ALLOW_LOCALHOST=true in /etc/mcpgateway/mcpgateway.env.
Step 10 — Replace the self-signed certificate
The image ships a per-VM self-signed certificate so the UI is available over HTTPS immediately. For any real use, install a certificate for your VM's DNS name (for example from your internal CA or Let's Encrypt) and point nginx at it:
sudo cp your-fullchain.pem /etc/ssl/mcpgateway/cert.pem
sudo cp your-private-key.pem /etc/ssl/mcpgateway/key.pem
sudo chmod 600 /etc/ssl/mcpgateway/key.pem
sudo systemctl reload nginx
Step 11 — Version, backup and maintenance
Confirm the installed version:
sudo -u mcpgateway /opt/mcpgateway/venv/bin/python -c "import importlib.metadata as m; print('ContextForge', m.version('mcp-contextforge-gateway'))"

The gateway's state (registered servers, tools, virtual servers, users and tokens) lives in the SQLite database at /var/lib/mcpgateway/mcp.db. Back it up with a filesystem snapshot or by copying the file while the service is stopped:
sudo systemctl stop mcp-context-forge
sudo cp /var/lib/mcpgateway/mcp.db /var/backups/mcp.db.$(date +%F)
sudo systemctl start mcp-context-forge
The image keeps unattended security upgrades enabled, so the OS receives patches automatically. Configuration lives in /etc/mcpgateway/mcpgateway.env; restart the gateway with sudo systemctl restart mcp-context-forge after any change.
Support
Every cloudimg deployment includes 24/7 support. If you have any questions about this image, contact us through cloudimg.co.uk.