Let Copilot handle your local Azure setup via MCP

kamilmrzyglod1 pts0 comments

Using Topaz with GitHub Copilot via MCP Server | Topaz

Skip to main content<br>The best GitHub Copilot experience for local Azure development is not "write me a bash script that calls az group create". It is telling the assistant what you need to build and having it wire up the local infrastructure while you write the application code. Instead of tab-switching to a terminal, remembering the right parameter names, and sequencing five CLI commands in the right order, you describe the stack in natural language and the assistant handles it — Key Vault, Storage Account, Service Bus namespace, all provisioned, connection strings returned, ready to paste into your configuration file.

Topaz ships a Model Context Protocol (MCP) server that makes this possible against the local emulator. This post covers how the MCP server works, why the Docker networking setup is non-trivial, and what the full setup looks like end to end.

Try it now<br>Configure the Topaz MCP server in VS Code with three steps: create the Docker network, add one entry to .vscode/mcp.json, and start chatting.docker network create --subnet 172.28.0.0/16 topaz-net

"servers": {

"Topaz": {

"type": "stdio",

"command": "docker",

"args": ["run", "--rm", "-i", "--network", "topaz-net", "--dns", "172.28.0.53", "thecloudtheory/topaz-mcp:latest"]

MCP server docs → · Star on GitHub →

What MCP actually does here​

The Model Context Protocol is a standard that lets AI assistants call external tools and receive structured results — creating real side effects rather than generating commands for you to copy-paste and run manually. When Copilot calls a tool, the call goes to the MCP server process, the server executes it against a live Topaz instance, and the result comes back to the assistant. The assistant sees real data: the vault URI of the Key Vault it just created, the connection string for the Service Bus namespace, the login server for the Container Registry.

This matters because the assistant can chain those results. After creating a Storage Account, it can pass the connection string directly to the next tool call that creates a Key Vault secret — without you manually copying values between terminal windows.

The Topaz MCP server exposes two kinds of capabilities:

Tools — individual operations: create a resource group, provision a Key Vault, fetch all connection strings in a subscription, check emulator health.

Prompts — pre-defined multi-step recipes that wire tools together into complete scenarios: bootstrap a full dev environment, set up a Functions-ready stack, provision a document processing pipeline.

The Docker connectivity problem​

When you run the MCP server as a Docker container — which is the recommended way to distribute it, so clients do not need the .NET runtime — it needs to reach the Topaz host over the network. The Topaz host also runs as a Docker container. Two containers running on the same machine are not on the same network by default; they cannot reach each other by hostname.

The first instinct is --network host. The Docker documentation describes this as "the container shares the host's network namespace". On Linux this is exactly what it means — the container sees localhost, all published ports, and everything else on the host's network stack. In practice, this works when Topaz runs directly on the host machine. But it breaks as soon as both Topaz and the MCP server are running as containers, because localhost inside the MCP container is the Linux VM's loopback, not a path to the Topaz container.

Even on Linux, where --network host does give the MCP container access to the host network stack, there is a second problem: wildcard subdomains. The Topaz MCP tools do not only call topaz.local.dev:8899 for ARM operations. When the Key Vault tool calls the Key Vault data-plane, it calls .vault.topaz.local.dev:8898. When the Container Registry tool calls the registry endpoint, it calls .cr.topaz.local.dev:8892. These subdomains are dynamic — they depend on resource names the user provides at runtime. --network host gives network access but does nothing for DNS; topaz.local.dev might resolve if the host has it in /etc/hosts, but no host-machine /etc/hosts entry covers my-vault.vault.topaz.local.dev.

The correct solution has two parts: a shared Docker network, and a wildcard DNS resolver.

The network and DNS setup​

The RunTopazAsContainer tool returns a shell command that sets up the full environment in one step. The command does three things:

1. Create a user-defined bridge network with a fixed subnet:

docker network create --subnet 172.28.0.0/16 topaz-net

User-defined networks have Docker's built-in DNS — containers can resolve each other by name. The fixed subnet allows assigning stable IP addresses, which the dnsmasq configuration depends on.

2. Start a lightweight DNS resolver at a fixed IP:

docker run -d --name topaz-dns \

--network topaz-net --ip 172.28.0.53 \

alpine sh -c "apk add -q --no-cache dnsmasq && \

dnsmasq...

topaz network docker server host vault

Related Articles