[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EWKN82EW3YA59A2SS4QETP":3,"skill-same:01M6EWKN82EW3YA59A2SS4QETP":105},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":34,"publishedAt":55,"linkOnly":56,"markdownContent":57,"markdownBody":58,"frontMatter":59,"refName":60,"commitSha":61,"skillDirectory":62,"forksCount":63,"repositoryHtmlUrl":64,"repositoryHomepageUrl":65,"ownerHtmlUrl":66,"ownerBlogUrl":6,"ownerDescription":67,"updatedAt":68,"install":69,"resources":82},"01M6EWKN82EW3YA59A2SS4QETP","azure-aigateway",null,"Configure Azure API Management (APIM) as AI Gateway to secure, observe, control AI models, MCP servers, agents. Helps with rate limiting, semantic caching, content safety, load balancing. USE FOR: AI Gateway, APIM, setup gateway, configure gateway, add gateway, model gateway, MCP server, rate limit, token limit, semantic cache, content safety, load balance, OpenAPI import, convert API to MCP. DO NOT USE FOR: deploy models (use microsoft-foundry), Azure Functions (use azure-functions), databases (use azure-postgres).","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",66,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fmicrosoft\u002Fazure-aigateway\u002FSKILL.md",[18,23,26,29],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000011","运维与部署",{"categoryNo":27,"categoryName":28,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":30,"categoryName":31,"taxonomyType":32,"taxonomyTypeDesc":33},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54],"azure aigateway","azure","azure api management","MCP","ai models","import","as","rate limiting","load balancing","content safety","do","functions","models","use","convert","Safety","ai gateway","server","mcp servers","secure","2026-11-10 10:12:30",false,"---\nname: azure-aigateway\ndescription: >-\n  Configure Azure API Management (APIM) as AI Gateway to secure, observe, control AI models, MCP servers, agents. Helps with rate limiting, semantic caching, content safety, load balancing.\n  USE FOR: AI Gateway, APIM, setup gateway, configure gateway, add gateway, model gateway, MCP server, rate limit, token limit, semantic cache, content safety, load balance, OpenAPI import, convert API to MCP.\n  DO NOT USE FOR: deploy models (use microsoft-foundry), Azure Functions (use azure-functions), databases (use azure-postgres).\n---\n\n# Azure AI Gateway\n\nBootstrap and configure Azure API Management (APIM) as an AI Gateway for securing, observing, and controlling AI models, tools (MCP Servers), and agents.\n\n## Skill Activation Triggers\n\n**Use this skill immediately when the user asks to:**\n- \"Set up a gateway for my model\"\n- \"Set up a gateway for my tools\"\n- \"Set up a gateway for my agents\"\n- \"Add a gateway to my MCP server\"\n- \"Protect my AI model with a gateway\"\n- \"Secure my AI agents\"\n- \"Ratelimit my model requests\"\n- \"Ratelimit my tool requests\"\n- \"Limit tokens for my model\"\n- \"Add rate limiting to my MCP server\"\n- \"Enable semantic caching for my AI API\"\n- \"Add content safety to my AI endpoint\"\n- \"Add my model behind gateway\"\n- \"Import API from OpenAPI spec\"\n- \"Add API to gateway from swagger\"\n- \"Convert my API to MCP\"\n- \"Expose my API as MCP server\"\n\n**Key Indicators:**\n- User deploying Azure OpenAI, AI Foundry, or other AI models\n- User creating or managing MCP servers\n- User needs token limits, rate limiting, or quota management\n- User wants to cache AI responses to reduce costs\n- User needs content filtering or safety controls\n- User wants load balancing across multiple AI backends\n\n**Secondary Triggers (Proactive Recommendations):**\n- After model creation: Recommend AI Gateway for security, caching, and token limits\n- After MCP server creation: Recommend AI Gateway for rate limiting, content safety, and auth\n\n## Overview\n\nAzure API Management serves as an AI Gateway that provides:\n- **Security**: Authentication, authorization, and content safety\n- **Observability**: Token metrics, logging, and monitoring\n- **Control**: Rate limiting, token limits, and load balancing\n- **Optimization**: Semantic caching to reduce costs and latency\n\n```\nAI Models ──┐                      ┌── Azure OpenAI\nMCP Tools ──┼── AI Gateway (APIM) ──┼── AI Foundry\nAgents ─────┘                      └── Custom Models\n```\n\n## Key Resources\n\n- **GitHub Repo**: https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway (aka.ms\u002Faigateway)\n- **Docs**:\n  - [GenAI Gateway Capabilities](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fgenai-gateway-capabilities)\n  - [MCP Server Overview](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fmcp-server-overview)\n  - [Azure AI Foundry API](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fazure-ai-foundry-api)\n  - [Semantic Caching](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fazure-openai-enable-semantic-caching)\n  - [Token Limits & LLM Logs](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fapi-management-howto-llm-logs)\n\n## Configuration Rules\n\n**Default to `Basicv2` SKU** when creating new APIM instances:\n- Cheaper than other tiers\n- Creates quickly (~5-10 minutes vs 30+ for Premium)\n- Supports all AI Gateway policies\n\n## Pattern 1: Quick Bootstrap AI Gateway\n\nDeploy APIM with Basicv2 SKU for AI workloads.\n\n```bash\n# Create resource group\naz group create --name rg-aigateway --location eastus2\n\n# Deploy APIM with Bicep\naz deployment group create \\\n  --resource-group rg-aigateway \\\n  --template-file main.bicep \\\n  --parameters apimSku=Basicv2\n```\n\n### Bicep Template\n\n```bicep\nparam location string = resourceGroup().location\nparam apimSku string = 'Basicv2'\nparam apimManagedIdentityType string = 'SystemAssigned'\n\n\u002F\u002F NOTE: Using 2024-06-01-preview because Basicv2 SKU support currently requires this preview API version.\n\u002F\u002F       Update to the latest stable (GA) API version once Basicv2 is available there.\nresource apimService 'Microsoft.ApiManagement\u002Fservice@2024-06-01-preview' = {\n  name: 'apim-aigateway-${uniqueString(resourceGroup().id)}'\n  location: location\n  sku: {\n    name: apimSku\n    capacity: 1\n  }\n  properties: {\n    publisherEmail: 'admin@contoso.com'\n    publisherName: 'Contoso'\n  }\n  identity: {\n    type: apimManagedIdentityType\n  }\n}\n\noutput gatewayUrl string = apimService.properties.gatewayUrl\noutput principalId string = apimService.identity.principalId\n```\n\n## Pattern 2: Semantic Caching\n\nCache similar prompts to reduce costs and latency.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003C!-- Cache lookup with 0.8 similarity threshold -->\n        \u003Cazure-openai-semantic-cache-lookup \n            score-threshold=\"0.8\" \n            embeddings-backend-id=\"embeddings-backend\" \n            embeddings-backend-auth=\"system-assigned\" \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n    \u003C\u002Finbound>\n    \u003Coutbound>\n        \u003C!-- Cache responses for 120 seconds -->\n        \u003Cazure-openai-semantic-cache-store duration=\"120\" \u002F>\n        \u003Cbase \u002F>\n    \u003C\u002Foutbound>\n\u003C\u002Fpolicies>\n```\n\n**Options:**\n| Parameter | Range | Description |\n|-----------|-------|-------------|\n| `score-threshold` | 0.7-0.95 | Higher = stricter matching |\n| `duration` | 60-3600 | Cache TTL in seconds |\n\n## Pattern 3: Token Rate Limiting\n\nLimit tokens per minute to control costs and prevent abuse.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n        \u003C!-- Limit to 500 tokens per minute per subscription -->\n        \u003Cazure-openai-token-limit \n            counter-key=\"@(context.Subscription.Id)\"\n            tokens-per-minute=\"500\" \n            estimate-prompt-tokens=\"false\" \n            remaining-tokens-variable-name=\"remainingTokens\" \u002F>\n    \u003C\u002Finbound>\n\u003C\u002Fpolicies>\n```\n\n**Options:**\n| Parameter | Values | Description |\n|-----------|--------|-------------|\n| `counter-key` | Subscription.Id, Request.IpAddress, custom | Grouping key for limits |\n| `tokens-per-minute` | 100-100000 | Token quota |\n| `estimate-prompt-tokens` | true\u002Ffalse | true = faster but less accurate |\n\n## Pattern 4: Content Safety\n\nFilter harmful content and detect jailbreak attempts.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n        \u003C!-- Block severity 4+ content, detect jailbreaks -->\n        \u003Cllm-content-safety backend-id=\"content-safety-backend\" shield-prompt=\"true\">\n            \u003Ccategories output-type=\"EightSeverityLevels\">\n                \u003Ccategory name=\"Hate\" threshold=\"4\" \u002F>\n                \u003Ccategory name=\"Sexual\" threshold=\"4\" \u002F>\n                \u003Ccategory name=\"SelfHarm\" threshold=\"4\" \u002F>\n                \u003Ccategory name=\"Violence\" threshold=\"4\" \u002F>\n            \u003C\u002Fcategories>\n            \u003Cblocklists>\n                \u003Cid>custom-blocklist\u003C\u002Fid>\n            \u003C\u002Fblocklists>\n        \u003C\u002Fllm-content-safety>\n    \u003C\u002Finbound>\n\u003C\u002Fpolicies>\n```\n\n**Options:**\n| Parameter | Range | Description |\n|-----------|-------|-------------|\n| `threshold` | 0-7 | 0=safe, 7=severe |\n| `shield-prompt` | true\u002Ffalse | Detect jailbreak attempts |\n\n## Pattern 5: Rate Limits for MCPs\u002FOpenAPI Tools\n\nProtect MCP servers and tools with request rate limiting.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003C!-- 10 calls per 60 seconds per IP -->\n        \u003Crate-limit-by-key \n            calls=\"10\" \n            renewal-period=\"60\" \n            counter-key=\"@(context.Request.IpAddress)\" \n            remaining-calls-variable-name=\"remainingCalls\" \u002F>\n    \u003C\u002Finbound>\n    \u003Coutbound>\n        \u003Cset-header name=\"X-Rate-Limit-Remaining\" exists-action=\"override\">\n            \u003Cvalue>@(context.Variables.GetValueOrDefault\u003Cint>(\"remainingCalls\", 0).ToString())\u003C\u002Fvalue>\n        \u003C\u002Fset-header>\n        \u003Cbase \u002F>\n    \u003C\u002Foutbound>\n\u003C\u002Fpolicies>\n```\n\n## Pattern 6: Managed Identity Authentication\n\nSecure backend access with managed identity instead of API keys.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003C!-- Managed identity auth to Azure OpenAI -->\n        \u003Cauthentication-managed-identity \n            resource=\"https:\u002F\u002Fcognitiveservices.azure.com\" \n            output-token-variable-name=\"managed-id-access-token\" \n            ignore-error=\"false\" \u002F>\n        \u003Cset-header name=\"Authorization\" exists-action=\"override\">\n            \u003Cvalue>@(\"Bearer \" + (string)context.Variables[\"managed-id-access-token\"])\u003C\u002Fvalue>\n        \u003C\u002Fset-header>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n        \u003C!-- Emit token metrics for monitoring -->\n        \u003Cazure-openai-emit-token-metric namespace=\"openai\">\n            \u003Cdimension name=\"Subscription ID\" value=\"@(context.Subscription.Id)\" \u002F>\n            \u003Cdimension name=\"Client IP\" value=\"@(context.Request.IpAddress)\" \u002F>\n            \u003Cdimension name=\"API ID\" value=\"@(context.Api.Id)\" \u002F>\n        \u003C\u002Fazure-openai-emit-token-metric>\n    \u003C\u002Finbound>\n\u003C\u002Fpolicies>\n```\n\n## Pattern 7: Load Balancing with Retry\n\nDistribute load across multiple backends with automatic failover.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-pool-id}\" \u002F>\n    \u003C\u002Finbound>\n    \u003Cbackend>\n        \u003C!-- Retry on 429 (rate limit) or 503 (service unavailable) -->\n        \u003Cretry count=\"2\" interval=\"0\" first-fast-retry=\"true\" \n            condition=\"@(context.Response.StatusCode == 429 || context.Response.StatusCode == 503)\">\n            \u003Cset-backend-service backend-id=\"{backend-pool-id}\" \u002F>\n            \u003Cforward-request buffer-request-body=\"true\" \u002F>\n        \u003C\u002Fretry>\n    \u003C\u002Fbackend>\n    \u003Con-error>\n        \u003Cwhen condition=\"@(context.Response.StatusCode == 503)\">\n            \u003Creturn-response>\n                \u003Cset-status code=\"503\" reason=\"Service Unavailable\" \u002F>\n            \u003C\u002Freturn-response>\n        \u003C\u002Fwhen>\n    \u003C\u002Fon-error>\n\u003C\u002Fpolicies>\n```\n\n## Pattern 8: Add AI Foundry Model Behind Gateway\n\nWhen user asks to \"add my model behind gateway\", first discover available models from Azure AI Foundry, then ask which model to add.\n\n### Step 1: Discover AI Foundry Projects and Available Models\n\n```bash\n# Set environment variables\naccountName=\"\u003Cai-foundry-resource-name>\"\nresourceGroupName=\"\u003Cresource-group>\"\n\n# List AI Foundry resources (AI Services accounts)\naz cognitiveservices account list --query \"[?kind=='AIServices'].{name:name, resourceGroup:resourceGroup, location:location}\" -o table\n\n# List available models in the AI Foundry resource\naz cognitiveservices account list-models \\\n  -n $accountName \\\n  -g $resourceGroupName \\\n  | jq '.[] | { name: .name, format: .format, version: .version, sku: .skus[0].name, capacity: .skus[0].capacity.default }'\n\n# List already deployed models\naz cognitiveservices account deployment list \\\n  -n $accountName \\\n  -g $resourceGroupName\n```\n\n### Step 2: Ask User Which Model to Add\n\nAfter listing the available models, **use the ask_user tool** to present the models as choices and let the user select which model to add behind the gateway.\n\nExample choices to present:\n- Model deployments from the discovered list\n- Include model name, format (provider), version, and SKU info\n\n### Step 3: Deploy the Model (if not already deployed)\n\n```bash\n# Deploy the selected model to AI Foundry\naz cognitiveservices account deployment create \\\n  -n $accountName \\\n  -g $resourceGroupName \\\n  --deployment-name \u003Cmodel-name> \\\n  --model-name \u003Cmodel-name> \\\n  --model-version \u003Cversion> \\\n  --model-format \u003Cformat> \\\n  --sku-capacity 1 \\\n  --sku-name \u003Csku>\n```\n\n### Step 4: Configure APIM Backend for Selected Model\n\n```bash\n# Get the AI Foundry inference endpoint\nENDPOINT=$(az cognitiveservices account show \\\n  -n $accountName \\\n  -g $resourceGroupName \\\n  | jq -r '.properties.endpoints[\"Azure AI Model Inference API\"]')\n\n# Create APIM backend for the selected model\naz apim backend create \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --backend-id \u003Cmodel-deployment-name>-backend \\\n  --protocol http \\\n  --url \"${ENDPOINT}\"\n```\n\n### Step 5: Create API and Apply Policies\n\n```bash\n# Import Azure OpenAI API specification\naz apim api import \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --path \u003Cmodel-deployment-name> \\\n  --specification-format OpenApiJson \\\n  --specification-url \"https:\u002F\u002Fraw.githubusercontent.com\u002FAzure\u002Fazure-rest-api-specs\u002Fmain\u002Fspecification\u002Fcognitiveservices\u002Fdata-plane\u002FAzureOpenAI\u002Finference\u002Fstable\u002F2024-02-01\u002Finference.json\"\n```\n\n### Step 6: Grant APIM Access to AI Foundry\n\n```bash\n# Get APIM managed identity principal ID\nAPIM_PRINCIPAL_ID=$(az apim show \\\n  --name \u003Capim-service-name> \\\n  --resource-group \u003Capim-resource-group> \\\n  --query \"identity.principalId\" -o tsv)\n\n# Get AI Foundry resource ID\nAI_RESOURCE_ID=$(az cognitiveservices account show \\\n  -n $accountName \\\n  -g $resourceGroupName \\\n  --query \"id\" -o tsv)\n\n# Assign Cognitive Services User role\naz role assignment create \\\n  --assignee $APIM_PRINCIPAL_ID \\\n  --role \"Cognitive Services User\" \\\n  --scope $AI_RESOURCE_ID\n```\n\n### Bicep Template for Backend Configuration\n\n```bicep\nparam apimServiceName string\nparam backendId string\nparam aiFoundryEndpoint string\nparam modelDeploymentName string\n\nresource apimService 'Microsoft.ApiManagement\u002Fservice@2024-06-01-preview' existing = {\n  name: apimServiceName\n}\n\nresource backend 'Microsoft.ApiManagement\u002Fservice\u002Fbackends@2024-06-01-preview' = {\n  parent: apimService\n  name: backendId\n  properties: {\n    protocol: 'http'\n    url: '${aiFoundryEndpoint}openai\u002Fdeployments\u002F${modelDeploymentName}'\n    credentials: {\n      header: {}\n    }\n    tls: {\n      validateCertificateChain: true\n      validateCertificateName: true\n    }\n  }\n}\n```\n\n## Pattern 9: Import API from OpenAPI Specification\n\nAdd an API to the gateway from an OpenAPI\u002FSwagger specification, either from a local file or web URL.\n\n### Step 1: Import API from Web URL\n\n```bash\n# Import API from a publicly accessible OpenAPI spec URL\naz apim api import \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --api-id \u003Capi-id> \\\n  --path \u003Capi-path> \\\n  --display-name \"\u003CAPI Display Name>\" \\\n  --specification-format OpenApiJson \\\n  --specification-url \"https:\u002F\u002Fexample.com\u002Fopenapi.json\"\n```\n\n### Step 2: Import API from Local File\n\n```bash\n# Import API from a local OpenAPI spec file (JSON or YAML)\naz apim api import \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --api-id \u003Capi-id> \\\n  --path \u003Capi-path> \\\n  --display-name \"\u003CAPI Display Name>\" \\\n  --specification-format OpenApi \\\n  --specification-path \".\u002Fopenapi.yaml\"\n```\n\n### Step 3: Configure Backend for the API\n\n```bash\n# Create backend pointing to your API server\naz apim backend create \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --backend-id \u003Cbackend-id> \\\n  --protocol http \\\n  --url \"https:\u002F\u002Fyour-api-server.com\"\n\n# Update API to use the backend\naz apim api update \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --api-id \u003Capi-id> \\\n  --set properties.serviceUrl=\"https:\u002F\u002Fyour-api-server.com\"\n```\n\n### Step 4: Apply Policies (Optional)\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n        \u003C!-- Add rate limiting -->\n        \u003Crate-limit-by-key \n            calls=\"100\" \n            renewal-period=\"60\" \n            counter-key=\"@(context.Request.IpAddress)\" \u002F>\n    \u003C\u002Finbound>\n    \u003Coutbound>\n        \u003Cbase \u002F>\n    \u003C\u002Foutbound>\n\u003C\u002Fpolicies>\n```\n\n### Supported Specification Formats\n\n| Format | Value | File Extension |\n|--------|-------|----------------|\n| OpenAPI 3.x JSON | `OpenApiJson` | `.json` |\n| OpenAPI 3.x YAML | `OpenApi` | `.yaml`, `.yml` |\n| Swagger 2.0 JSON | `SwaggerJson` | `.json` |\n| Swagger 2.0 (link) | `SwaggerLinkJson` | URL |\n| WSDL | `Wsdl` | `.wsdl` |\n| WADL | `Wadl` | `.wadl` |\n\n## Pattern 10: Convert API to MCP Server\n\nConvert existing APIM API operations into an MCP (Model Context Protocol) server, enabling AI agents to discover and use your APIs as tools.\n\n### Prerequisites\n\n- APIM instance with Basicv2 SKU or higher\n- Existing API imported into APIM\n- MCP feature enabled on APIM\n\n### Step 1: List Existing APIs in APIM\n\n```bash\n# List all APIs in APIM\naz apim api list \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --query \"[].{id:name, displayName:displayName, path:path}\" \\\n  -o table\n```\n\n### Step 2: Ask User Which API to Convert\n\nAfter listing the APIs, **use the ask_user tool** to let the user select which API to convert to an MCP server.\n\n### Step 3: List API Operations\n\n```bash\n# List all operations for the selected API\naz apim api operation list \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --api-id \u003Capi-id> \\\n  --query \"[].{operationId:name, displayName:displayName, method:method, urlTemplate:urlTemplate}\" \\\n  -o table\n```\n\n### Step 4: Ask User Which Operations to Expose as MCP Tools\n\nAfter listing the operations, **use the ask_user tool** to present the operations as choices. Let the user select which operations to expose as MCP tools. Users may want to expose all operations or only a subset.\n\nExample choices to present:\n- All operations (convert entire API)\n- Individual operations from the discovered list\n- Include operation name, method, and URL template\n\n### Step 5: Enable MCP Server on APIM\n\n```bash\n# Enable MCP server capability (via ARM\u002FBicep or Portal)\n# Note: MCP configuration is done via APIM policies and product configuration\n```\n\n### Step 6: Configure MCP Endpoint for API\n\nCreate an MCP-compatible endpoint that exposes your API operations as tools:\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003C!-- MCP tools\u002Flist endpoint handler -->\n        \u003Cchoose>\n            \u003Cwhen condition=\"@(context.Request.Url.Path.EndsWith(\"\u002Fmcp\u002Ftools\u002Flist\"))\">\n                \u003Creturn-response>\n                    \u003Cset-status code=\"200\" reason=\"OK\" \u002F>\n                    \u003Cset-header name=\"Content-Type\" exists-action=\"override\">\n                        \u003Cvalue>application\u002Fjson\u003C\u002Fvalue>\n                    \u003C\u002Fset-header>\n                    \u003Cset-body>@{\n                        var tools = new JArray();\n                        \u002F\u002F Define your API operations as MCP tools\n                        tools.Add(new JObject(\n                            new JProperty(\"name\", \"operation_name\"),\n                            new JProperty(\"description\", \"Description of what this operation does\"),\n                            new JProperty(\"inputSchema\", new JObject(\n                                new JProperty(\"type\", \"object\"),\n                                new JProperty(\"properties\", new JObject(\n                                    new JProperty(\"param1\", new JObject(\n                                        new JProperty(\"type\", \"string\"),\n                                        new JProperty(\"description\", \"Parameter description\")\n                                    ))\n                                ))\n                            ))\n                        ));\n                        return new JObject(new JProperty(\"tools\", tools)).ToString();\n                    }\u003C\u002Fset-body>\n                \u003C\u002Freturn-response>\n            \u003C\u002Fwhen>\n        \u003C\u002Fchoose>\n    \u003C\u002Finbound>\n\u003C\u002Fpolicies>\n```\n\n### Step 7: Bicep Template for MCP-Enabled API\n\n```bicep\nparam apimServiceName string\nparam apiId string\nparam apiDisplayName string\nparam apiPath string\nparam backendUrl string\n\nresource apimService 'Microsoft.ApiManagement\u002Fservice@2024-06-01-preview' existing = {\n  name: apimServiceName\n}\n\nresource api 'Microsoft.ApiManagement\u002Fservice\u002Fapis@2024-06-01-preview' = {\n  parent: apimService\n  name: apiId\n  properties: {\n    displayName: apiDisplayName\n    path: apiPath\n    protocols: ['https']\n    serviceUrl: backendUrl\n    subscriptionRequired: true\n    \u002F\u002F MCP endpoints\n    apiType: 'http'\n  }\n}\n\n\u002F\u002F MCP tools\u002Flist operation\nresource mcpToolsListOperation 'Microsoft.ApiManagement\u002Fservice\u002Fapis\u002Foperations@2024-06-01-preview' = {\n  parent: api\n  name: 'mcp-tools-list'\n  properties: {\n    displayName: 'MCP Tools List'\n    method: 'POST'\n    urlTemplate: '\u002Fmcp\u002Ftools\u002Flist'\n    description: 'List available MCP tools'\n  }\n}\n\n\u002F\u002F MCP tools\u002Fcall operation\nresource mcpToolsCallOperation 'Microsoft.ApiManagement\u002Fservice\u002Fapis\u002Foperations@2024-06-01-preview' = {\n  parent: api\n  name: 'mcp-tools-call'\n  properties: {\n    displayName: 'MCP Tools Call'\n    method: 'POST'\n    urlTemplate: '\u002Fmcp\u002Ftools\u002Fcall'\n    description: 'Call an MCP tool'\n  }\n}\n```\n\n### Step 8: Test MCP Endpoint\n\n```bash\n# Get APIM gateway URL\nGATEWAY_URL=$(az apim show \\\n  --name \u003Capim-service-name> \\\n  --resource-group \u003Capim-resource-group> \\\n  --query \"gatewayUrl\" -o tsv)\n\n# Test MCP tools\u002Flist endpoint\ncurl -X POST \"${GATEWAY_URL}\u002F\u003Capi-path>\u002Fmcp\u002Ftools\u002Flist\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Ocp-Apim-Subscription-Key: \u003Csubscription-key>\" \\\n  -d '{}'\n```\n\n### MCP Tool Definition Schema\n\nWhen converting API operations to MCP tools, use this schema:\n\n```json\n{\n  \"tools\": [\n    {\n      \"name\": \"get_weather\",\n      \"description\": \"Get current weather for a location\",\n      \"inputSchema\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"location\": {\n            \"type\": \"string\",\n            \"description\": \"City name or coordinates\"\n          }\n        },\n        \"required\": [\"location\"]\n      }\n    }\n  ]\n}\n```\n\n### Reference\n\n- [MCP Server Overview](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fmcp-server-overview)\n- [MCP from API Lab](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fmcp-from-api)\n\n## Lab References (AI-Gateway Repo)\n\n**Essential Labs to Get Started:**\n\n| Scenario | Lab | Description |\n|----------|-----|-------------|\n| Semantic Caching | [semantic-caching](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fsemantic-caching) | Cache similar prompts to reduce costs |\n| Token Rate Limiting | [token-rate-limiting](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Ftoken-rate-limiting) | Limit tokens per minute |\n| Content Safety | [content-safety](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fcontent-safety) | Filter harmful content |\n| Load Balancing | [backend-pool-load-balancing](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fbackend-pool-load-balancing) | Distribute load across backends |\n| MCP from API | [mcp-from-api](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fmcp-from-api) | Convert OpenAPI to MCP server |\n| Zero to Production | [zero-to-production](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fzero-to-production) | Complete production setup guide |\n\n**Find more labs at:** https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\n\n## Quick Start Checklist\n\n### Prerequisites\n- [ ] Azure subscription created\n- [ ] Azure CLI installed and authenticated (`az login`)\n- [ ] Resource group created for AI Gateway resources\n\n### Deployment\n- [ ] Deploy APIM with Basicv2 SKU\n- [ ] Configure managed identity\n- [ ] Add backend for Azure OpenAI or AI Foundry\n- [ ] Apply policies (caching, rate limits, content safety)\n\n### Verification\n- [ ] Test API endpoint through gateway\n- [ ] Verify token metrics in Application Insights\n- [ ] Check rate limiting headers in response\n- [ ] Validate content safety filtering\n\n## Best Practices\n\n| Practice | Description |\n|----------|-------------|\n| **Default to Basicv2** | Use Basicv2 SKU for cost\u002Fspeed optimization |\n| **Use managed identity** | Prefer managed identity over API keys for backend auth |\n| **Enable token metrics** | Use `azure-openai-emit-token-metric` for cost tracking |\n| **Semantic caching** | Cache similar prompts to reduce costs (60-80% savings possible) |\n| **Rate limit by key** | Use subscription ID or IP for granular rate limiting |\n| **Content safety** | Enable `shield-prompt` to detect jailbreak attempts |\n\n## Troubleshooting\n\n| Issue | Symptom | Solution |\n|-------|---------|----------|\n| **Slow APIM creation** | Deployment takes 30+ minutes | Use Basicv2 SKU instead of Premium |\n| **Token limit exceeded** | 429 response | Increase `tokens-per-minute` or add load balancing |\n| **Cache not working** | No cache hits | Lower `score-threshold` (e.g., 0.7) |\n| **Content blocked** | False positives | Increase category thresholds |\n| **Backend auth fails** | 401 from Azure OpenAI | Assign Cognitive Services User role to APIM managed identity |\n| **Rate limit too strict** | Legitimate requests blocked | Increase `calls` or `renewal-period` |\n\n## SDK Quick References\n\n- **Content Safety**: [Python](references\u002Fsdk\u002Fazure-ai-contentsafety-py.md) | [TypeScript](references\u002Fsdk\u002Fazure-ai-contentsafety-ts.md)\n- **API Management**: [Python](references\u002Fsdk\u002Fazure-mgmt-apimanagement-py.md) | [.NET](references\u002Fsdk\u002Fazure-mgmt-apimanagement-dotnet.md)\n\n## Additional Resources\n\n- [Azure API Management Documentation](https:\u002F\u002Flearn.microsoft.com\u002Fazure\u002Fapi-management\u002F)\n- [AI Gateway Samples Repository](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway)\n- [APIM Policies Reference](https:\u002F\u002Flearn.microsoft.com\u002Fazure\u002Fapi-management\u002Fapi-management-policies)\n- [Azure OpenAI Integration](https:\u002F\u002Flearn.microsoft.com\u002Fazure\u002Fapi-management\u002Fazure-openai-api-from-specification)\n","# Azure AI Gateway\n\nBootstrap and configure Azure API Management (APIM) as an AI Gateway for securing, observing, and controlling AI models, tools (MCP Servers), and agents.\n\n## Skill Activation Triggers\n\n**Use this skill immediately when the user asks to:**\n- \"Set up a gateway for my model\"\n- \"Set up a gateway for my tools\"\n- \"Set up a gateway for my agents\"\n- \"Add a gateway to my MCP server\"\n- \"Protect my AI model with a gateway\"\n- \"Secure my AI agents\"\n- \"Ratelimit my model requests\"\n- \"Ratelimit my tool requests\"\n- \"Limit tokens for my model\"\n- \"Add rate limiting to my MCP server\"\n- \"Enable semantic caching for my AI API\"\n- \"Add content safety to my AI endpoint\"\n- \"Add my model behind gateway\"\n- \"Import API from OpenAPI spec\"\n- \"Add API to gateway from swagger\"\n- \"Convert my API to MCP\"\n- \"Expose my API as MCP server\"\n\n**Key Indicators:**\n- User deploying Azure OpenAI, AI Foundry, or other AI models\n- User creating or managing MCP servers\n- User needs token limits, rate limiting, or quota management\n- User wants to cache AI responses to reduce costs\n- User needs content filtering or safety controls\n- User wants load balancing across multiple AI backends\n\n**Secondary Triggers (Proactive Recommendations):**\n- After model creation: Recommend AI Gateway for security, caching, and token limits\n- After MCP server creation: Recommend AI Gateway for rate limiting, content safety, and auth\n\n## Overview\n\nAzure API Management serves as an AI Gateway that provides:\n- **Security**: Authentication, authorization, and content safety\n- **Observability**: Token metrics, logging, and monitoring\n- **Control**: Rate limiting, token limits, and load balancing\n- **Optimization**: Semantic caching to reduce costs and latency\n\n```\nAI Models ──┐                      ┌── Azure OpenAI\nMCP Tools ──┼── AI Gateway (APIM) ──┼── AI Foundry\nAgents ─────┘                      └── Custom Models\n```\n\n## Key Resources\n\n- **GitHub Repo**: https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway (aka.ms\u002Faigateway)\n- **Docs**:\n  - [GenAI Gateway Capabilities](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fgenai-gateway-capabilities)\n  - [MCP Server Overview](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fmcp-server-overview)\n  - [Azure AI Foundry API](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fazure-ai-foundry-api)\n  - [Semantic Caching](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fazure-openai-enable-semantic-caching)\n  - [Token Limits & LLM Logs](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fapi-management-howto-llm-logs)\n\n## Configuration Rules\n\n**Default to `Basicv2` SKU** when creating new APIM instances:\n- Cheaper than other tiers\n- Creates quickly (~5-10 minutes vs 30+ for Premium)\n- Supports all AI Gateway policies\n\n## Pattern 1: Quick Bootstrap AI Gateway\n\nDeploy APIM with Basicv2 SKU for AI workloads.\n\n```bash\n# Create resource group\naz group create --name rg-aigateway --location eastus2\n\n# Deploy APIM with Bicep\naz deployment group create \\\n  --resource-group rg-aigateway \\\n  --template-file main.bicep \\\n  --parameters apimSku=Basicv2\n```\n\n### Bicep Template\n\n```bicep\nparam location string = resourceGroup().location\nparam apimSku string = 'Basicv2'\nparam apimManagedIdentityType string = 'SystemAssigned'\n\n\u002F\u002F NOTE: Using 2024-06-01-preview because Basicv2 SKU support currently requires this preview API version.\n\u002F\u002F       Update to the latest stable (GA) API version once Basicv2 is available there.\nresource apimService 'Microsoft.ApiManagement\u002Fservice@2024-06-01-preview' = {\n  name: 'apim-aigateway-${uniqueString(resourceGroup().id)}'\n  location: location\n  sku: {\n    name: apimSku\n    capacity: 1\n  }\n  properties: {\n    publisherEmail: 'admin@contoso.com'\n    publisherName: 'Contoso'\n  }\n  identity: {\n    type: apimManagedIdentityType\n  }\n}\n\noutput gatewayUrl string = apimService.properties.gatewayUrl\noutput principalId string = apimService.identity.principalId\n```\n\n## Pattern 2: Semantic Caching\n\nCache similar prompts to reduce costs and latency.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003C!-- Cache lookup with 0.8 similarity threshold -->\n        \u003Cazure-openai-semantic-cache-lookup \n            score-threshold=\"0.8\" \n            embeddings-backend-id=\"embeddings-backend\" \n            embeddings-backend-auth=\"system-assigned\" \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n    \u003C\u002Finbound>\n    \u003Coutbound>\n        \u003C!-- Cache responses for 120 seconds -->\n        \u003Cazure-openai-semantic-cache-store duration=\"120\" \u002F>\n        \u003Cbase \u002F>\n    \u003C\u002Foutbound>\n\u003C\u002Fpolicies>\n```\n\n**Options:**\n| Parameter | Range | Description |\n|-----------|-------|-------------|\n| `score-threshold` | 0.7-0.95 | Higher = stricter matching |\n| `duration` | 60-3600 | Cache TTL in seconds |\n\n## Pattern 3: Token Rate Limiting\n\nLimit tokens per minute to control costs and prevent abuse.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n        \u003C!-- Limit to 500 tokens per minute per subscription -->\n        \u003Cazure-openai-token-limit \n            counter-key=\"@(context.Subscription.Id)\"\n            tokens-per-minute=\"500\" \n            estimate-prompt-tokens=\"false\" \n            remaining-tokens-variable-name=\"remainingTokens\" \u002F>\n    \u003C\u002Finbound>\n\u003C\u002Fpolicies>\n```\n\n**Options:**\n| Parameter | Values | Description |\n|-----------|--------|-------------|\n| `counter-key` | Subscription.Id, Request.IpAddress, custom | Grouping key for limits |\n| `tokens-per-minute` | 100-100000 | Token quota |\n| `estimate-prompt-tokens` | true\u002Ffalse | true = faster but less accurate |\n\n## Pattern 4: Content Safety\n\nFilter harmful content and detect jailbreak attempts.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n        \u003C!-- Block severity 4+ content, detect jailbreaks -->\n        \u003Cllm-content-safety backend-id=\"content-safety-backend\" shield-prompt=\"true\">\n            \u003Ccategories output-type=\"EightSeverityLevels\">\n                \u003Ccategory name=\"Hate\" threshold=\"4\" \u002F>\n                \u003Ccategory name=\"Sexual\" threshold=\"4\" \u002F>\n                \u003Ccategory name=\"SelfHarm\" threshold=\"4\" \u002F>\n                \u003Ccategory name=\"Violence\" threshold=\"4\" \u002F>\n            \u003C\u002Fcategories>\n            \u003Cblocklists>\n                \u003Cid>custom-blocklist\u003C\u002Fid>\n            \u003C\u002Fblocklists>\n        \u003C\u002Fllm-content-safety>\n    \u003C\u002Finbound>\n\u003C\u002Fpolicies>\n```\n\n**Options:**\n| Parameter | Range | Description |\n|-----------|-------|-------------|\n| `threshold` | 0-7 | 0=safe, 7=severe |\n| `shield-prompt` | true\u002Ffalse | Detect jailbreak attempts |\n\n## Pattern 5: Rate Limits for MCPs\u002FOpenAPI Tools\n\nProtect MCP servers and tools with request rate limiting.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003C!-- 10 calls per 60 seconds per IP -->\n        \u003Crate-limit-by-key \n            calls=\"10\" \n            renewal-period=\"60\" \n            counter-key=\"@(context.Request.IpAddress)\" \n            remaining-calls-variable-name=\"remainingCalls\" \u002F>\n    \u003C\u002Finbound>\n    \u003Coutbound>\n        \u003Cset-header name=\"X-Rate-Limit-Remaining\" exists-action=\"override\">\n            \u003Cvalue>@(context.Variables.GetValueOrDefault\u003Cint>(\"remainingCalls\", 0).ToString())\u003C\u002Fvalue>\n        \u003C\u002Fset-header>\n        \u003Cbase \u002F>\n    \u003C\u002Foutbound>\n\u003C\u002Fpolicies>\n```\n\n## Pattern 6: Managed Identity Authentication\n\nSecure backend access with managed identity instead of API keys.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003C!-- Managed identity auth to Azure OpenAI -->\n        \u003Cauthentication-managed-identity \n            resource=\"https:\u002F\u002Fcognitiveservices.azure.com\" \n            output-token-variable-name=\"managed-id-access-token\" \n            ignore-error=\"false\" \u002F>\n        \u003Cset-header name=\"Authorization\" exists-action=\"override\">\n            \u003Cvalue>@(\"Bearer \" + (string)context.Variables[\"managed-id-access-token\"])\u003C\u002Fvalue>\n        \u003C\u002Fset-header>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n        \u003C!-- Emit token metrics for monitoring -->\n        \u003Cazure-openai-emit-token-metric namespace=\"openai\">\n            \u003Cdimension name=\"Subscription ID\" value=\"@(context.Subscription.Id)\" \u002F>\n            \u003Cdimension name=\"Client IP\" value=\"@(context.Request.IpAddress)\" \u002F>\n            \u003Cdimension name=\"API ID\" value=\"@(context.Api.Id)\" \u002F>\n        \u003C\u002Fazure-openai-emit-token-metric>\n    \u003C\u002Finbound>\n\u003C\u002Fpolicies>\n```\n\n## Pattern 7: Load Balancing with Retry\n\nDistribute load across multiple backends with automatic failover.\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-pool-id}\" \u002F>\n    \u003C\u002Finbound>\n    \u003Cbackend>\n        \u003C!-- Retry on 429 (rate limit) or 503 (service unavailable) -->\n        \u003Cretry count=\"2\" interval=\"0\" first-fast-retry=\"true\" \n            condition=\"@(context.Response.StatusCode == 429 || context.Response.StatusCode == 503)\">\n            \u003Cset-backend-service backend-id=\"{backend-pool-id}\" \u002F>\n            \u003Cforward-request buffer-request-body=\"true\" \u002F>\n        \u003C\u002Fretry>\n    \u003C\u002Fbackend>\n    \u003Con-error>\n        \u003Cwhen condition=\"@(context.Response.StatusCode == 503)\">\n            \u003Creturn-response>\n                \u003Cset-status code=\"503\" reason=\"Service Unavailable\" \u002F>\n            \u003C\u002Freturn-response>\n        \u003C\u002Fwhen>\n    \u003C\u002Fon-error>\n\u003C\u002Fpolicies>\n```\n\n## Pattern 8: Add AI Foundry Model Behind Gateway\n\nWhen user asks to \"add my model behind gateway\", first discover available models from Azure AI Foundry, then ask which model to add.\n\n### Step 1: Discover AI Foundry Projects and Available Models\n\n```bash\n# Set environment variables\naccountName=\"\u003Cai-foundry-resource-name>\"\nresourceGroupName=\"\u003Cresource-group>\"\n\n# List AI Foundry resources (AI Services accounts)\naz cognitiveservices account list --query \"[?kind=='AIServices'].{name:name, resourceGroup:resourceGroup, location:location}\" -o table\n\n# List available models in the AI Foundry resource\naz cognitiveservices account list-models \\\n  -n $accountName \\\n  -g $resourceGroupName \\\n  | jq '.[] | { name: .name, format: .format, version: .version, sku: .skus[0].name, capacity: .skus[0].capacity.default }'\n\n# List already deployed models\naz cognitiveservices account deployment list \\\n  -n $accountName \\\n  -g $resourceGroupName\n```\n\n### Step 2: Ask User Which Model to Add\n\nAfter listing the available models, **use the ask_user tool** to present the models as choices and let the user select which model to add behind the gateway.\n\nExample choices to present:\n- Model deployments from the discovered list\n- Include model name, format (provider), version, and SKU info\n\n### Step 3: Deploy the Model (if not already deployed)\n\n```bash\n# Deploy the selected model to AI Foundry\naz cognitiveservices account deployment create \\\n  -n $accountName \\\n  -g $resourceGroupName \\\n  --deployment-name \u003Cmodel-name> \\\n  --model-name \u003Cmodel-name> \\\n  --model-version \u003Cversion> \\\n  --model-format \u003Cformat> \\\n  --sku-capacity 1 \\\n  --sku-name \u003Csku>\n```\n\n### Step 4: Configure APIM Backend for Selected Model\n\n```bash\n# Get the AI Foundry inference endpoint\nENDPOINT=$(az cognitiveservices account show \\\n  -n $accountName \\\n  -g $resourceGroupName \\\n  | jq -r '.properties.endpoints[\"Azure AI Model Inference API\"]')\n\n# Create APIM backend for the selected model\naz apim backend create \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --backend-id \u003Cmodel-deployment-name>-backend \\\n  --protocol http \\\n  --url \"${ENDPOINT}\"\n```\n\n### Step 5: Create API and Apply Policies\n\n```bash\n# Import Azure OpenAI API specification\naz apim api import \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --path \u003Cmodel-deployment-name> \\\n  --specification-format OpenApiJson \\\n  --specification-url \"https:\u002F\u002Fraw.githubusercontent.com\u002FAzure\u002Fazure-rest-api-specs\u002Fmain\u002Fspecification\u002Fcognitiveservices\u002Fdata-plane\u002FAzureOpenAI\u002Finference\u002Fstable\u002F2024-02-01\u002Finference.json\"\n```\n\n### Step 6: Grant APIM Access to AI Foundry\n\n```bash\n# Get APIM managed identity principal ID\nAPIM_PRINCIPAL_ID=$(az apim show \\\n  --name \u003Capim-service-name> \\\n  --resource-group \u003Capim-resource-group> \\\n  --query \"identity.principalId\" -o tsv)\n\n# Get AI Foundry resource ID\nAI_RESOURCE_ID=$(az cognitiveservices account show \\\n  -n $accountName \\\n  -g $resourceGroupName \\\n  --query \"id\" -o tsv)\n\n# Assign Cognitive Services User role\naz role assignment create \\\n  --assignee $APIM_PRINCIPAL_ID \\\n  --role \"Cognitive Services User\" \\\n  --scope $AI_RESOURCE_ID\n```\n\n### Bicep Template for Backend Configuration\n\n```bicep\nparam apimServiceName string\nparam backendId string\nparam aiFoundryEndpoint string\nparam modelDeploymentName string\n\nresource apimService 'Microsoft.ApiManagement\u002Fservice@2024-06-01-preview' existing = {\n  name: apimServiceName\n}\n\nresource backend 'Microsoft.ApiManagement\u002Fservice\u002Fbackends@2024-06-01-preview' = {\n  parent: apimService\n  name: backendId\n  properties: {\n    protocol: 'http'\n    url: '${aiFoundryEndpoint}openai\u002Fdeployments\u002F${modelDeploymentName}'\n    credentials: {\n      header: {}\n    }\n    tls: {\n      validateCertificateChain: true\n      validateCertificateName: true\n    }\n  }\n}\n```\n\n## Pattern 9: Import API from OpenAPI Specification\n\nAdd an API to the gateway from an OpenAPI\u002FSwagger specification, either from a local file or web URL.\n\n### Step 1: Import API from Web URL\n\n```bash\n# Import API from a publicly accessible OpenAPI spec URL\naz apim api import \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --api-id \u003Capi-id> \\\n  --path \u003Capi-path> \\\n  --display-name \"\u003CAPI Display Name>\" \\\n  --specification-format OpenApiJson \\\n  --specification-url \"https:\u002F\u002Fexample.com\u002Fopenapi.json\"\n```\n\n### Step 2: Import API from Local File\n\n```bash\n# Import API from a local OpenAPI spec file (JSON or YAML)\naz apim api import \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --api-id \u003Capi-id> \\\n  --path \u003Capi-path> \\\n  --display-name \"\u003CAPI Display Name>\" \\\n  --specification-format OpenApi \\\n  --specification-path \".\u002Fopenapi.yaml\"\n```\n\n### Step 3: Configure Backend for the API\n\n```bash\n# Create backend pointing to your API server\naz apim backend create \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --backend-id \u003Cbackend-id> \\\n  --protocol http \\\n  --url \"https:\u002F\u002Fyour-api-server.com\"\n\n# Update API to use the backend\naz apim api update \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --api-id \u003Capi-id> \\\n  --set properties.serviceUrl=\"https:\u002F\u002Fyour-api-server.com\"\n```\n\n### Step 4: Apply Policies (Optional)\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003Cset-backend-service backend-id=\"{backend-id}\" \u002F>\n        \u003C!-- Add rate limiting -->\n        \u003Crate-limit-by-key \n            calls=\"100\" \n            renewal-period=\"60\" \n            counter-key=\"@(context.Request.IpAddress)\" \u002F>\n    \u003C\u002Finbound>\n    \u003Coutbound>\n        \u003Cbase \u002F>\n    \u003C\u002Foutbound>\n\u003C\u002Fpolicies>\n```\n\n### Supported Specification Formats\n\n| Format | Value | File Extension |\n|--------|-------|----------------|\n| OpenAPI 3.x JSON | `OpenApiJson` | `.json` |\n| OpenAPI 3.x YAML | `OpenApi` | `.yaml`, `.yml` |\n| Swagger 2.0 JSON | `SwaggerJson` | `.json` |\n| Swagger 2.0 (link) | `SwaggerLinkJson` | URL |\n| WSDL | `Wsdl` | `.wsdl` |\n| WADL | `Wadl` | `.wadl` |\n\n## Pattern 10: Convert API to MCP Server\n\nConvert existing APIM API operations into an MCP (Model Context Protocol) server, enabling AI agents to discover and use your APIs as tools.\n\n### Prerequisites\n\n- APIM instance with Basicv2 SKU or higher\n- Existing API imported into APIM\n- MCP feature enabled on APIM\n\n### Step 1: List Existing APIs in APIM\n\n```bash\n# List all APIs in APIM\naz apim api list \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --query \"[].{id:name, displayName:displayName, path:path}\" \\\n  -o table\n```\n\n### Step 2: Ask User Which API to Convert\n\nAfter listing the APIs, **use the ask_user tool** to let the user select which API to convert to an MCP server.\n\n### Step 3: List API Operations\n\n```bash\n# List all operations for the selected API\naz apim api operation list \\\n  --resource-group \u003Capim-resource-group> \\\n  --service-name \u003Capim-service-name> \\\n  --api-id \u003Capi-id> \\\n  --query \"[].{operationId:name, displayName:displayName, method:method, urlTemplate:urlTemplate}\" \\\n  -o table\n```\n\n### Step 4: Ask User Which Operations to Expose as MCP Tools\n\nAfter listing the operations, **use the ask_user tool** to present the operations as choices. Let the user select which operations to expose as MCP tools. Users may want to expose all operations or only a subset.\n\nExample choices to present:\n- All operations (convert entire API)\n- Individual operations from the discovered list\n- Include operation name, method, and URL template\n\n### Step 5: Enable MCP Server on APIM\n\n```bash\n# Enable MCP server capability (via ARM\u002FBicep or Portal)\n# Note: MCP configuration is done via APIM policies and product configuration\n```\n\n### Step 6: Configure MCP Endpoint for API\n\nCreate an MCP-compatible endpoint that exposes your API operations as tools:\n\n```xml\n\u003Cpolicies>\n    \u003Cinbound>\n        \u003Cbase \u002F>\n        \u003C!-- MCP tools\u002Flist endpoint handler -->\n        \u003Cchoose>\n            \u003Cwhen condition=\"@(context.Request.Url.Path.EndsWith(\"\u002Fmcp\u002Ftools\u002Flist\"))\">\n                \u003Creturn-response>\n                    \u003Cset-status code=\"200\" reason=\"OK\" \u002F>\n                    \u003Cset-header name=\"Content-Type\" exists-action=\"override\">\n                        \u003Cvalue>application\u002Fjson\u003C\u002Fvalue>\n                    \u003C\u002Fset-header>\n                    \u003Cset-body>@{\n                        var tools = new JArray();\n                        \u002F\u002F Define your API operations as MCP tools\n                        tools.Add(new JObject(\n                            new JProperty(\"name\", \"operation_name\"),\n                            new JProperty(\"description\", \"Description of what this operation does\"),\n                            new JProperty(\"inputSchema\", new JObject(\n                                new JProperty(\"type\", \"object\"),\n                                new JProperty(\"properties\", new JObject(\n                                    new JProperty(\"param1\", new JObject(\n                                        new JProperty(\"type\", \"string\"),\n                                        new JProperty(\"description\", \"Parameter description\")\n                                    ))\n                                ))\n                            ))\n                        ));\n                        return new JObject(new JProperty(\"tools\", tools)).ToString();\n                    }\u003C\u002Fset-body>\n                \u003C\u002Freturn-response>\n            \u003C\u002Fwhen>\n        \u003C\u002Fchoose>\n    \u003C\u002Finbound>\n\u003C\u002Fpolicies>\n```\n\n### Step 7: Bicep Template for MCP-Enabled API\n\n```bicep\nparam apimServiceName string\nparam apiId string\nparam apiDisplayName string\nparam apiPath string\nparam backendUrl string\n\nresource apimService 'Microsoft.ApiManagement\u002Fservice@2024-06-01-preview' existing = {\n  name: apimServiceName\n}\n\nresource api 'Microsoft.ApiManagement\u002Fservice\u002Fapis@2024-06-01-preview' = {\n  parent: apimService\n  name: apiId\n  properties: {\n    displayName: apiDisplayName\n    path: apiPath\n    protocols: ['https']\n    serviceUrl: backendUrl\n    subscriptionRequired: true\n    \u002F\u002F MCP endpoints\n    apiType: 'http'\n  }\n}\n\n\u002F\u002F MCP tools\u002Flist operation\nresource mcpToolsListOperation 'Microsoft.ApiManagement\u002Fservice\u002Fapis\u002Foperations@2024-06-01-preview' = {\n  parent: api\n  name: 'mcp-tools-list'\n  properties: {\n    displayName: 'MCP Tools List'\n    method: 'POST'\n    urlTemplate: '\u002Fmcp\u002Ftools\u002Flist'\n    description: 'List available MCP tools'\n  }\n}\n\n\u002F\u002F MCP tools\u002Fcall operation\nresource mcpToolsCallOperation 'Microsoft.ApiManagement\u002Fservice\u002Fapis\u002Foperations@2024-06-01-preview' = {\n  parent: api\n  name: 'mcp-tools-call'\n  properties: {\n    displayName: 'MCP Tools Call'\n    method: 'POST'\n    urlTemplate: '\u002Fmcp\u002Ftools\u002Fcall'\n    description: 'Call an MCP tool'\n  }\n}\n```\n\n### Step 8: Test MCP Endpoint\n\n```bash\n# Get APIM gateway URL\nGATEWAY_URL=$(az apim show \\\n  --name \u003Capim-service-name> \\\n  --resource-group \u003Capim-resource-group> \\\n  --query \"gatewayUrl\" -o tsv)\n\n# Test MCP tools\u002Flist endpoint\ncurl -X POST \"${GATEWAY_URL}\u002F\u003Capi-path>\u002Fmcp\u002Ftools\u002Flist\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Ocp-Apim-Subscription-Key: \u003Csubscription-key>\" \\\n  -d '{}'\n```\n\n### MCP Tool Definition Schema\n\nWhen converting API operations to MCP tools, use this schema:\n\n```json\n{\n  \"tools\": [\n    {\n      \"name\": \"get_weather\",\n      \"description\": \"Get current weather for a location\",\n      \"inputSchema\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"location\": {\n            \"type\": \"string\",\n            \"description\": \"City name or coordinates\"\n          }\n        },\n        \"required\": [\"location\"]\n      }\n    }\n  ]\n}\n```\n\n### Reference\n\n- [MCP Server Overview](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fapi-management\u002Fmcp-server-overview)\n- [MCP from API Lab](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fmcp-from-api)\n\n## Lab References (AI-Gateway Repo)\n\n**Essential Labs to Get Started:**\n\n| Scenario | Lab | Description |\n|----------|-----|-------------|\n| Semantic Caching | [semantic-caching](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fsemantic-caching) | Cache similar prompts to reduce costs |\n| Token Rate Limiting | [token-rate-limiting](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Ftoken-rate-limiting) | Limit tokens per minute |\n| Content Safety | [content-safety](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fcontent-safety) | Filter harmful content |\n| Load Balancing | [backend-pool-load-balancing](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fbackend-pool-load-balancing) | Distribute load across backends |\n| MCP from API | [mcp-from-api](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fmcp-from-api) | Convert OpenAPI to MCP server |\n| Zero to Production | [zero-to-production](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\u002Fzero-to-production) | Complete production setup guide |\n\n**Find more labs at:** https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway\u002Ftree\u002Fmain\u002Flabs\n\n## Quick Start Checklist\n\n### Prerequisites\n- [ ] Azure subscription created\n- [ ] Azure CLI installed and authenticated (`az login`)\n- [ ] Resource group created for AI Gateway resources\n\n### Deployment\n- [ ] Deploy APIM with Basicv2 SKU\n- [ ] Configure managed identity\n- [ ] Add backend for Azure OpenAI or AI Foundry\n- [ ] Apply policies (caching, rate limits, content safety)\n\n### Verification\n- [ ] Test API endpoint through gateway\n- [ ] Verify token metrics in Application Insights\n- [ ] Check rate limiting headers in response\n- [ ] Validate content safety filtering\n\n## Best Practices\n\n| Practice | Description |\n|----------|-------------|\n| **Default to Basicv2** | Use Basicv2 SKU for cost\u002Fspeed optimization |\n| **Use managed identity** | Prefer managed identity over API keys for backend auth |\n| **Enable token metrics** | Use `azure-openai-emit-token-metric` for cost tracking |\n| **Semantic caching** | Cache similar prompts to reduce costs (60-80% savings possible) |\n| **Rate limit by key** | Use subscription ID or IP for granular rate limiting |\n| **Content safety** | Enable `shield-prompt` to detect jailbreak attempts |\n\n## Troubleshooting\n\n| Issue | Symptom | Solution |\n|-------|---------|----------|\n| **Slow APIM creation** | Deployment takes 30+ minutes | Use Basicv2 SKU instead of Premium |\n| **Token limit exceeded** | 429 response | Increase `tokens-per-minute` or add load balancing |\n| **Cache not working** | No cache hits | Lower `score-threshold` (e.g., 0.7) |\n| **Content blocked** | False positives | Increase category thresholds |\n| **Backend auth fails** | 401 from Azure OpenAI | Assign Cognitive Services User role to APIM managed identity |\n| **Rate limit too strict** | Legitimate requests blocked | Increase `calls` or `renewal-period` |\n\n## SDK Quick References\n\n- **Content Safety**: [Python](references\u002Fsdk\u002Fazure-ai-contentsafety-py.md) | [TypeScript](references\u002Fsdk\u002Fazure-ai-contentsafety-ts.md)\n- **API Management**: [Python](references\u002Fsdk\u002Fazure-mgmt-apimanagement-py.md) | [.NET](references\u002Fsdk\u002Fazure-mgmt-apimanagement-dotnet.md)\n\n## Additional Resources\n\n- [Azure API Management Documentation](https:\u002F\u002Flearn.microsoft.com\u002Fazure\u002Fapi-management\u002F)\n- [AI Gateway Samples Repository](https:\u002F\u002Fgithub.com\u002FAzure-Samples\u002FAI-Gateway)\n- [APIM Policies Reference](https:\u002F\u002Flearn.microsoft.com\u002Fazure\u002Fapi-management\u002Fapi-management-policies)\n- [Azure OpenAI Integration](https:\u002F\u002Flearn.microsoft.com\u002Fazure\u002Fapi-management\u002Fazure-openai-api-from-specification)\n",{"name":5,"description":7},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002Fmicrosoft\u002Fazure-aigateway",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":70,"prompt":80,"zipAvailable":81},[71,74,77],{"tool":72,"command":73},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill azure-aigateway",{"tool":75,"command":76},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill azure-aigateway",{"tool":78,"command":79},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill azure-aigateway","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fmicrosoft\u002Fazure-aigateway\u002FSKILL.md",true,[83,89,93,97,101],{"path":84,"resourceType":85,"resourceTypeDesc":86,"sizeBytes":87,"sourceHtmlUrl":88},"references\u002Fsdk\u002Fazure-ai-contentsafety-py.md","REFERENCE","参考文档",1361,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fmicrosoft\u002Fazure-aigateway\u002Freferences\u002Fsdk\u002Fazure-ai-contentsafety-py.md",{"path":90,"resourceType":85,"resourceTypeDesc":86,"sizeBytes":91,"sourceHtmlUrl":92},"references\u002Fsdk\u002Fazure-ai-contentsafety-ts.md",1413,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fmicrosoft\u002Fazure-aigateway\u002Freferences\u002Fsdk\u002Fazure-ai-contentsafety-ts.md",{"path":94,"resourceType":85,"resourceTypeDesc":86,"sizeBytes":95,"sourceHtmlUrl":96},"references\u002Fsdk\u002Fazure-mgmt-apimanagement-dotnet.md",1059,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fmicrosoft\u002Fazure-aigateway\u002Freferences\u002Fsdk\u002Fazure-mgmt-apimanagement-dotnet.md",{"path":98,"resourceType":85,"resourceTypeDesc":86,"sizeBytes":99,"sourceHtmlUrl":100},"references\u002Fsdk\u002Fazure-mgmt-apimanagement-py.md",883,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fmicrosoft\u002Fazure-aigateway\u002Freferences\u002Fsdk\u002Fazure-mgmt-apimanagement-py.md",{"path":102,"resourceType":85,"resourceTypeDesc":86,"sizeBytes":103,"sourceHtmlUrl":104},"skill-report.json",10286,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fmicrosoft\u002Fazure-aigateway\u002Fskill-report.json",[106,116,125,134,140,147],{"skillNo":107,"name":108,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":112,"publishedAt":55},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[111],{"categoryNo":27,"categoryName":28,"taxonomyType":21,"taxonomyTypeDesc":22},[113,114,115],"model","model hierarchy","model hierarchy skill",{"skillNo":117,"name":118,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":122,"publishedAt":55},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[121],{"categoryNo":27,"categoryName":28,"taxonomyType":21,"taxonomyTypeDesc":22},[38,123,124],"zoom","zoom mcp",{"skillNo":126,"name":127,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":128,"categories":129,"keywords":130,"publishedAt":55},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[131,132,133,123],"sdk","zoom apps sdk","apps",{"skillNo":135,"name":136,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":139,"publishedAt":55},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[136],{"skillNo":141,"name":142,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":146,"publishedAt":55},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[145],{"categoryNo":27,"categoryName":28,"taxonomyType":21,"taxonomyTypeDesc":22},[142],{"skillNo":148,"name":149,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":150,"categories":151,"keywords":152,"publishedAt":55},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[149]]