Gerir servidores MCP programaticamente na Gestão de APIs

Neste artigo, aprende a criar e gerir servidores MCP no API Management do Azure usando a API REST, templates ARM, Bicep, CLI do Azure e Terraform. 

Importante

As funcionalidades de gestão de servidores MCP descritas neste artigo requerem API Management REST API versão 2025-09-01-preview ou posterior. Afixe esta versão em todas as solicitações. 

Para informações sobre as capacidades dos servidores MCP, veja Sobre os servidores MCP no API Management do Azure.

Pré-requisitos

Modelo de recursos

Azure Resource Manager representa os servidores MCP da seguinte forma:

  • Servidor MCP: Um recurso API de Gestão de APIs do tipoMCP.

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

  • Ferramenta: Um sub-recurso de ferramenta API de um servidor MCP. Podes gerir recursos de ferramentas em segurança a partir do CI/CD. Pode adicionar, renomear ou remover ferramentas sem recriar o servidor MCP.

  • Políticas: Tal como nas APIs normais, anexe os sub-recursos política de API ou política a um servidor MCP.

  • Produtos: A associação de produto é uma relação subordinada autónoma (products/{productId}/apis/{mcpServerId}), permitindo a implementação autónoma e a associação a vários produtos.

Exemplos REST

Para maior clareza, os exemplos seguintes mostram corpos de resposta abreviados. Para esquemas completos de resposta, consulte a referência da API REST do API Management.

Adicionar o cabeçalho If-Match: * nos exemplos de pedidos PUT e DELETE torna os pedidos idempotentes. Este cabeçalho aplica-se independentemente de o recurso já existir ou não, que é o padrão recomendado para pipelines CI/CD.

Antes de começares

Defina as seguintes variáveis antes de executar qualquer exemplo. Todos os exemplos nesta secção fazem referência a estas 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

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

Referência: Api - Lista 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 está expirado. Reexecute o comando de aquisição de tokens.


Arranja um único servidor MCP

Referência: Api - Get

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 que mcpServerId corresponde ao name campo devolvido pela operação Lista.


Criar um servidor MCP apoiado por API REST

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

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 Criada)

{
  "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 espera-se para operações de PUT assíncronas. Consulte o URL devolvido no cabeçalho de resposta Azure-AsyncOperation para confirmar a conclusão.

Erro comum:400 Bad Request Certifique-se de que type é "mcp" e de que path é única dentro da instância de serviço.


Criar um servidor MCP de passagem

Um servidor passthrough encaminha todos os pedidos MCP diretamente para um backend MCP externo. Define mcpProperties.transportType para corresponder ao transporte que o teu backend implementa.

Antes de criar um servidor de passagem, confirme que o sistema de back-end está acessível a partir do gateway do API Management e implementa o transporte MCP selecionado nos caminhos dos pontos finais que configurar. Se o backend exigir autenticação, configure as credenciais ou cabeçalhos necessários usando políticas de gestão de API ou configuração do backend.

Referência: API - Criar ou Atualizar

Transporte HTTP transmissível

Utilize streamable para back-ends que implementem a especificação atual do MCP para transporte HTTP por fluxo. É necessária uma única definição de endpoint.

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 Criada)

{
  "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

Utilize sse para back-ends que implementam o transporte HTTP+SSE (Eventos Enviados pelo Servidor). Defina dois endpoints: um para o fluxo de eventos SSE e outro para o canal de mensagens.

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 transportType se é streamable ou sse, e todos uriTemplate começam por /.
  • 400 Bad Request. O transporte SSE requer exatamente dois pontos finais (sse e message). O transporte por streaming requer um (message).

Adicionar ou atualizar uma ferramenta

Adiciona uma nova ferramenta a um servidor MCP apoiado por API REST, ou atualiza um existente. O operationId campo liga a ferramenta a uma operação específica num recurso de API REST de apoio. Pode adicionar, atualizar ou remover ferramentas de forma independente sem recriar o servidor principal.

Referência: Ferramenta 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 Criada)

{
  "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 principal não existe. Crie o servidor antes de adicionar ferramentas.

Eliminar uma ferramenta

Remove uma ferramenta de um servidor MCP. Elimine as ferramentas antes de eliminar as operações da API REST subjacentes a que estas fazem referência; caso contrário, a operação de eliminação falhará com um erro de dependência.

Referência: Ferramenta API - Eliminar

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 em caso de sucesso.

Erro comum:412 Precondition FailedIf-Match é necessária para eliminações. Utilize If-Match: * para corresponder a qualquer ETag.


Aplicar uma política ao nível do MCP

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

Referência: Api Policy - 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 Política mal formada em XML. Valide o documento antes de o enviar.


Vincular um servidor MCP a um produto

Associa o servidor MCP a um produto, para que os assinantes desse produto possam aceder às ferramentas do servidor. O pedido não tem corpo.

Quando vincula o servidor MCP a um produto, torna-o disponível através desse produto, mas os clientes ainda precisam de acesso de acordo com a configuração do produto. Se o produto exigir subscrições, o cliente deve usar uma chave de subscrição válida para esse produto.

Referência: Product API - 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 ambos productId e mcpServerId existem antes de criar a ligação.


Eliminar um servidor MCP

Elimina um servidor MCP e todos os seus subrecursos de ferramentas e políticas. Antes de eliminar o servidor, remova quaisquer ferramentas que referenciam operações de backing APIs; caso contrário, não pode apagar essas operações enquanto a referência da ferramenta existir.

Referência: Api - Eliminar

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 em caso de sucesso.

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

Modelos ARM e Bicep

Os modelos seguintes implementam uma configuração completa de servidor MCP numa única implementação. Cada modelo assume uma instância existente de serviço de Gestão de API e utiliza uma tabela de parâmetros para que possa reutilizar o mesmo ficheiro entre ambientes alterando apenas os valores dos parâmetros.

Servidor MCP apoiado por API REST

Estes templates criam um servidor MCP, definem uma ferramenta que corresponde a uma operação numa API REST de suporte existente, anexam uma política de limite de taxa no âmbito do servidor e associam o servidor a um produto existente. Podes fazer todas estas tarefas numa única implementação.

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

Parâmetro Obrigatório Predefinição Description
serviceName Sim Nome da instância existente do serviço de Gestão de APIs.
mcpServerId No orders-mcp Nome do recurso para o novo servidor MCP. Tem de ser único dentro do serviço.
backingApiId Sim Nome do recurso da API REST existente que suporta este servidor MCP.
backingOperationId Sim Nome do recurso da operação a expor como uma ferramenta.
toolId No sampleTool Nome do recurso e nome de exibição da ferramenta MCP a criar.
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 implementar:

# 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

Estes modelos criam um servidor MCP de passagem que utiliza transporte HTTP transmissível em fluxo. O âmbito do servidor tem uma política de limite de taxa, e o servidor vincula-se a um produto existente. Os templates não definem sub-recursos de ferramentas. O backend externo determina a superfície da ferramenta.

Note

Os modelos seguintes utilizam transportType: streamable, que implementa a especificação HTTP transmissível atual do MCP. Para usar o transporte SSE em vez disso, defina transportType e sse substitua o endpoints array por duas entradas: { "name": "sse", "uriTemplate": "/sse" } e { "name": "message", "uriTemplate": "/messages" }. No Bicep, usa os mesmos valores com cadeias de aspas simples.

Pré-requisitos: um serviço de Gestão de API existente, uma URL de backend MCP acessível (backendUrl) que implementa os caminhos selecionados de transporte e endpoint, e um produto existente (productId).

Parâmetro Obrigatório Predefinição Description
serviceName Sim Nome da instância existente do serviço de Gestão de APIs.
mcpServerId No external-mcp Nome do recurso para o novo servidor MCP. Tem de ser único dentro do serviço.
backendUrl Sim 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 implementar:

# 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, pode usar az rest para aceder diretamente à API REST. O script seguinte cria um servidor MCP passthrough, anexa uma política de limite de taxa e liga-a a um produto. Este processo cobre o mesmo cenário do modelo Bicep na secção anterior.

Define variáveis e depois executa as quatro az rest chamadas por ordem.

Note

az rest Usa a credencial da tua sessão atual az login . Não precisas de um passo de autenticação separado.

# 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 passo é idempotente. Reexecutar o script atualiza o recurso no local. 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 fornecedor AzureRM Terraform ainda não tem recursos nativos para servidores MCP. Atualmente, pode usar o azapi_resource tipo de recurso do fornecedor AzAPI, que lhe permite gerir qualquer tipo de recurso Azure contra qualquer versão da API. O exemplo seguinte espelha o modelo Bicep do servidor MCP passthrough.

Pré-requisitos: um serviço de gestão de API existente, um URL de backend MCP acessível e um produto existente. Adicione o fornecedor AzAPI ao bloco terraform se 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" {}

Variáveis

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 implementar:

Note

azapi_resource utiliza a autenticação do provedor AzAPI, que recorre à mesma az login credencial que a CLI do Azure. Não precisas de configurar autenticação separada ao correr 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 CI/CD

  • Upserts idempotentes: Enviar pedidos PUT com If-Match: "*" para que o mesmo modelo se aplique independentemente de o recurso já existir ou não. 

  • Promover configurações em diferentes ambientes: Tratar as definições de servidores MCP e as listas de ferramentas como artefactos controlados por código-fonte. Parametrize apenas valores específicos do ambiente, como nome da instância e URL do backend. 

  • Gera a lista de ferramentas a partir da especificação da tua API: Conduz o sub-recurso de ferramentas a partir do teu ficheiro OpenAPI de origem para que a superfície da ferramenta se mantenha sincronizada com a API de suporte à medida que esta evolui. 

  • Apagar pela ordem correta: Remover referências às ferramentas MCP antes de eliminar as APIs de backup ou operações para as quais apontam. Caso contrário, a eliminação falha numa verificação de chave estrangeira.