MetaMCP
Overview
MetaMCP is an open-source aggregator, orchestrator, middleware and gateway for the Model Context Protocol (MCP), the standard that lets AI assistants and agents call external tools. It groups many MCP servers into namespaces and exposes each namespace as a single endpoint over Streamable HTTP, SSE and an OpenAPI REST surface. A client connects once and reaches every underlying tool.
This SecureAnyCloud image runs MetaMCP 2.4.22 and PostgreSQL as a Docker Compose stack managed by systemd, behind an nginx TLS reverse proxy. At first boot it registers the official MCP time server in a default namespace behind a public endpoint, so a working federated tool call is available as soon as the VM is up.
What you get:
- MetaMCP 2.4.22 (a Next.js and Node backend) under Docker Compose, published to loopback
127.0.0.1:12008 - PostgreSQL 16 in the same Compose stack, on a private container network with no host port
- An nginx TLS reverse proxy on
:443with a per-VM self-signed certificate;:80redirects to:443 - A bundled reference MCP time server (
uv tool run mcp-server-time), registered and aggregated at first boot into thedefaultnamespace behind thepublicendpoint - A management web interface to register servers, compose namespaces, apply per-namespace tool middleware and issue API keys
- A per-VM administrator password, session authentication secret, database password and API key generated at first boot; the admin credential and API key are written to
/root/metamcp-credentials.txt - Public self-registration disabled after the single administrator is seeded
metamcp.service(the Compose stack) andnginx.serviceas enabled, active systemd units- 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting size. Choose a larger size for bigger tool estates or more concurrent clients.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 443/tcp from the clients and agents that need the aggregator. MetaMCP holds access to every server it federates and issues API keys, 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 MetaMCP by SecureAnyCloud, and select Create.
On the Basics tab, 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).
Select Review + create, then Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:metamcp-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name metamcp \
--image sac1647283583153:metamcp-ubuntu-24-04:default:latest \
--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 metamcp --port 443 --priority 1010Step 3 - Connect to your VM
Connect over SSH as azureuser:
ssh azureuser@<vm-public-ip>Step 4 - Confirm the services are running
The Compose stack (the MetaMCP app and PostgreSQL) and nginx start automatically on first boot. Check that they are active:
systemctl is-active docker metamcp nginx ss -tln | grep -E ':443 |:80 |:12008 ' curl -sk -o /dev/null -w 'MetaMCP health: HTTP %{http_code}\n' https://127.0.0.1/healthThe MetaMCP app (12008) is bound to loopback, and PostgreSQL is only on the private Compose network. Neither is reachable directly from the network. Only nginx on :443 is exposed.
Step 5 - Retrieve the per-VM administrator credentials
Every VM generates its own administrator password, session authentication secret, database password and API key on first boot, so there is no shared default login. The administrator credential and API key are written to a root-only file. Read it with sudo:
sudo cat /root/metamcp-credentials.txtThe file is mode 0600 root:root. Note the admin email, the password and the METAMCP_API_KEY, then keep them somewhere safe.
Step 6 - Sign in to the management UI
Browse to https://<vm-public-ip>/. The image ships a self-signed TLS certificate, so your browser warns on the first visit. Replace the certificate with your own in Step 12.
MetaMCP requires authentication, so a sign-in page opens. Enter the administrator email and password from Step 5. Public self-registration is disabled, so no sign-up form is offered.
After you sign in, you land on the MCP Servers page. On a fresh VM the bundled localtime server is already registered, with type STDIO and status No Error. This is the reference server the image aggregates at first boot, and it shows the aggregator working end to end.
Step 7 - Inspect the default namespace
Open MetaMCP Namespaces, then open the default namespace. Its connection status is Connected.
MetaMCP has automatically discovered the tools that the localtime server exposes (get_current_time and convert_time) and mapped them into the namespace. Any client that reaches the namespace's endpoint can call those tools.
Step 8 - Review the public endpoint
Open MetaMCP Endpoints. The public endpoint maps to the default namespace and exposes it over three transports: SSE, Streamable HTTP and an OpenAPI REST surface. Each is secured with the API key.
Point your MCP client at the Streamable HTTP or SSE URL. Alternatively, drive the tools over plain REST through the OpenAPI surface.
Step 9 - Call a federated tool through the aggregated endpoint
The aggregated endpoint is authenticated with this VM's own API key, and an unauthenticated request is refused. With the key, the OpenAPI surface lists the federated tools, and a POST invokes one through the aggregator:
KEY=$(sudo grep '^METAMCP_API_KEY=' /root/metamcp-credentials.txt | cut -d= -f2-)
curl -sk -o /dev/null -w 'no API key: HTTP %{http_code}\n' https://127.0.0.1/metamcp/public/api/openapi.json
curl -sk -H "X-API-Key: $KEY" https://127.0.0.1/metamcp/public/api/openapi.json \
| python3 -c 'import sys,json; print("federated tools:", [p.strip("/") for p in json.load(sys.stdin).get("paths",{})])'Now invoke the bundled tool. The request goes to MetaMCP, which proxies it to the localtime server and returns the result, a real federated round trip:
KEY=$(sudo grep '^METAMCP_API_KEY=' /root/metamcp-credentials.txt | cut -d= -f2-)
curl -sk -X POST https://127.0.0.1/metamcp/public/api/localtime__get_current_time \
-H "X-API-Key: $KEY" -H 'Content-Type: application/json' -d '{"timezone":"Europe/Dublin"}'The response contains the current time for the requested timezone, returned by the bundled server through the aggregated endpoint.
Step 10 - Verify the secure defaults
No login is baked into the image. The administrator password, API key and session authentication secret are generated per VM at first boot, and the credential file is 0600 root:root. Public self-registration is disabled, and PostgreSQL is on the private Compose network only. Verify each of these:
stat -c 'creds file: %n perms: %a owner: %U:%G' /root/metamcp-credentials.txt curl -sk https://127.0.0.1/trpc/frontend.config.getSignupDisabled \
| python3 -c 'import sys,json; print("public signup disabled:", json.load(sys.stdin)["result"]["data"])' ss -tln | grep -q ':5432 ' && echo 'PostgreSQL EXPOSED (unexpected)' || echo 'PostgreSQL not exposed on the host (good)'Step 11 - Add your own MCP server, namespace and endpoint
Use the management UI to build out your tool estate:
- On MCP Servers, add a server. Use a
STDIOcommand (for examplenpx -y @modelcontextprotocol/server-filesystem /data) or theSSEorStreamable HTTPURL of a remote MCP server. - On MetaMCP Namespaces, create a namespace and attach the servers you want grouped together. You can optionally apply tool middleware.
- On MetaMCP Endpoints, expose the namespace as a new endpoint and choose its authentication.
- On API Keys, create keys for the clients that will connect.
Downstream STDIO servers are launched on the VM and may fetch their package from the internet on first use. Make sure the VM has outbound access.
Step 12 - 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. Then set APP_URL to that name so the browser origin is trusted:
sudo cp your-fullchain.pem /etc/ssl/metamcp/cert.pem
sudo cp your-private-key.pem /etc/ssl/metamcp/key.pem
sudo chmod 600 /etc/ssl/metamcp/key.pem
sudo sed -i 's#^APP_URL=.*#APP_URL=https://mcp.example.com#; s#^NEXT_PUBLIC_APP_URL=.*#NEXT_PUBLIC_APP_URL=https://mcp.example.com#' /opt/metamcp/.env cd /opt/metamcp && sudo docker compose up -d && sudo systemctl reload nginxStep 13 - Check the version, back up and maintain
Confirm the running version:
grep -oE 'metamcp:[0-9.]+' /opt/metamcp/docker-compose.yml | head -1MetaMCP's state lives in the PostgreSQL database inside the Compose stack. This covers registered servers, namespaces, endpoints, users and API keys. Back it up with pg_dump; the container reads its own credentials from the environment:
cd /opt/metamcp
sudo docker compose exec -T metamcp-pg sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' \
| sudo tee /var/backups/metamcp-$(date +%F).sql >/dev/nullThe image keeps unattended security upgrades enabled, so the OS receives patches automatically. Configuration lives in /opt/metamcp/.env. Apply changes with cd /opt/metamcp && sudo docker compose up -d.
Support
SecureAnyCloud images come with 24/7 support. For questions about this MetaMCP image or help with your deployment, contact us through secureanycloud.com.
Deploy on Azure
Launch MetaMCP MCP Aggregator on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com