Hantera MCP-servrar programmatiskt i API Management

I den här artikeln får du lära dig hur du skapar och hanterar MCP-servrar i Azure API Management med hjälp av REST API, ARM-mallar, Bicep, Azure CLI och Terraform. 

Important

Funktionerna för MCP-serverhantering som beskrivs i den här artikeln kräver API Management REST API version 2025-09-01-preview eller senare. Fäst den här versionen i varje begäran. 

Bakgrund om MCP-serverfunktioner finns i Om MCP-servrar i Azure API Management.

Förutsättningar

Resursmodell

Azure Resource Manager representerar MCP-servrar på följande sätt:

  • MCP-server: En API-resurs i API Management av typenMCP.

  • Vidarekopplande server: Pekar på en befintlig extern MCP-backend. MCP-serverresursen deklarerar serverdels-URL:en och transporttypen (strömmande HTTP eller SSE).

  • Verktyg: En API-verktygsunderresurs för en MCP-server. Du kan hantera verktygsresurser från CI/CD på ett säkert sätt. Du kan lägga till, byta namn på eller ta bort verktyg utan att återskapa MCP-servern.

  • Principer: Precis som med vanliga API:er bifogar du API-princip - eller principunderresurser till en MCP-server.

  • Produkter: Produktbindning är en separat underordnad relation (products/{productId}/apis/{mcpServerId}), vilket möjliggör oberoende distribution och bindning av flera produkter.

REST-exempel

För tydlighetens skull visar följande exempel förkortade svarskroppar. Fullständiga svarsscheman finns i API Management REST API-referensen.

Att lägga till If-Match: *-headern i PUT- och DELETE-anropsexemplen gör begärandena idempotenta. Det här huvudet gäller oavsett om resursen redan finns eller inte, vilket är det rekommenderade tillvägagångssättet för CI/CD-pipelines.

Innan du börjar

Ange följande variabler innan du kör något exempel. Alla exempel i det här avsnittet refererar till dessa variabler.

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)

Lista MCP-servrar

Returnerar alla API:er i instansen som filtrerats efter typ mcp. $top Använd frågeparametrarna och $skip för att bläddra igenom stora resultatuppsättningar.

Referens: Api – lista efter tjänst

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

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

Vanligt fel:401 Unauthorized. Bearertoken har gått ut. Kör tokenförvärvskommandot igen.


Hämta en enskild MCP-server

Referens: Api – Hämta

MCP_SERVER_ID="my-mcp-server"

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

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

Vanligt fel:404 Not Found. Bekräfta att mcpServerId matchar fältet name som returneras av List-åtgärden.


Skapa en REST API-backad MCP-server

Skapar MCP-serverresursen. När du har skapat dem lägger du till verktyg individuellt med hjälp av åtgärden Lägg till eller uppdatera ett verktyg . Varje verktyg hänvisar till en specifik åtgärd i en underliggande REST API-resurs.

Referens: Api – Skapa eller uppdatera

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

Svar (201 skapades)

{
  "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 förväntas för asynkrona PUT-åtgärder. Gör anrop mot den URL som returneras i svarshuvudet för svaret Azure-AsyncOperation för att bekräfta att processen har slutförts.

Vanligt fel:400 Bad Request. Se till att type är "mcp" och path är unikt i tjänstinstansen.


Skapa en passthrough-MCP-server

En vidarekopplingsserver vidarebefordrar alla MCP-begäranden direkt till en extern MCP-bakände. Ange mcpProperties.transportType för att matcha transporten som serverdelen implementerar.

Innan du skapar en genomströmningsserver kontrollerar du att serverdelen kan nås från API Management-gatewayen och implementerar den valda MCP-transporten på de slutpunktssökvägar som du konfigurerar. Om serverdelen kräver autentisering konfigurerar du nödvändiga autentiseringsuppgifter eller huvuden med hjälp av API Management-principer eller serverdelskonfiguration.

Referens: Api – Skapa eller uppdatera

Strömmande HTTP-transport

Använd streamable för backend-system som implementerar den aktuella specifikationen för MCP:s strömmande HTTP-transport. En enskild slutpunktsdefinition krävs.

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

Svar (201 skapades)

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

SSE-transport

Använd sse för serverdelar som implementerar HTTP+SSE-transporten (Server-Sent Events). Definiera två slutpunkter: en för SSE-händelseströmmen och en för meddelandekanalen.

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

Vanliga fel:

  • 400 Bad Request. Ogiltig mcpProperties. Verifiera transportType är streamable eller sse, och varje uriTemplate börjar med /.
  • 400 Bad Request. SSE-transport kräver exakt två slutpunkter (sse och message). Streamable transport kräver en (message).

Lägga till eller uppdatera ett verktyg

Lägger till ett nytt verktyg till en REST API-backad MCP-server eller uppdaterar en befintlig. Fältet operationId länkar verktyget till en specifik åtgärd i en rest-API-resurs. Du kan lägga till, uppdatera eller ta bort verktyg oberoende av varandra utan att återskapa den överordnade servern.

Referens: Api Tool – Skapa eller uppdatera

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

Svar (201 skapades)

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

Vanliga fel:

  • 400 Bad Request. Sökvägen operationId är felaktigt formaterad eller så finns inte den refererade åtgärden.
  • 404 Not Found. Den överordnade MCP-servern finns inte. Skapa servern innan du lägger till verktyg.

Ta bort ett verktyg

Tar bort ett verktyg från en MCP-server. Ta bort verktyg innan du tar bort de REST API-åtgärder som de hänvisar till. Annars misslyckas borttagningen med ett beroendefel.

Referens: Api Tool – Ta bort

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

Svar:200 OK om framgång.

Vanligt fel:412 Precondition FailedIf-Match krävs för borttagningar. Använd If-Match: * för att matcha valfri ETag.


Tillämpa en princip på MCP-nivå

Skapar eller ersätter principdokumentet som är kopplat till en MCP-server. Servern utvärderar principer i det här omfånget för varje verktygsanrop. Formatet rawxml accepterar okodad princip-XML.

Referens: API-princip – Skapa eller uppdatera

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

Svar (200 OK)

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

Vanligt fel:400 Bad Request. Felaktigt formaterad policy-XML. Verifiera dokumentet innan du skickar det.


Binda en MCP-server till en produkt

Associerar MCP-servern med en produkt, så att prenumeranter av den produkten kan anropa serverns verktyg. Begäran har inget innehåll.

När du binder MCP-servern till en produkt gör du den tillgänglig via den produkten, men klienterna behöver fortfarande åtkomst enligt produktens konfiguration. Om produkten kräver prenumerationer måste klienten använda en giltig prenumerationsnyckel för den produkten.

Referens: Produkt-API – Skapa eller uppdatera

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"

Svar:201 Created med MCP-serverns API-kontrakt i brödtexten.

Vanligt fel:404 Not Found. Kontrollera att både productId och mcpServerId finns innan du skapar bindningen.


Ta bort en MCP-server

Tar bort en MCP-server och alla dess underresurser för verktyg och principer. Innan du tar bort servern tar du bort alla verktyg som refererar till åtgärder i api:er för säkerhetskopiering. Annars kan du inte ta bort dessa åtgärder medan verktygsreferensen finns.

Referens: Api – Ta bort

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

Svar:200 OK om framgång.

Vanligt fel:412 Precondition Failed. If-Match krävs för borttagningar. Använd If-Match: * för att kringgå ETag-kontroll.

ARM- och Bicep-mallar

Följande mallar distribuerar en fullständig MCP-serverkonfiguration i en enda distribution. Varje mall förutsätter en befintlig API Management-tjänstinstans och använder en parametertabell så att du kan återanvända samma fil mellan miljöer genom att bara ändra parametervärdena.

MCP-server driven av REST API

Dessa mallar skapar en MCP-server, definierar ett verktyg som motsvarar en åtgärd i ett underliggande befintligt REST-API, tillämpar en princip för hastighetsbegränsning på servernivå och knyter servern till en befintlig produkt. Du kan utföra alla dessa uppgifter i en enda distribution.

Förutsättningar: en befintlig API Management-tjänst, ett REST API (backingApiId) med minst en åtgärd (backingOperationId) och en befintlig produkt (productId).

Parameter Obligatoriskt Standardvärde Description
serviceName Ja Namnet på den befintliga API Management-tjänstinstansen.
mcpServerId No orders-mcp Resursnamn för den nya MCP-servern. Måste vara unikt i tjänsten.
backingApiId Ja Resursnamn för det befintliga REST-API:et som stöder den här MCP-servern.
backingOperationId Ja Resursnamnet på åtgärden som ska exponeras som ett verktyg.
toolId No sampleTool Resursnamn och visningsnamn för MCP-verktyget som ska skapas.
productId No starter Resursnamnet på den befintliga produkten som servern ska bindas till.
@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 ]
}

Så här distribuerar du:

# 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

Genomströmnings-MCP-server

Dessa mallar skapar en vidarebefordrande MCP-server som använder den strömbara HTTP-transporten. Serveromfånget har en hastighetsbegränsningsprincip och servern binder till en befintlig produkt. Mallarna definierar inte några verktygsunderresurser. Den externa backenden avgör verktygsgränssnittet.

Note

Följande mallar använder transportType: streamable, som implementerar den aktuella MCP-strömmande HTTP-specifikationen. Om du vill använda SSE-transport i stället anger du transportType till sse och ersätter matrisen endpoints med två poster: { "name": "sse", "uriTemplate": "/sse" } och { "name": "message", "uriTemplate": "/messages" }. I Bicep använder du samma värden med enciterade strängar.

Förutsättningar: en befintlig API Management-tjänst, en nåbar MCP-backend-URL (backendUrl) som implementerar de valda transport- och slutpunktssökvägarna, och en befintlig produkt (productId).

Parameter Obligatoriskt Standardvärde Description
serviceName Ja Namnet på den befintliga API Management-tjänstinstansen.
mcpServerId No external-mcp Resursnamn för den nya MCP-servern. Måste vara unikt i tjänsten.
backendUrl Ja Absolut URL för den externa MCP-bakändan.
productId No starter Resursnamnet på den befintliga produkten som servern ska bindas till.
@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 ]
}

Så här distribuerar du:

# 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

Azure CLI

För närvarande kan du använda az rest för att anropa REST-API:et direkt. Följande skript skapar en MCP-server för vidarebefordran, tillämpar en princip för hastighetsbegränsning och binder den till en produkt. Den här processen omfattar samma scenario som mallen Bicep i föregående avsnitt.

Ange variabler och kör sedan de fyra az rest anropen i ordning.

Note

az rest använder autentiseringsuppgifterna från den aktuella az login sessionen. Du behöver inte ett separat autentiseringssteg.

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

Varje steg är idempotent. Om du kör skriptet igen uppdateras resursen på plats. Kontrollera att servern har skapats genom att köra följande kommando:

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

Terraform

AzureRM Terraform-providern har ännu inte inbyggda resurser för MCP-servrar. För närvarande kan du använda azapi_resource resurstypen från AzAPI-providern, vilket gör att du kan hantera alla Azure resurstyper mot valfri API-version. Följande exempel motsvarar Bicep-mallen för MCP-passthrough-servern.

Förutsättningar: en befintlig API Management-tjänst, en nåbar MCP-serverdels-URL och en befintlig produkt. Lägg till AzAPI-providern i blocket terraform om den inte redan finns.

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

provider "azurerm" {
  features {}
}

provider "azapi" {}

Variabler

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

Så här distribuerar du:

Note

azapi_resource använder AzAPI-providerns autentisering, som använder samma az login autentiseringsuppgift som Azure CLI. Du behöver inte konfigurera separat autentisering när du kör lokalt.

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

CI/CD-mönster

  • Idempotent upserts: Skicka PUT-begäranden med If-Match: "*" så att samma mall gäller om resursen redan finns eller inte. 

  • Höj upp konfigurationer mellan miljöer: Behandla MCP-serverdefinitioner och verktygslistor som källkontrollerade artefakter. Parameterisera endast miljöspecifika värden, till exempel instansnamn och serverdels-URL. 

  • Generera verktygslistan från din API-specifikation: Styr verktygens underresurs från din OpenAPI-källfil så att verktygsgränssnittet förblir synkroniserat med det bakomliggande API:et i takt med att det utvecklas. 

  • Ta bort i rätt ordning: Ta bort MCP-verktygsreferenser innan du tar bort de API:er eller åtgärder som de pekar på. Annars misslyckas borttagningen vid kontroll av främmande nyckel.