|
9 | 9 | "## Microsoft Foundry Private connectivity lab\n", |
10 | 10 | "\n", |
11 | 11 | "\n", |
12 | | - "Playground to show how to create a private network for consuming REST API managed as MCPs using `Foundry Agents V1`. This lab demonstrates how to create a private network for consuming MCPs from `Foundry Agents V1` using `Private Link Services`, `Azure API Management (APIM)`, and `Azure Front Door`.\n", |
| 12 | + "Playground to show how to create a private network for consuming REST API managed as MCPs using `Foundry Agents Classic`. This lab demonstrates how to create a private network for consuming MCPs from `Foundry Agents Classic` using `Private Link Services`, `Azure API Management (APIM)`, and `Azure Front Door`.\n", |
13 | 13 | "\n", |
14 | 14 | "Notes:\n", |
15 | 15 | "- `Foundry Agents` are only accessible through `Private Endpoints`. Public network access is disabled.\n", |
|
19 | 19 | "- **`Azure Front Door` is the only publicly-accessible service.**\n", |
20 | 20 | "\n", |
21 | 21 | "### Prerequisites\n", |
| 22 | + "- **important** Admin access to be able to deploy and configure Enterprise Applications in Entra ID\n", |
22 | 23 | "- [Python 3.12 or later version](https://www.python.org/) installed\n", |
23 | 24 | "- [Pandas Library](https://pandas.pydata.org/) and matplotlib installed\n", |
24 | 25 | "- [VS Code](https://code.visualstudio.com/) installed with the [Jupyter notebook extension](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter) enabled\n", |
|
161 | 162 | " apim_resource_id = utils.get_deployment_output(output, 'apimResourceId', 'apimResourceId')\n", |
162 | 163 | "\n", |
163 | 164 | " outputPls = utils.run(f\"az network private-endpoint-connection list --id {apim_resource_id} --query \\\"[?properties.privateLinkServiceConnectionState.status=='Pending'].id\\\" --output tsv\")\n", |
164 | | - " print(outputPls.text)\n", |
165 | 165 | "\n", |
166 | 166 | " if outputPls.success:\n", |
167 | 167 | " pls_connection_id = outputPls.text.strip()\n", |
|
220 | 220 | " apim_resource_gateway_url = utils.get_deployment_output(output, 'apimResourceGatewayURL', 'APIM API Gateway URL')\n", |
221 | 221 | " apim_subscription_key = utils.get_deployment_output(output, 'apimSubscriptionKey', 'APIM Subscription Key (masked)', True)\n", |
222 | 222 | " ai_foundry_project_endpoint = utils.get_deployment_output(output, 'ai_project_endpoint', 'AI Foundry Project Endpoint')\n", |
223 | | - " ai_deployment_name = utils.get_deployment_output(output, 'ai_model_deployment_name', 'AI Model Deployment Name')" |
| 223 | + " ai_deployment_name = utils.get_deployment_output(output, 'ai_model_deployment_name', 'AI Model Deployment Name')\n", |
| 224 | + " vm_resource_id = utils.get_deployment_output(output, 'vmResourceId', 'VM Resource ID')\n", |
| 225 | + " key_vault_url = utils.get_deployment_output(output, 'keyVaultUrl', 'Key Vault URL')" |
224 | 226 | ] |
225 | 227 | }, |
226 | 228 | { |
|
230 | 232 | "<a id='6'></a>\n", |
231 | 233 | "### 6️⃣ 🧪 Test the API using a direct HTTP call through Frontdoor\n", |
232 | 234 | "\n", |
233 | | - "Requests is an elegant and simple HTTP library for Python that will be used here to make raw API requests and inspect the responses. " |
| 235 | + "Requests is an elegant and simple HTTP library for Python that will be used here to make raw API requests and inspect the responses.\n", |
| 236 | + "\n", |
| 237 | + "**After a successful deployment it may take up to 45 mins for this cell to run correctly**" |
234 | 238 | ] |
235 | 239 | }, |
236 | 240 | { |
|
271 | 275 | " error_text = response.text\n", |
272 | 276 | " except Exception:\n", |
273 | 277 | " error_text = \"[Unable to read response body]\"\n", |
274 | | - " utils.print_error(f\"Unexpected status code: {response.status_code}. Response text: {error_text}\")\n", |
| 278 | + " utils.print_error(f\"Unexpected status code: {response.status_code}.\")\n", |
275 | 279 | "\n", |
276 | 280 | "call_mcp_api(f\"https://{frontdoor_endpoint}\")" |
277 | 281 | ] |
|
310 | 314 | "\n" |
311 | 315 | ] |
312 | 316 | }, |
| 317 | + { |
| 318 | + "cell_type": "code", |
| 319 | + "execution_count": null, |
| 320 | + "metadata": {}, |
| 321 | + "outputs": [], |
| 322 | + "source": [ |
| 323 | + "utils.print_info(f\"\"\"Run the following command to connect to the VM via Bastion: \n", |
| 324 | + "az network bastion ssh \\\n", |
| 325 | + "--name bastion-host \\\n", |
| 326 | + "--resource-group {resource_group_name} \\\n", |
| 327 | + "--target-resource-id {vm_resource_id} \\\n", |
| 328 | + "--auth-type password \\\n", |
| 329 | + "--username azureuser\n", |
| 330 | + "\"\"\")" |
| 331 | + ] |
| 332 | + }, |
313 | 333 | { |
314 | 334 | "cell_type": "markdown", |
315 | 335 | "metadata": {}, |
316 | 336 | "source": [ |
317 | 337 | "##### 1. Connect to Jumpbox\n", |
318 | | - "Use Azure Bastion to connect to the VM:\n", |
319 | | - "\n", |
320 | | - "## MISSING NSG & SSH Allow rule\n", |
| 338 | + "Use Azure Bastion to connect to the VM (full command is the output from previos cell):\n", |
321 | 339 | "\n", |
322 | 340 | "```bash\n", |
323 | 341 | "az network bastion ssh \\\n", |
|
328 | 346 | " --username azureuser\n", |
329 | 347 | "```\n", |
330 | 348 | "\n", |
331 | | - "or\n", |
332 | | - "\n", |
| 349 | + "***Password:***\n", |
333 | 350 | "```bash\n", |
334 | | - "az ssh vm --resource-group lab-ai-foundry-private-mcp \\\n", |
335 | | - "--vm-name vm-jumpbox \\\n", |
336 | | - "--subscription <subscription-id>\n", |
| 351 | + "@Aa123456789\n", |
337 | 352 | "```\n", |
338 | 353 | "\n", |
339 | 354 | "Or connect via the Azure Portal: Navigate to the VM → Connect → Bastion\n", |
|
342 | 357 | "\n", |
343 | 358 | "##### 2. Download needed files\n", |
344 | 359 | "```bash \n", |
345 | | - "wget https://raw.githubusercontent.com/pablocast/AI-Gateway/refs/heads/main/requirements.txt\n", |
346 | 360 | "wget https://raw.githubusercontent.com/pablocast/AI-Gateway/refs/heads/main/labs/ai-foundry-private-mcp/agent/load_env_from_kv.py\n", |
347 | 361 | "wget https://raw.githubusercontent.com/pablocast/AI-Gateway/refs/heads/main/labs/ai-foundry-private-mcp/agent/sample_agents_mcp.py\n", |
348 | 362 | "```\n", |
349 | 363 | "\n", |
350 | | - "## MISSING REQUIREMENTS.TXT FILE\n", |
351 | | - "##### 4. Run the agent\n", |
| 364 | + "##### 3. Run the agent\n", |
352 | 365 | "```bash\n", |
353 | | - "python3 -m venv ~/venv\n", |
354 | | - "\n", |
355 | | - "# Activate virtual environment\n", |
356 | | - "source ~/venv/bin/activate\n", |
357 | | - "\n", |
358 | | - "pip install -r requirements.txt\n", |
359 | | - "\n", |
360 | 366 | "# Get Key Vault URL from deployment outputs\n", |
361 | | - "KEY_VAULT_URL=\"https://kv-xqdtyddlyrpoe.vault.azure.net/\"\n", |
| 367 | + "KEY_VAULT_URL=\"<KEY-VAULT-URL>\"\n", |
362 | 368 | "\n", |
363 | 369 | "# Run the MCP agent\n", |
364 | 370 | "python3 ~/sample_agents_mcp.py $KEY_VAULT_URL\n", |
|
0 commit comments