Azure API Center MCP registry as code: JSON per server, Bicep module, and safe pruning

6/16/2026

Azure API Center MCP registry as code: JSON per server, Bicep module, and safe pruning

One awkward fact: Bicep rejects several MCP-specific fields that the Azure API Center API actually accepts. If you want to manage a private MCP registry as code, that mismatch blocks you fast. If you’re past a handful of servers, this matters.

The portal flow is fine to prove the concept. At 10-plus servers and multiple environments, you need pull requests, drift detection, repeatable deployments, and the ability to rebuild from a single repo. The guide I’m summarizing lays out a concrete, working approach to do exactly that.

What’s actually in play

  • API Center supports registering MCP servers as assets: remote endpoints with a runtime URL tied to an environment, or local/package-based servers described via package metadata. The portal creates remotes and versions; under the hood there’s an APIs resource plus a deployments child with a runtime URL and environment.
  • The rub: ARM/Bicep type definitions don’t include all MCP fields you’ll want in practice (think remote, packages, auth/security bits). The service API will take them; Bicep type checking won’t.

The approach that works in practice

  • One JSON per MCP server. Name, title, summary, description (don’t leave it empty), kind=mcp, version title, plus optional vendor/icon/useCases/license/support. For remotes: runtime URL and transport hint. For packages: registry/name/version/runtime hint and arguments. These JSON files become the source of truth.
  • A reusable Bicep module (2024-06-01-preview API) that:
    • Creates the workspace and an environment.
    • Materializes each JSON as an API of kind mcp.
    • When a remote is present, creates a deployments child with server.runtimeUri pointing to the runtime URL and associates it to the environment so it shows up in the servers listing.
    • Loads JSON at compile time (no parameter files) using Bicep’s JSON loading.
  • To get past missing types, the module wraps properties in any/unions to bypass compile-time validation so the service can accept the full MCP shape.
  • A PowerShell deploy script that runs the Bicep and then prunes: anything in Azure not defined in the JSONs is deleted. That keeps drift to zero across dev/test/prod.

Constraints and trade-offs

  • Bypassing type checks with any() is a tactical workaround. You lose schema safety in exchange for getting real deployments. Expect to revisit this as the resource provider types evolve.
  • Registry JSON vs. ARM shape isn’t 1:1. Some fields map differently than partner schemas suggest. Test carefully before rolling into prod.
  • Portal behaviors matter: an empty description makes a server invisible in VS Code. Keep mandatory display fields populated.
  • Pruning deletes. Wire approvals and dry runs into CI so you don’t accidentally wipe legitimate assets when files move or names change.
  • Remote versus package-based servers will age differently. Streamable HTTP is where most remote servers are heading; SSE is on the way out across the ecosystem. Don’t overfit to transports that might be deprecated.

What this changes on teams

  • You get PR review on every server addition or change, with a simple “add a JSON file” workflow.
  • You can spin up identical registries per environment and rebuild from scratch, useful for DR and audits.
  • You finally get real drift detection and automated cleanup instead of a portal-only registry that accumulates cruft.

What I’d watch: changes to the API Center ARM schema that might make the any/union hack unnecessary—or break it. Guard the pruning step with explicit allowlists in early rollouts. And document the minimum required fields in your repo to avoid invisible servers.

The takeaway: If your org is adopting MCP beyond a demo, treat the registry like any other infra: JSON per server, a Bicep module that tolerates today’s gaps, and a deploy script that enforces desired state with a cautious delete path.

Azure API CenterMCPInfrastructure as CodeBicepPowerShell