Administración de servidores MCP mediante programación en API Management

En este artículo, aprenderá a crear y administrar servidores MCP en Azure API Management mediante la API REST, plantillas de ARM, Bicep, el CLI de Azure y Terraform. 

Important

Las características de administración del servidor MCP que se describen en este artículo requieren la versión 2025-09-01-preview o posterior de la API REST de API Management. Incluye esta versión en todas las solicitudes. 

Para obtener información sobre las funcionalidades del servidor MCP, consulte Acerca de los servidores MCP en Azure API Management.

Prerrequisitos

Modelo de recursos

Azure Resource Manager representa servidores MCP de la siguiente manera:

  • Servidor MCP: Un recurso API Management de API de tipoMCP.

  • Servidor de paso: Apunta a un backend de MCP externo existente. El recurso del servidor MCP declara la URL del backend y el tipo de transporte (HTTP de transmisión o SSE).

  • Herramienta: Un subrecurso de la herramienta de API de un servidor MCP. Puede administrar recursos de herramientas de forma segura desde CI/CD. Puede agregar, cambiar el nombre o quitar herramientas sin volver a crear el servidor MCP.

  • Directivas: Al igual que con las API normales, adjunte la directiva de API o los subrecursos de directiva a un servidor MCP.

  • Productos: El enlace de productos es una relación secundaria independiente (products/{productId}/apis/{mcpServerId}), lo que permite la implementación independiente y el enlace de varios productos.

Ejemplos de REST

Para mayor claridad, los ejemplos siguientes muestran cuerpos de respuesta abreviados. Para consultar los esquemas de respuesta completos, consulte la referencia de la API REST de API Management.

Al añadir el encabezado If-Match: * en los ejemplos de llamadas PUT y DELETE, las solicitudes se vuelven idempotentes. Este encabezado se aplica tanto si el recurso ya existe como si no, y esta es la práctica recomendada para las canalizaciones de CI/CD.

Antes de empezar

Establezca las siguientes variables antes de ejecutar cualquier ejemplo. Todos los ejemplos de esta sección hacen referencia a estas variables.

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)

Enumerar servidores MCP

Devuelve todas las API de la instancia filtradas por el tipo mcp. Utiliza los parámetros de consulta $top y $skip para navegar por conjuntos de resultados de gran tamaño.

Referencia: Api - List By Service

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

Respuesta (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" ]
      }
    }
  ]
}

Error común:401 Unauthorized. El token de portador ha expirado. Vuelva a ejecutar el comando de adquisición de tokens.


Obtención de un único servidor MCP

Referencia: Api - Get

MCP_SERVER_ID="my-mcp-server"

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

Respuesta (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"
  }
}

Error común:404 Not Found. Confirme que mcpServerId coincide con el name campo devuelto por la operación List.


Creación de un servidor MCP respaldado por la API REST

Crea el recurso del servidor MCP. Después de la creación, agregue herramientas a ella individualmente mediante la operación Agregar o actualizar una herramienta . Cada herramienta hace referencia a una operación específica en un recurso de API REST de respaldo.

Referencia: Api: Creación o actualización

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"]
    }
  }'

Respuesta (201 creado)

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

Se espera provisioningState: InProgress para operaciones PUT asíncronas. Consulta la URL devuelta en el encabezado de respuesta Azure-AsyncOperation para confirmar la finalización.

Error común:400 Bad Request. Asegúrese de que type sea "mcp" y que path sea único dentro de la instancia del servicio.


Crea un servidor MCP de tipo passthrough

Un servidor de paso a través reenvía todas las solicitudes MCP directamente a un back-end de MCP externo. Establezca mcpProperties.transportType para que coincida con el transporte que implementa el back-end.

Antes de crear un servidor de acceso directo, confirme que el back-end es accesible desde la puerta de enlace de API Management e implementa el transporte MCP seleccionado en las rutas de acceso del punto de conexión que configure. Si el back-end requiere autenticación, configure las credenciales o encabezados necesarios mediante directivas de API Management o configuración de back-end.

Referencia: Api: Creación o actualización

Transporte HTTP que se puede transmitir

Utilice streamable para los backends que implementan la especificación actual de transporte HTTP en streaming de MCP. Se requiere una definición de punto de conexión único.

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" }
        ]
      }
    }
  }'

Respuesta (201 creado)

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

Utilice sse para los backends que implementan el transporte HTTP+SSE (eventos enviados por el servidor). Defina dos puntos de conexión: uno para el flujo de eventos SSE y otro para el canal de mensajes.

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" }
        ]
      }
    }
  }'

Errores comunes:

  • 400 Bad Request. No válido mcpProperties. Compruebe transportType que es streamable o ssey cada uriTemplate comienza por /.
  • 400 Bad Request. El transporte SSE requiere exactamente dos puntos de conexión (sse y message). El transporte streamable requiere uno (message).

Agregar o actualizar una herramienta

Agrega una nueva herramienta a un servidor MCP respaldado por la API REST o actualiza uno existente. El operationId campo vincula la herramienta a una operación específica en un recurso de API REST de respaldo. Puede agregar, actualizar o quitar herramientas de forma independiente sin volver a crear el servidor primario.

Referencia: Herramienta de API: Crear o actualizar

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}\"
    }
  }"

Respuesta (201 creado)

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

Errores comunes:

  • 400 Bad Request. La operationId ruta de acceso tiene un formato incorrecto o la operación a la que se hace referencia no existe.
  • 404 Not Found. El servidor MCP primario no existe. Cree el servidor antes de agregar herramientas.

Eliminar una herramienta

Quita una herramienta de un servidor MCP. Elimine las herramientas antes de eliminar las operaciones de la API REST subyacentes a las que hacen referencia; de lo contrario, la eliminación falla con un error de dependencia.

Referencia: Herramienta de 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: *"

Respuesta:200 OK en caso de éxito.

Error común:412 Precondition Failed : If-Match es necesario para las eliminaciones. Utilice If-Match: * para que coincida con cualquier ETag.


Aplicar una directiva en el ámbito de MCP

Crea o reemplaza el documento de directiva adjunto a un servidor MCP. El servidor evalúa las directivas en este ámbito para cada invocación de herramienta. El rawxml formato acepta XML de directiva sin codificar.

Referencia: Directiva de API: crear o actualizar

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}\"}}"

Respuesta (200 OK)

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

Error común:400 Bad Request. XML de directiva con formato incorrecto. Valide el documento antes de enviarlo.


Enlace de un servidor MCP a un producto

Asocia el servidor MCP a un producto, por lo que los suscriptores de ese producto pueden llamar a las herramientas del servidor. La solicitud no tiene cuerpo.

Al enlazar el servidor MCP a un producto, lo hace disponible a través de ese producto, pero los clientes siguen necesitando acceso según la configuración del producto. Si el producto requiere suscripciones, el cliente debe usar una clave de suscripción válida para ese producto.

Referencia: API del producto - Crear o actualizar

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"

Respuesta:201 Created con el contrato de API del servidor MCP en el cuerpo.

Error común:404 Not Found. Compruebe que productId y mcpServerId existan antes de crear la vinculación.


Eliminación de un servidor MCP

Elimina un servidor MCP y todos sus subrecursos de herramientas y directivas. Antes de eliminar el servidor, quite las herramientas que hagan referencia a las operaciones de respaldo de las API; De lo contrario, no puede eliminar esas operaciones mientras existe la referencia de la herramienta.

Referencia: Api - Delete

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: *"

Respuesta:200 OK en caso de éxito.

Error común:412 Precondition Failed. Se requiere If-Match para las eliminaciones. Use If-Match: * para omitir la comprobación de ETag.

Plantillas de ARM y Bicep

Las plantillas siguientes implementan una configuración completa del servidor MCP en una sola implementación. Cada plantilla supone una instancia de servicio de API Management existente y usa una tabla de parámetros para que pueda reutilizar el mismo archivo entre entornos cambiando solo los valores de parámetro.

Servidor MCP respaldado por la API REST

Estas plantillas crean un servidor MCP, definen una herramienta que se asigna a una operación en una API REST de respaldo existente, adjuntan una directiva de límite de velocidad en el ámbito del servidor y enlazan el servidor a un producto existente. Puede realizar todas estas tareas en una sola implementación.

Requisitos previos: un servicio DE API Management existente, una API REST (backingApiId) con al menos una operación (backingOperationId) y un producto existente (productId).

Parameter Obligatorio Valor predeterminado Description
serviceName Nombre de la instancia del servicio API Management existente.
mcpServerId No orders-mcp Nombre del recurso para el nuevo servidor MCP. Debe ser único dentro del servicio.
backingApiId Nombre de recurso de la API REST existente que respalda este servidor MCP.
backingOperationId Nombre del recurso de la operación que se va a exponer como herramienta.
toolId No sampleTool Nombre del recurso y nombre para mostrar de la herramienta MCP que se va a crear.
productId No starter Nombre de recurso del producto existente al que se va a enlazar el 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 desplegar:

# 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 paso directo

Estas plantillas crean un servidor MCP de paso que utiliza el transporte HTTP streamable. El ámbito del servidor tiene una directiva de límite de velocidad y el servidor se enlaza a un producto existente. Las plantillas no definen ningún subrecurso de herramientas. El back-end externo determina la superficie de la herramienta.

Note

Las plantillas siguientes usan transportType: streamable, que implementa la especificación HTTP actual que se puede transmitir con MCP. Para usar el transporte SSE en su lugar, establezca transportType en sse y reemplace el array endpoints por dos elementos: { "name": "sse", "uriTemplate": "/sse" } y { "name": "message", "uriTemplate": "/messages" }. En Bicep, utilice los mismos valores con cadenas entre comillas simples.

Requisitos previos: un servicio de API Management existente, una URL del backend de MCP accesible (backendUrl) que implemente las rutas del transporte y del punto de conexión seleccionados, y un producto existente (productId).

Parameter Obligatorio Valor predeterminado Description
serviceName Nombre de la instancia del servicio API Management existente.
mcpServerId No external-mcp Nombre del recurso para el nuevo servidor MCP. Debe ser único dentro del servicio.
backendUrl URL absoluta del servidor externo de MCP.
productId No starter Nombre de recurso del producto existente al que se va a enlazar el 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 desplegar:

# 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 de Azure

Actualmente, puede usar az rest para llamar directamente a la API REST. El script siguiente crea un servidor MCP de acceso directo, adjunta una directiva de límite de velocidad y la enlaza a un producto. Este proceso cubre el mismo escenario que la plantilla de Bicep en la sección anterior.

Establezca variables y, a continuación, ejecute las cuatro az rest llamadas en orden.

Note

az rest usa las credenciales de tu sesión actual de az login. No necesita un paso de autenticación independiente.

# 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 paso es idempotente. Al volver a ejecutar el script, se actualiza el recurso en su lugar. Para comprobar que se creó el servidor, ejecute el siguiente comando:

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

Terraform

El proveedor de Terraform de AzureRM aún no tiene recursos nativos para los servidores MCP. Actualmente, puede usar el azapi_resource tipo de recurso del proveedor AzAPI, que le permite administrar cualquier tipo de recurso Azure en cualquier versión de API. El siguiente ejemplo reproduce la plantilla Bicep del servidor MCP de paso.

Requisitos previos: un servicio de API Management existente, una dirección URL de back-end de MCP accesible y un producto existente. Añada el proveedor AzAPI en el bloque terraform si todavía no está 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 desplegar:

Note

azapi_resource usa la autenticación del proveedor AzAPI, que utiliza la misma credencial az login que CLI de Azure. No es necesario configurar la autenticación independiente al ejecutarse 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"

Patrones de CI/CD

  • Upserts idempotentes: envía solicitudes PUT con If-Match: "*" para que se aplique la misma plantilla tanto si el recurso ya existe como si no. 

  • Promover configuraciones entre entornos: trate las definiciones de servidor MCP y las listas de herramientas como artefactos controlados por código fuente. Parametrizar solo valores específicos del entorno, como el nombre de instancia y la dirección URL de back-end. 

  • Genere la lista de herramientas a partir de la especificación de API: impulse los subrecursos de herramientas desde el archivo OpenAPI de origen para que la superficie de herramientas permanezca sincronizada con la API de respaldo a medida que evoluciona. 

  • Eliminar en el orden correcto: quite las referencias de la herramienta MCP antes de eliminar las API de respaldo o las operaciones a las que apuntan. De lo contrario, la eliminación generará un error al comprobar la clave foránea.