Gerenciar servidores MCP programaticamente no Gerenciamento de API

Neste artigo, você aprenderá a criar e gerenciar servidores MCP em Gerenciamento de API do Azure usando a API REST, modelos do ARM, Bicep, o CLI do Azure e o Terraform. 

Importante

Os recursos de gerenciamento do servidor MCP descritos neste artigo exigem a API REST do API Management na versão 2025-09-01-preview ou posterior. Fixe essa versão em cada solicitação. 

Para obter informações sobre os recursos do servidor MCP, consulte Sobre servidores MCP em Gerenciamento de API do Azure.

Prerequisites

Modelo de recurso

Azure Resource Manager representa os servidores MCP da seguinte maneira:

  • Servidor MCP: um recurso de API da API Management do tipoMCP.

  • Servidor de passagem: aponta para um back-end do MCP externo existente. O recurso do servidor MCP declara a URL do backend e o tipo de transporte (HTTP com streaming ou SSE).

  • Ferramenta: Um sub-recurso de ferramenta de API de um servidor MCP. Você pode gerenciar com segurança os recursos da ferramenta a partir do CI/CD. Você pode adicionar, renomear ou remover ferramentas sem recriar o servidor MCP.

  • Políticas: Assim como acontece com APIs regulares, anexe a política de API ou os sub-recursos de política a um servidor MCP.

  • Produtos: a associação de produto é uma relação filho separada (products/{productId}/apis/{mcpServerId}), habilitando a implantação independente e a associação de vários produtos.

Exemplos de REST

Para maior clareza, os exemplos a seguir mostram corpos de resposta abreviados. Para obter esquemas de resposta completos, consulte a referência da API REST do Gerenciamento de APIs.

Adicionar o cabeçalho If-Match: * nos exemplos de chamadas PUT e DELETE torna as solicitações idempotentes. Esse cabeçalho se aplica independentemente de o recurso já existir ou não, e esse é o padrão recomendado para pipelines de CI/CD.

Antes de começar

Defina as variáveis a seguir antes de executar qualquer exemplo. Todos os exemplos nesta seção fazem referência a essas variáveis.

SUBSCRIPTION_ID="<your-subscription-id>"
RESOURCE_GROUP="<your-resource-group>"
APIM_NAME="<your-api-management-service-name>"
API_VERSION="2025-09-01-preview"
BASE_URL="https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_NAME}"
TOKEN=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv)

Listar servidores MCP

Retorna todas as APIs da instância filtradas por tipo mcp. Use os parâmetros de consulta $top e $skip para paginar grandes conjuntos de resultados.

Referência: API – Listar por serviço

curl -sG "${BASE_URL}/apis" \
  --data-urlencode "api-version=${API_VERSION}" \
  --data-urlencode "\$filter=type eq 'mcp'" \
  -H "Authorization: Bearer ${TOKEN}"

Resposta (200 OK)

{
  "count": 1,
  "value": [
    {
      "id": "/subscriptions/.../apis/my-mcp-server",
      "name": "my-mcp-server",
      "type": "Microsoft.ApiManagement/service/apis",
      "properties": {
        "type": "mcp",
        "displayName": "My MCP Server",
        "path": "my-mcp",
        "protocols": [ "https" ]
      }
    }
  ]
}

Erro comum:401 Unauthorized. O token de portador expirou. Execute novamente o comando de aquisição de token.


Obter um único servidor MCP

Referência: API – Obter

MCP_SERVER_ID="my-mcp-server"

curl -s "${BASE_URL}/apis/${MCP_SERVER_ID}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${TOKEN}"

Resposta (200 OK)

{
  "id": "/subscriptions/.../apis/my-mcp-server",
  "name": "my-mcp-server",
  "type": "Microsoft.ApiManagement/service/apis",
  "properties": {
    "type": "mcp",
    "displayName": "My MCP Server",
    "path": "my-mcp",
    "protocols": [ "https" ],
    "serviceUrl": "https://api.contoso.com"
  }
}

Erro comum:404 Not Found. Confirme se corresponde mcpServerId ao name campo retornado pela operação Lista.


Criar um servidor MCP baseado em uma API REST

Cria o recurso de servidor MCP. Após a criação, adicione ferramentas a ele individualmente usando a operação Adicionar ou atualizar uma ferramenta . Cada ferramenta faz referência a uma operação específica em um recurso de API REST de backup.

Referência: API – Criar ou atualizar

MCP_SERVER_ID="my-mcp-server"

curl -s -X PUT \
  "${BASE_URL}/apis/${MCP_SERVER_ID}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -H "If-Match: *" \
  -d '{
    "properties": {
      "type": "mcp",
      "path": "my-mcp",
      "displayName": "My MCP Server",
      "description": "MCP server backed by a REST API",
      "protocols": ["https"]
    }
  }'

Resposta (201 Criado)

{
  "id": "/subscriptions/.../apis/my-mcp-server",
  "name": "my-mcp-server",
  "type": "Microsoft.ApiManagement/service/apis",
  "properties": {
    "type": "mcp",
    "displayName": "My MCP Server",
    "path": "my-mcp",
    "protocols": ["https"],
    "provisioningState": "InProgress"
  }
}

Note

provisioningState: InProgress é esperado para operações PUT assíncronas. Consulte a URL retornada no cabeçalho de resposta Azure-AsyncOperation para confirmar a conclusão do processo.

Erro comum:400 Bad Request. Verifique se type é "mcp" e path é exclusivo dentro da instância de serviço.


Criar um servidor MCP de passagem

Um servidor de passagem encaminha todas as solicitações MCP diretamente para um back-end do MCP externo. Defina mcpProperties.transportType de modo que corresponda ao transporte que seu backend implementa.

Antes de criar um servidor pass-through, confirme se o backend pode ser acessado a partir do gateway de Gerenciamento de API e se implementa o transporte MCP selecionado nos caminhos de endpoint que você configurar. Se o back-end exigir autenticação, configure as credenciais ou cabeçalhos necessários usando políticas de Gerenciamento de API ou configuração de back-end.

Referência: API – Criar ou atualizar

Transporte HTTP que pode ser transmitido

Use streamable para backends que implementam a especificação atual de transporte HTTP de streaming do MCP. Uma única definição de ponto de extremidade é necessária.

MCP_SERVER_ID="my-mcp-passthrough"

curl -s -X PUT \
  "${BASE_URL}/apis/${MCP_SERVER_ID}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -H "If-Match: *" \
  -d '{
    "properties": {
      "type": "mcp",
      "path": "my-mcp-passthrough",
      "displayName": "My Passthrough MCP Server",
      "description": "Passthrough MCP server using streamable HTTP transport",
      "protocols": ["https"],
      "serviceUrl": "https://mcp-backend.contoso.com",
      "mcpProperties": {
        "transportType": "streamable",
        "endpoints": [
          { "name": "message", "uriTemplate": "/mcp" }
        ]
      }
    }
  }'

Resposta (201 Criado)

{
  "id": "/subscriptions/.../apis/my-mcp-passthrough",
  "name": "my-mcp-passthrough",
  "type": "Microsoft.ApiManagement/service/apis",
  "properties": {
    "type": "mcp",
    "displayName": "My Passthrough MCP Server",
    "path": "my-mcp-passthrough",
    "protocols": ["https"],
    "serviceUrl": "https://mcp-backend.contoso.com",
    "provisioningState": "InProgress",
    "mcpProperties": {
      "transportType": "streamable",
      "endpoints": [ { "name": "message", "uriTemplate": "/mcp" } ]
    }
  }
}

Transporte SSE

Use sse para back-ends que implementam o transporte HTTP+SSE (Server-Sent Events). Defina dois pontos de extremidade: um para o fluxo de eventos SSE e outro para o canal de mensagem.

MCP_SERVER_ID="my-mcp-sse"

curl -s -X PUT \
  "${BASE_URL}/apis/${MCP_SERVER_ID}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -H "If-Match: *" \
  -d '{
    "properties": {
      "type": "mcp",
      "path": "my-mcp-sse",
      "displayName": "My SSE MCP Server",
      "description": "Passthrough MCP server using SSE transport",
      "protocols": ["https"],
      "serviceUrl": "https://mcp-backend.contoso.com",
      "mcpProperties": {
        "transportType": "sse",
        "endpoints": [
          { "name": "sse",     "uriTemplate": "/sse" },
          { "name": "message", "uriTemplate": "/messages" }
        ]
      }
    }
  }'

Erros comuns:

  • 400 Bad Request. Inválido mcpProperties. Verifique se transportType é streamable ou sse, e cada um uriTemplate começa com /.
  • 400 Bad Request. O transporte SSE requer exatamente dois endpoints (sse e message). O transporte em fluxo requer um (message).

Adicionar ou atualizar uma ferramenta

Adiciona uma nova ferramenta a um servidor MCP com suporte da API REST ou atualiza uma existente. O operationId campo vincula a ferramenta a uma operação específica em um recurso de API REST de backup. Você pode adicionar, atualizar ou remover ferramentas independentemente sem recriar o servidor pai.

Referência: Ferramenta de API – Criar ou atualizar

MCP_SERVER_ID="my-mcp-server"
TOOL_ID="listOrders"
BACKING_API_ID="orders-api"
BACKING_OP_ID="list-orders"
OP_ID="/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_NAME}/apis/${BACKING_API_ID}/operations/${BACKING_OP_ID}"

curl -s -X PUT \
  "${BASE_URL}/apis/${MCP_SERVER_ID}/tools/${TOOL_ID}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -H "If-Match: *" \
  --data-raw "{
    \"properties\": {
      \"displayName\": \"listOrders\",
      \"description\": \"List all orders for a customer\",
      \"operationId\": \"${OP_ID}\"
    }
  }"

Resposta (201 Criado)

{
  "id": "/subscriptions/.../apis/my-mcp-server/tools/listOrders",
  "name": "listOrders",
  "type": "Microsoft.ApiManagement/service/apis/tools",
  "properties": {
    "displayName": "listOrders",
    "description": "List all orders for a customer",
    "operationId": "/subscriptions/.../apis/orders-api/operations/list-orders"
  }
}

Erros comuns:

  • 400 Bad Request. O operationId caminho está malformado ou a operação referenciada não existe.
  • 404 Not Found. O servidor MCP pai não existe. Crie o servidor antes de adicionar ferramentas.

Excluir uma ferramenta

Remove uma ferramenta de um servidor MCP. Exclua as ferramentas antes de excluir as operações subjacentes da API REST que elas referenciam; caso contrário, a exclusão falhará devido a um erro de dependência.

Referência: Ferramenta de API – Excluir

MCP_SERVER_ID="my-mcp-server"
TOOL_ID="listOrders"

curl -s -X DELETE \
  "${BASE_URL}/apis/${MCP_SERVER_ID}/tools/${TOOL_ID}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "If-Match: *"

Resposta:200 OK sobre o sucesso.

Erro comum:412 Precondition FailedIf-Match é necessário para exclusões. Use If-Match: * para corresponder a qualquer valor de ETag.


Aplicar uma política no escopo do MCP

Cria ou substitui o documento de política anexado a um servidor MCP. O servidor avalia as políticas nesse escopo para cada invocação de ferramenta. O rawxml formato aceita XML de política não codificada.

Referência: Política de API – Criar ou atualizar

MCP_SERVER_ID="my-mcp-server"
POLICY='<policies><inbound><base /><rate-limit calls="100" renewal-period="60" /></inbound><backend><forward-request /></backend><outbound><base /></outbound></policies>'

curl -s -X PUT \
  "${BASE_URL}/apis/${MCP_SERVER_ID}/policies/policy?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -H "If-Match: *" \
  --data-raw "{\"properties\":{\"format\":\"rawxml\",\"value\":\"${POLICY}\"}}"

Resposta (200 OK)

{
  "id": "/subscriptions/.../apis/my-mcp-server/policies/policy",
  "name": "policy",
  "type": "Microsoft.ApiManagement/service/apis/policies",
  "properties": {
    "value": "<policies>...</policies>"
  }
}

Erro comum:400 Bad Request. XML de política malformada. Valide o documento antes de enviar.


Associar um servidor MCP a um produto

Associa o servidor MCP a um produto, para que os assinantes desse produto possam chamar as ferramentas do servidor. A solicitação não tem corpo.

Ao associar o servidor MCP a um produto, você o disponibiliza por meio desse produto, mas os clientes ainda precisam de acesso de acordo com a configuração do produto. Se o produto exigir assinaturas, o cliente deverá usar uma chave de assinatura válida para esse produto.

Referência: API do produto – Criar ou atualizar

MCP_SERVER_ID="my-mcp-server"
PRODUCT_ID="my-product"

curl -s -X PUT \
  "${BASE_URL}/products/${PRODUCT_ID}/apis/${MCP_SERVER_ID}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Length: 0"

Resposta:201 Created com o contrato de API do servidor MCP no corpo.

Erro comum:404 Not Found. Verifique se productId e mcpServerId existem antes de criar a associação.


Excluir um servidor MCP

Exclui um servidor MCP e todos os seus sub-recursos de ferramentas e políticas. Antes de excluir o servidor, remova todas as ferramentas que fazem referência a operações em APIs de suporte; caso contrário, você não poderá excluir essas operações enquanto a referência de ferramenta existir.

Referência: API – Excluir

MCP_SERVER_ID="my-mcp-server"

curl -s -X DELETE \
  "${BASE_URL}/apis/${MCP_SERVER_ID}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "If-Match: *"

Resposta:200 OK sobre o sucesso.

Erro comum:412 Precondition Failed. If-Match é necessário para exclusões. Use If-Match: * para ignorar a verificação de ETag.

Modelos ARM e Bicep

Os modelos a seguir implantam uma configuração completa do servidor MCP em uma única implantação. Cada modelo pressupõe uma instância de serviço de Gerenciamento de API existente e usa uma tabela de parâmetros para que você possa reutilizar o mesmo arquivo em ambientes alterando apenas os valores de parâmetro.

Servidor MCP apoiado pela API REST

Esses modelos criam um servidor MCP, definem uma ferramenta que mapeia para uma operação em uma API REST de suporte existente, anexam uma política de limite de taxa no escopo do servidor e associam o servidor a um produto existente. Você pode realizar todas essas tarefas em uma única implantação.

Pré-requisitos: um serviço de Gerenciamento de API existente, uma API REST (backingApiId) com pelo menos uma operação (backingOperationId) e um produto existente (productId).

Parâmetro Obrigatório Default Description
serviceName Yes Nome da instância do serviço de Gerenciamento de API existente.
mcpServerId No orders-mcp Nome do recurso para o novo servidor MCP. Deve ser único no serviço.
backingApiId Yes Nome do recurso da API REST existente que apoia esse servidor MCP.
backingOperationId Yes Nome do recurso da operação a ser exposta como uma ferramenta.
toolId No sampleTool Nome do recurso e nome de exibição da ferramenta MCP a ser criada.
productId No starter Nome do recurso do produto existente ao qual associar o servidor.
@description('Name of the existing API Management service instance.')
param serviceName string

@description('Resource name for the new MCP server.')
param mcpServerId string = 'orders-mcp'

@description('Resource name of the existing REST API that backs this MCP server.')
param backingApiId string

@description('Resource name of the operation in the backing REST API to expose as a tool.')
param backingOperationId string

@description('Resource name and display name of the MCP tool to create.')
param toolId string = 'sampleTool'

@description('Resource name of the existing product to bind the MCP server to.')
param productId string = 'starter'

resource apimService 'Microsoft.ApiManagement/service@2025-09-01-preview' existing = {
  name: serviceName
}

resource mcpServer 'Microsoft.ApiManagement/service/apis@2025-09-01-preview' = {
  parent: apimService
  name: mcpServerId
  properties: {
    type: 'mcp'
    displayName: 'Orders MCP Server'
    description: 'MCP server backed by the Orders REST API'
    path: mcpServerId
    protocols: [ 'https' ]
    subscriptionRequired: true
  }
}

resource mcpTool 'Microsoft.ApiManagement/service/apis/tools@2025-09-01-preview' = {
  parent: mcpServer
  name: toolId
  properties: {
    displayName: toolId
    description: 'MCP tool backed by an API operation'
    operationId: resourceId(
      'Microsoft.ApiManagement/service/apis/operations',
      serviceName, backingApiId, backingOperationId
    )
  }
}

resource mcpPolicy 'Microsoft.ApiManagement/service/apis/policies@2025-09-01-preview' = {
  parent: mcpServer
  name: 'policy'
  properties: {
    format: 'rawxml'
    value: '''<policies>
  <inbound>
    <base />
    <rate-limit calls="100" renewal-period="60" />
  </inbound>
  <backend>
    <forward-request />
  </backend>
  <outbound>
    <base />
  </outbound>
</policies>'''
  }
}

resource product 'Microsoft.ApiManagement/service/products@2025-09-01-preview' existing = {
  parent: apimService
  name: productId
}

resource productBinding 'Microsoft.ApiManagement/service/products/apis@2025-09-01-preview' = {
  parent: product
  name: mcpServerId
  dependsOn: [ mcpServer ]
}

Para implantar:

# Use orders-mcp.json if you're deploying the ARM template.
az deployment group create \
  --resource-group <resource-group> \
  --template-file orders-mcp.bicep \
  --parameters serviceName=<api-management-name> \
               backingApiId=orders-api \
               backingOperationId=get-orders \
               toolId=getOrders

Servidor MCP de passagem

Esses modelos criam um servidor MCP de passagem que usa o transporte HTTP passível de transmissão. O escopo do servidor tem uma política de limitação de taxa, e o servidor se vincula a um produto existente. Os modelos não definem nenhum sub-recurso de ferramentas. O back-end externo determina a superfície da ferramenta.

Note

Os modelos a seguir usam transportType: streamable, que implementa a especificação HTTP streamable do MCP atual. Para usar o transporte SSE, defina transportTypesse e substitua a endpoints matriz por duas entradas: { "name": "sse", "uriTemplate": "/sse" } e { "name": "message", "uriTemplate": "/messages" }. No Bicep, use os mesmos valores com cadeias de caracteres entre aspas simples.

Pré-requisitos: um serviço de Gerenciamento de API existente, uma URL de back-end MCP acessível (backendUrl) que implementa os caminhos de transporte e ponto de extremidade selecionados e um produto existente (productId).

Parâmetro Obrigatório Default Description
serviceName Yes Nome da instância do serviço de Gerenciamento de API existente.
mcpServerId No external-mcp Nome do recurso para o novo servidor MCP. Deve ser único no serviço.
backendUrl Yes URL absoluta do backend MCP externo.
productId No starter Nome do recurso do produto existente ao qual associar o servidor.
@description('Name of the existing API Management service instance.')
param serviceName string

@description('Resource name for the new MCP server.')
param mcpServerId string = 'external-mcp'

@description('Absolute URL of the external MCP backend.')
param backendUrl string

@description('Resource name of the existing product to bind the MCP server to.')
param productId string = 'starter'

resource apimService 'Microsoft.ApiManagement/service@2025-09-01-preview' existing = {
  name: serviceName
}

resource mcpServer 'Microsoft.ApiManagement/service/apis@2025-09-01-preview' = {
  parent: apimService
  name: mcpServerId
  properties: {
    type: 'mcp'
    displayName: 'External MCP Server'
    description: 'Passthrough MCP server using streamable HTTP transport'
    path: mcpServerId
    protocols: [ 'https' ]
    serviceUrl: backendUrl
    subscriptionRequired: true
    mcpProperties: {
      transportType: 'streamable'
      endpoints: [
        {
          name: 'message'
          uriTemplate: '/mcp'
        }
      ]
    }
  }
}

resource mcpPolicy 'Microsoft.ApiManagement/service/apis/policies@2025-09-01-preview' = {
  parent: mcpServer
  name: 'policy'
  properties: {
    format: 'rawxml'
    value: '''<policies>
  <inbound>
    <base />
    <rate-limit calls="100" renewal-period="60" />
  </inbound>
  <backend>
    <forward-request />
  </backend>
  <outbound>
    <base />
  </outbound>
</policies>'''
  }
}

resource product 'Microsoft.ApiManagement/service/products@2025-09-01-preview' existing = {
  parent: apimService
  name: productId
}

resource productBinding 'Microsoft.ApiManagement/service/products/apis@2025-09-01-preview' = {
  parent: product
  name: mcpServerId
  dependsOn: [ mcpServer ]
}

Para implantar:

# Use external-mcp.json if you're deploying the ARM template.
az deployment group create \
  --resource-group <resource-group> \
  --template-file external-mcp.bicep \
  --parameters serviceName=<api-management-name> \
               backendUrl=https://mcp-backend.contoso.com

CLI do Azure

Atualmente, você pode usar az rest para chamar a API REST diretamente. O script a seguir cria um servidor MCP de passagem, anexa uma política de limite de taxa e a associa a um produto. Esse processo abrange o mesmo cenário que o modelo de Bicep na seção anterior.

Defina variáveis e execute as quatro az rest chamadas em ordem.

Note

az rest usa a credencial da sua sessão az login atual. Você não precisa de uma etapa de autenticação separada.

# Variables. Edit these for your environment
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
RESOURCE_GROUP="<your-resource-group>"
APIM_NAME="<your-apim-service-name>"
MCP_SERVER_ID="external-mcp"
BACKEND_URL="https://mcp-backend.contoso.com"
PRODUCT_ID="starter"
API_VERSION="2025-09-01-preview"

BASE="https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_NAME}"

# 1. Create the passthrough MCP server

az rest --method PUT \
  --uri "${BASE}/apis/${MCP_SERVER_ID}?api-version=${API_VERSION}" \
  --headers "If-Match=*" \
  --body '{
    "properties": {
      "type": "mcp",
      "displayName": "External MCP Server",
      "description": "Passthrough MCP server using streamable HTTP transport",
      "path": "external-mcp",
      "protocols": ["https"],
      "serviceUrl": "'"${BACKEND_URL}"'",
      "subscriptionRequired": true,
      "mcpProperties": {
        "transportType": "streamable",
        "endpoints": [
          { "name": "message", "uriTemplate": "/mcp" }
        ]
      }
    }
  }'

# 2. Attach a rate-limit policy at the server scope

az rest --method PUT \
  --uri "${BASE}/apis/${MCP_SERVER_ID}/policies/policy?api-version=${API_VERSION}" \
  --headers "If-Match=*" \
  --body '{
    "properties": {
      "format": "rawxml",
      "value": "<policies><inbound><base /><rate-limit calls=\"100\" renewal-period=\"60\" /></inbound><backend><forward-request /></backend><outbound><base /></outbound></policies>"
    }
  }'


# 3. Bind the server to a product

az rest --method PUT \
  --uri "${BASE}/products/${PRODUCT_ID}/apis/${MCP_SERVER_ID}?api-version=${API_VERSION}"

Cada etapa é idempotente. Executar novamente o script atualiza o recurso em vigor. Para verificar se o servidor foi criado, execute o seguinte comando:

az rest --method GET \
  --uri "${BASE}/apis/${MCP_SERVER_ID}?api-version=${API_VERSION}"

Terraform

O provedor Terraform do AzureRM ainda não tem recursos nativos para servidores MCP. Atualmente, você pode usar o azapi_resource tipo de recurso do provedor AzAPI, que permite gerenciar qualquer tipo de recurso Azure em qualquer versão da API. O exemplo a seguir reflete o modelo Bicep do servidor MCP de encaminhamento.

Pré-requisitos: um serviço de Gerenciamento de API existente, uma URL de back-end MCP acessível e um produto existente. Adicione o provedor AzAPI ao bloco terraform se ele ainda não estiver presente.

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">= 3.0"
    }
    azapi = {
      source  = "Azure/azapi"
      version = ">= 1.13"
    }
  }
}

provider "azurerm" {
  features {}
}

provider "azapi" {}

Variables

variable "resource_group_name" {
  description = "Name of the resource group containing the API Management service."
  type        = string
}

variable "service_name" {
  description = "Name of the existing API Management service instance."
  type        = string
}

variable "mcp_server_id" {
  description = "Resource name for the new MCP server."
  type        = string
  default     = "external-mcp"
}

variable "backend_url" {
  description = "Absolute URL of the external MCP backend."
  type        = string
}

variable "product_id" {
  description = "Resource name of the existing product to bind the server to."
  type        = string
  default     = "starter"
}

Resources

# Reference the existing API Management service
data "azurerm_api_management" "apim" {
  name                = var.service_name
  resource_group_name = var.resource_group_name
}

# 1. Create the passthrough MCP server
resource "azapi_resource" "mcp_server" {
  type      = "Microsoft.ApiManagement/service/apis@2025-09-01-preview"
  name      = var.mcp_server_id
  parent_id = data.azurerm_api_management.apim.id

  body = {
    properties = {
      type                = "mcp"
      displayName         = "External MCP Server"
      description         = "Passthrough MCP server using streamable HTTP transport"
      path                = var.mcp_server_id
      protocols           = ["https"]
      serviceUrl          = var.backend_url
      subscriptionRequired = true
      mcpProperties = {
        transportType = "streamable"
        endpoints = [
          {
            name        = "message"
            uriTemplate = "/mcp"
          }
        ]
      }
    }
  }
}

# 2. Attach a rate-limit policy at the server scope
resource "azapi_resource" "mcp_policy" {
  type      = "Microsoft.ApiManagement/service/apis/policies@2025-09-01-preview"
  name      = "policy"
  parent_id = azapi_resource.mcp_server.id

  body = {
    properties = {
      format = "rawxml"
      value  = "<policies><inbound><base /><rate-limit calls=\"100\" renewal-period=\"60\" /></inbound><backend><forward-request /></backend><outbound><base /></outbound></policies>"
    }
  }

  depends_on = [azapi_resource.mcp_server]
}

# 3. Bind the server to a product
resource "azapi_resource" "product_binding" {
  type      = "Microsoft.ApiManagement/service/products/apis@2025-09-01-preview"
  name      = var.mcp_server_id
  parent_id = "${data.azurerm_api_management.apim.id}/products/${var.product_id}"

  body = {}

  depends_on = [azapi_resource.mcp_server]
}

Para implantar:

Note

azapi_resource usa a autenticação do provedor AzAPI, que usa as mesmas az login credenciais da CLI do Azure. Você não precisa configurar a autenticação separada ao executar localmente.

terraform init
terraform apply \
  -var="resource_group_name=<resource-group>" \
  -var="service_name=<api-management-name>" \
  -var="backend_url=https://mcp-backend.contoso.com"

Padrões de CI/CD

  • Upserts idempotentes: envie solicitações PUT com If-Match: "*" para que o mesmo modelo seja aplicado independentemente de o recurso já existir ou não. 

  • Promover configurações entre ambientes: trate as definições do servidor MCP e as listas de ferramentas como artefatos controlados pela origem. Parametrize apenas valores específicos do ambiente, como o nome da instância e a URL de back-end. 

  • Gere a lista de ferramentas a partir da sua especificação de API: gere o sub-recurso de ferramentas a partir do seu arquivo OpenAPI de origem para que o conjunto de ferramentas permaneça sincronizado com a API subjacente à medida que ela evolui. 

  • Exclua na ordem correta: remova as referências à ferramenta MCP antes de excluir as APIs subjacentes ou as operações para as quais elas apontam. Caso contrário, a exclusão falhará devido a uma restrição de chave estrangeira.