在 API Management 中以程式化方式管理 MCP 伺服器

在本文中,你將學習如何利用 REST API、ARM 範本、Bicep、Azure CLI 和 Terraform 在 Azure API 管理 中建立和管理 MCP 伺服器。 

Important

本文所述的 MCP 伺服器管理功能需要 API Management REST API 版本 2025-09-01-preview 或更新版本。 在每個請求中固定此版本。 

關於 MCP 伺服器功能的背景,請參閱 Azure API 管理 中的 MCP 伺服器。

Prerequisites

資源模型

Azure Resource Manager 對 MCP 伺服器的表示如下:

  • MCP 伺服器:API Management 中屬於 類型 的 MCP 資源。

  • 直通伺服器: 指向現有的外部 MCP 後端。 MCP 伺服器資源宣告後端 URL 與傳輸類型(可串流 HTTP 或 SSE)。

  • 工具: MCP 伺服器的 API 工具 子資源。 你可以安全地從 CI/CD 管理工具資源。 你可以新增、重新命名或移除工具,而不必重新建立 MCP 伺服器。

  • 政策: 與一般 API 一樣,將 API 政策 或 政策 子資源附加到 MCP 伺服器。

  • 產品: 產品綁定是一個獨立的子關係(),products/{productId}/apis/{mcpServerId}使得獨立部署與多產品綁定成為可能。

REST 範例

為了清楚起見,以下範例展示了簡略的反應體。 完整回應結構請參見 API Management REST API 參考。

在 PUT 和 DELETE 呼叫範例中加入 If-Match: * 標頭,使請求成為冪等元。 此標頭無論資源是否已存在都適用,這是 CI/CD 管線的推薦模式。

開始之前

在執行任何範例前,請先設定以下變數。 本節中所有範例皆參考這些變數。

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)

列出 MCP 伺服器

回傳實例中所有篩選為類型 mcp 的 API。 使用 $top 和 $skip 查詢參數對大型結果集進行分頁。

參考資料: API - 依服務列表

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

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

常見錯誤:401 Unauthorized 持有者代幣已過期。 重新執行代幣取得指令。


買一台 MCP 伺服器

參考資料: API - 取得

MCP_SERVER_ID="my-mcp-server"

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

回應(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"
  }
}

常見錯誤:404 Not Found 確認 mcpServerId 與 List 作業傳回的 name 欄位相符。


建立一個以 REST API 為支援的 MCP 伺服器

建立 MCP 伺服器資源。 建立後,請使用 新增或更新工具 操作,逐一新增工具。 每個工具都會參考 REST API 資源中的特定操作。

參考資料: API - 建立或更新

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

回應(201 已建立)

{
  "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 預期用於非同步 PUT 操作。 輪詢回應標題中 Azure-AsyncOperation 回傳的 URL 以確認完成。

常見錯誤:400 Bad Request 確保type是"mcp"path且在服務實例中是唯一的。


建立一個直通式 MCP 伺服器

直通伺服器會直接將所有 MCP 請求轉發到外部 MCP 後端。 設定 mcpProperties.transportType 成與後端實作的傳輸方式相匹配。

在建立直通伺服器前,先確認後端可從 API 管理閘道存取,並在你設定的端點路徑上實作所選的 MCP 傳輸。 若後端需要驗證,請透過 API 管理策略或後端設定來設定所需的憑證或標頭。

參考資料: API - 建立或更新

可串流的 HTTP 傳輸

將 streamable 用於實作目前 MCP 可串流 HTTP 傳輸規範的後端。 需要單一端點定義。

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

回應(201 已建立)

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

對於實作 HTTP+SSE(伺服器傳送事件)傳輸機制的後端,請使用 sse。 定義兩個端點:一個負責 SSE 事件串流,另一個負責訊息通道。

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

常見錯誤:

  • 400 Bad Request。 無效 mcpProperties。 驗證transportType為streamable或sse,並確認每個uriTemplate都以/開頭。
  • 400 Bad Request。 SSE 傳輸需要恰好兩個端點(sse 與 message)。 串流傳輸需要一個 (message)。

新增或更新工具

為 REST API 支援的 MCP 伺服器新增工具,或更新現有工具。 欄位將 operationId 工具連結到支援 REST API 資源中的特定操作。 你可以獨立新增、更新或移除工具,而不必重建母伺服器。

參考資料: API 工具 - 建立或更新

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

回應(201 已建立)

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

常見錯誤:

  • 400 Bad Request。 operationId路徑形狀異常,或是參考的操作不存在。
  • 404 Not Found。 母 MCP 伺服器不存在。 先建立伺服器再加工具。

刪除工具

從 MCP 伺服器移除工具。 刪除工具後再刪除它們參考的 REST API 操作;否則,刪除會因依賴性錯誤而失敗。

參考資料: API 工具 - 刪除

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

回應:200 OK 關於成功。

常見錯誤:412 Precondition Failed —— If-Match 是刪除的必要條件。 用 If-Match: * 來匹配任何 ETag。


在 MCP 範圍套用原則

建立或替換附加於 MCP 伺服器的政策文件。 伺服器會針對每次工具調用評估此範圍內的政策。 此 rawxml 格式接受未編碼的政策 XML。

參考資料: API 政策 - 建立或更新

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

回應(200 OK)

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

常見錯誤:400 Bad Request 格式錯誤的原則 XML。 寄出前請驗證文件。


將 MCP 伺服器綁定到產品

將 MCP 伺服器與產品關聯,讓該產品的訂閱者能呼叫伺服器的工具。 這個請求沒有實體。

當你將 MCP 伺服器綁定到產品時,你是透過該產品讓它可用,但客戶端仍需依產品設定存取權限。 若產品需要訂閱,客戶端必須使用該產品的有效訂閱金鑰。

參考資料: Product API - 建立或更新

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"

回應:201 Created,MCP 伺服器的 API 合約則在主體中。

常見錯誤:404 Not Found 在建立綁定前,先確認兩者productIdmcpServerId都存在。


刪除 MCP 伺服器

刪除 MCP 伺服器及其所有工具與政策子資源。 在刪除伺服器前,移除所有引用後備 API 操作的工具;否則,只要工具參考存在,就無法刪除這些操作。

參考資料: API - 刪除

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

回應:200 OK 關於成功。

常見錯誤:412 Precondition Failed 刪除時必須使用If-Match。 用 If-Match: * 來繞過 ETag 檢查。

ARM 與 Bicep 範本

以下範本可在一次部署中部署完整的 MCP 伺服器配置。 每個範本假設已有的 API 管理服務實例,並使用參數表,因此您只需更改參數值即可在不同環境中重複使用同一檔案。

REST API 支援的 MCP 伺服器

這些範本建立 MCP 伺服器,定義一個可對應至現有後備 REST API 操作的工具,在伺服器範圍內附加速率限制政策,並將伺服器綁定至現有產品。 你可以在一次部署中完成所有這些任務。

前置條件:現有的 API 管理服務、至少一個操作 (backingApiId) 的 REST APIbackingOperationId(),以及一個現有產品(productId)。

Parameter 必填 預設值 Description
serviceName 是的 — 現有 API 管理服務實例的名稱。
mcpServerId No orders-mcp 新 MCP 伺服器的資源名稱。 必須是服務中獨一無二的。
backingApiId 是的 — 支援此 MCP 伺服器的現有 REST API 資源名稱。
backingOperationId 是的 — 要作為工具公開的操作資源名稱。
toolId No sampleTool 要建立的 MCP 工具的資源名稱與顯示名稱。
productId No starter 現有產品的資源名稱,用來綁定伺服器。
@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 ]
}

部署方式:

# 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

傳遞式 MCP 伺服器

這些範本建立一個通過式 MCP 伺服器,使用可串流的 HTTP 傳輸方式。 伺服器範圍有速率限制政策,且伺服器綁定於現有產品。 範本中沒有定義任何工具子資源。 外部後端決定了工具表面。

Note

以下範本使用 transportType: streamable,實作了目前的 MCP 可串流 HTTP 規範。 若要改用 SSE 傳輸,請將 transportType 設為 sse,並將 endpoints 陣列替換為兩個項目:{ "name": "sse", "uriTemplate": "/sse" } 和 { "name": "message", "uriTemplate": "/messages" }。 在 Bicep 中,使用相同的值,並以單引號字串表示。

前提條件: 現有的 API 管理服務、可達的 MCP 後端 URL(backendUrl)以實作所選的傳輸與端點路徑,以及現有產品(productId)。

Parameter 必填 預設值 Description
serviceName 是的 — 現有 API 管理服務實例的名稱。
mcpServerId No external-mcp 新 MCP 伺服器的資源名稱。 必須是服務中獨一無二的。
backendUrl 是的 — 外部 MCP 後端的絕對網址。
productId No starter 現有產品的資源名稱,用來綁定伺服器。
@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 ]
}

部署方式:

# 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

目前,你可以直接呼叫 az rest REST API。 以下腳本建立一個直通式 MCP 伺服器,附加速率限制政策,並將其綁定至產品。 這個流程涵蓋的情境與前一節的 Bicep 範本相同。

設定變數,然後依序執行四個 az rest 呼叫。

Note

az rest 使用您目前 az login 工作階段的憑證。 你不需要另外的認證步驟。

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

每一步都是等冪性的。 重新執行腳本會更新該資源。 要驗證伺服器是否已建立,請執行以下指令:

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

Terraform

AzureRM Terraform 供應商目前還沒有原生資源支援 MCP 伺服器。 目前,你可以使用 azapi_resourceAzAPI 提供者的資源類型,這讓你能管理任何 Azure 資源類型,針對任何 API 版本。 以下範例與直通 MCP 伺服器的 Bicep 模板相對應。

前提條件: 現有的 API 管理服務、可達的 MCP 後端 URL,以及現有產品。 如果你的 terraform 區塊中還沒有 AzAPI 提供者,請將其加入。

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

provider "azurerm" {
  features {}
}

provider "azapi" {}

變數

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

部署方式:

Note

azapi_resource 使用 AzAPI 提供者的驗證,其會讀取與 Azure CLI 相同的 az login 認證。 本地運行時不需要另外設定認證。

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 模式

  • 冪等 upsert:使用 If-Match: "*" 傳送 PUT 請求,讓相同的範本無論資源是否已存在都能套用。 

  • 促進跨環境配置:將 MCP 伺服器定義與工具清單視為原始碼控制的產物。 僅參數化環境特定的值,例如實例名稱與後端網址。 

  • 從你的 API 規格產生工具清單:從原始 OpenAPI 檔案驅動工具子資源,讓工具表面在演進時能與後備 API 保持同步。 

  • 依正確順序刪除:在刪除 MCP 工具指向的後備 API 或操作前,先移除它們的參考。 否則,刪除作業會因外鍵檢查而失敗。