Artificial Intelligence (AI) Azure

ContextForge MCP Gateway on Ubuntu 24.04 on Azure User Guide

| Product: ContextForge MCP Gateway on Ubuntu 24.04 LTS on Azure

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 loopback 127.0.0.1:4444
  • nginx TLS reverse proxy on :443 (a per-VM self-signed certificate; :80 redirects 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.service and nginx.service as 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 + createCreate.

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.

ContextForge services active and loopback-bound

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.

Per-VM credentials file exists with 0600 root:root permissions

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.

ContextForge admin sign-in page

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.

ContextForge System Overview dashboard

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.

The bundled localtime MCP server registered and active

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.

Federated MCP tools discovered through the gateway

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.

A real tool call traversing the gateway to the bundled MCP server

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'))"

ContextForge version, health and unauthenticated API refused

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.