この記事では、REST API、ARM テンプレート、Bicep、Azure CLI、Terraform を使用して、Azure API Managementで MCP サーバーを作成および管理する方法について説明します。
Important
この記事で説明する MCP サーバー管理機能には、API Management REST API バージョン 2025-09-01-preview 以降が必要です。 すべての要求にこのバージョンをピン留めします。
MCP サーバー機能の背景については、Azure API Managementの MCP サーバーについてを参照してください。
Prerequisites
ID には、API Management サービスを読み取り、API、API ツール、API ポリシー、および製品 API バインドを作成または更新するためのアクセス許可が必要です。 Terraform の場合、ID には、
azurerm_api_managementデータ ソースによって使用される既存の API Management サービスへの読み取りアクセスも必要です。Azure CLI の場合:
Azure Cloud Shell で Bash 環境を使用します。 詳細については、「Get started with Azure Cloud Shell」を参照してください。
CLI 参照コマンドをローカルで実行する場合は、Azure CLI を インストール します。 Windows または macOS で実行している場合は、Docker コンテナーで Azure CLI を実行することを検討してください。 詳細については、「Docker コンテナーで Azure CLI を実行する方法」を参照してください。
ローカル インストールを使用する場合は、az login コマンドを使用して Azure CLI にサインインします。 認証プロセスを完了するには、ターミナルに表示される手順に従います。 他のサインインオプションについては、「Azure CLI を使用して Azure に認証する」を参照してください。
初回使用時にインストールを求められたら、Azure CLI 拡張機能をインストールします。 拡張機能の詳細については、「Azure CLI で拡張機能を使用および管理する」を参照してください。
az version を実行して、インストールされているバージョンと依存ライブラリを検索します。 最新バージョンにアップグレードするには、az upgrade を実行します。
Azure PowerShell の場合:
- Azure PowerShell をローカルで使用する場合は、次のようにします。
- Az PowerShell モジュールの最新バージョンをインストールします。
- Connect-AzAccount コマンドレットを使用して、Azure アカウントに接続します。
- Azure Cloud Shell を使用する場合は、次のようにします。
- 詳細については、Azure Cloud Shell の概要に関するページを参照してください。
- Azure PowerShell をローカルで使用する場合は、次のようにします。
Terraform の場合: Terraform をインストールして構成する
リソース モデル
Azure Resource Managerは、MCP サーバーを次のように表します。
MCP サーバー:種類の An 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 - Get
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 Management ゲートウェイから到達可能であることを確認し、構成したエンドポイント パスで選択した MCP トランスポートを実装します。 バックエンドで認証が必要な場合は、API Management ポリシーまたはバックエンド構成を使用して、必要な資格情報またはヘッダーを構成します。
リファレンス: API - 作成または更新
ストリーミング可能な HTTP トランスポート
現在の MCP ストリーミング可能な HTTP トランスポート仕様を実装するバックエンドには、 streamable を使用します。 単一のエンドポイント定義が必要です。
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 (Server-Sent イベント) トランスポートを実装するバックエンドには、 sse を使用します。 2 つのエンドポイントを定義します。1 つは SSE イベント ストリーム用、1 つはメッセージ チャネル用です。
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 トランスポートには、正確に 2 つのエンドポイント (sseとmessage) が必要です。 ストリーミング可能なトランスポートには 1 つ (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 サーバーを製品にバインドする場合は、その製品を介して 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。 バインドを作成する前に、 productId と mcpServerId の両方が存在することを確認します。
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 は削除に必要です。 ETag チェックをバイパスするには、 If-Match: * を使用します。
ARM テンプレートとBicep テンプレート
次のテンプレートは、1 つのデプロイで完全な MCP サーバー構成をデプロイします。 各テンプレートは、既存の API Management サービス インスタンスを前提とし、パラメーター テーブルを使用するため、パラメーター値のみを変更することで、複数の環境で同じファイルを再利用できます。
REST API ベースの MCP サーバー
これらのテンプレートは、MCP サーバーを作成し、既存のバッキング REST API の操作にマップする 1 つのツールを定義し、サーバー スコープでレート制限ポリシーをアタッチして、サーバーを既存の製品にバインドします。 これらのタスクはすべて、1 つのデプロイで実行できます。
前提条件: 既存の API Management サービス、少なくとも 1 つの操作 (backingApiId) を含む REST API (backingOperationId)、既存の製品 (productId)。
| Parameter | 必須 | Default | Description |
|---|---|---|---|
serviceName |
はい | — | 既存の API Management サービス インスタンスの名前。 |
mcpServerId |
いいえ | orders-mcp |
新しい MCP サーバーのリソース名。 サービス内で一意である必要があります。 |
backingApiId |
はい | — | この MCP サーバーをサポートする既存の REST API のリソース名。 |
backingOperationId |
はい | — | ツールとして公開する操作のリソース名。 |
toolId |
いいえ | sampleTool |
作成する MCP ツールのリソース名と表示名。 |
productId |
いいえ | 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 サーバー
これらのテンプレートは、ストリーミング可能な HTTP トランスポートを使用するパススルー MCP サーバーを作成します。 サーバー スコープにはレート制限ポリシーがあり、サーバーは既存の製品にバインドされます。 テンプレートでは、ツールサブリソースは定義されません。 外部バックエンドがツール サーフェイスを決定します。
Note
次のテンプレートでは、現在の MCP ストリーミング可能 HTTP 仕様を実装する transportType: streamableを使用します。 代わりに SSE トランスポートを使用するには、 transportType を sse に設定し、 endpoints 配列を { "name": "sse", "uriTemplate": "/sse" } と { "name": "message", "uriTemplate": "/messages" } の 2 つのエントリに置き換えます。 Bicepでは、一重引用符で囲まれた文字列と同じ値を使用します。
前提条件: 既存の API Management サービス、選択したトランスポートパスとエンドポイント パスを実装する到達可能な MCP バックエンド URL (backendUrl)、既存の製品 (productId)。
| Parameter | 必須 | Default | Description |
|---|---|---|---|
serviceName |
はい | — | 既存の API Management サービス インスタンスの名前。 |
mcpServerId |
いいえ | external-mcp |
新しい MCP サーバーのリソース名。 サービス内で一意である必要があります。 |
backendUrl |
はい | — | 外部 MCP バックエンドの絶対 URL。 |
productId |
いいえ | 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 テンプレートと同じシナリオについて説明します。
変数を設定し、4 つの 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_resourceから リソースの種類を使用できます。これにより、任意の API バージョンに対して任意のAzureリソースの種類を管理できます。 次の例では、パススルー MCP サーバー Bicep テンプレートをミラー化します。
前提条件: 既存の API Management サービス、到達可能な MCP バックエンド URL、および既存の製品。 AzAPI プロバイダーがまだ存在しない場合は、 terraform ブロックに追加します。
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 パターン
冪等アップサート: リソースがすでに存在するかどうかにかかわらず同じテンプレートを適用できるように、
If-Match: "*"を使用してPUTリクエストを送信します。環境間での構成の昇格: MCP サーバー定義とツール リストをソース管理成果物として扱います。 インスタンス名やバックエンド URL など、環境固有の値のみをパラメーター化します。
API 仕様からツール リストを生成する: ソース OpenAPI ファイルからツール サブリソースを駆動し、ツール サーフェスが進化するにつれてバッキング API と同期し続けます。
正しい順序で削除する: MCP ツール参照を削除してから、それらが指すバッキング API または操作を削除します。 それ以外の場合、外部キーチェックで削除は失敗します。