Files
2026-07-13 13:31:35 +08:00

493 lines
15 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"cells": [
{
"cell_type": "markdown",
"id": "deb94027",
"metadata": {},
"source": [
"# Azure AI Agents with Model Context Protocol (MCP) Support\n",
"\n",
"This notebook demonstrates how to use Azure AI Agents with Model Context Protocol (MCP) tools to create an intelligent agent that can leverage external MCP servers for enhanced capabilities."
]
},
{
"cell_type": "markdown",
"id": "c65b1772",
"metadata": {},
"source": [
"## Install Required NuGet Packages\n",
"\n",
"First, we need to install the Azure AI Agents Persistent package which provides the core functionality for working with Azure AI Agents."
]
},
{
"cell_type": "markdown",
"id": "000d6659",
"metadata": {},
"source": [
"## Keyless Authentication Benefits\n",
"\n",
"This notebook demonstrates **keyless authentication** which provides several advantages:\n",
"- ✅ **No API keys to manage** - Uses Azure identity-based authentication\n",
"- ✅ **Enhanced security** - No secrets stored in code or configuration\n",
"- ✅ **Automatic credential rotation** - Azure handles credential lifecycle\n",
"- ✅ **Role-based access** - Uses Azure RBAC for fine-grained permissions\n",
"\n",
"The `DefaultAzureCredential` will automatically use the best available credential source:\n",
"1. Managed Identity (when running in Azure)\n",
"2. Azure CLI credentials (during development)\n",
"3. Visual Studio credentials\n",
"4. Environment variables (if configured)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "ba8d7dfe",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Azure.AI.Agents.Persistent, 1.1.0-beta.4</span></li></ul></div></div>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"#r \"nuget: Azure.AI.Agents.Persistent, 1.1.0-beta.4\""
]
},
{
"cell_type": "markdown",
"id": "832540a4",
"metadata": {},
"source": [
"Install the Azure Identity package for authentication with Azure services using DefaultAzureCredential."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "836f34ef",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Azure.Identity, 1.14.2</span></li></ul></div></div>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"#r \"nuget: Azure.Identity, 1.14.2\""
]
},
{
"cell_type": "markdown",
"id": "c871f7c3",
"metadata": {},
"source": [
"## Import Required Namespaces\n",
"\n",
"Import the necessary namespaces for Azure AI Agents and Azure Identity."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "6f4467f6",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"using Azure.AI.Agents.Persistent;\n",
"using Azure.Identity;"
]
},
{
"cell_type": "markdown",
"id": "531fd5c4",
"metadata": {},
"source": [
"## Configure Azure AI Agent Client (Keyless Authentication)\n",
"\n",
"Set up the configuration variables and create the PersistentAgentsClient using **keyless authentication**:\n",
"- **projectEndpoint**: The Azure AI Foundry project endpoint\n",
"- **modelDeploymentName**: The name of the deployed AI model (GPT-4.1 nano)\n",
"- **mcpServerUrl**: The URL of the MCP server (Microsoft Learn API)\n",
"- **mcpServerLabel**: A label to identify the MCP server\n",
"- **DefaultAzureCredential**: Uses managed identity, Azure CLI, or other credential sources (no API keys required)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6aee3e93",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"var projectEndpoint = \"Your Azure AI Foundry Project Endpoint\";\n",
"var modelDeploymentName = \"Your Azure OpenAI Model Deployment Name\";\n",
"var mcpServerUrl = \"https://learn.microsoft.com/api/mcp\";\n",
"var mcpServerLabel = \"mslearn\";\n",
"PersistentAgentsClient agentClient = new(projectEndpoint, new DefaultAzureCredential());"
]
},
{
"cell_type": "markdown",
"id": "3fcd686c",
"metadata": {},
"source": [
"## Create MCP Tool Definition\n",
"\n",
"Create an MCP tool definition that connects to the Microsoft Learn MCP server. This will allow the agent to access Microsoft Learn content and documentation."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "678a4a25",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"MCPToolDefinition mcpTool = new(mcpServerLabel, mcpServerUrl);"
]
},
{
"cell_type": "markdown",
"id": "5304cefe",
"metadata": {},
"source": [
"## Create the AI Agent\n",
"\n",
"Create a persistent AI agent with the specified model and MCP tools. The agent is configured with:\n",
"- The GPT-4.1 nano model\n",
"- Instructions to use MCP tools for assistance\n",
"- Access to the Microsoft Learn MCP server"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cf7cb7d0",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"PersistentAgent agent = await agentClient.Administration.CreateAgentAsync(\n",
" model: modelDeploymentName,\n",
" name: \"my-learn-agent\",\n",
" instructions: \"You are a helpful agent that can use MCP tools to assist users. Use the available MCP tools to answer questions and perform tasks.\",\n",
" tools: [mcpTool]\n",
" );"
]
},
{
"cell_type": "markdown",
"id": "8e82cb78",
"metadata": {},
"source": [
"## Create Thread and Send Message\n",
"\n",
"Create a conversation thread and send a user message asking about the difference between Azure OpenAI and OpenAI. This will test the agent's ability to use the MCP tools to provide accurate information."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "c3e5fe54",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"PersistentAgentThread thread = await agentClient.Threads.CreateThreadAsync();\n",
"\n",
"// Create message to thread\n",
"PersistentThreadMessage message = await agentClient.Messages.CreateMessageAsync(\n",
" thread.Id,\n",
" MessageRole.User,\n",
" \"What's difference between Azure OpenAI and OpenAI?\");"
]
},
{
"cell_type": "markdown",
"id": "c6caf33e",
"metadata": {},
"source": [
"## Configure MCP Tool Resources (Keyless)\n",
"\n",
"Set up the MCP tool resources. For a truly keyless approach, you can remove custom headers if the MCP server supports Azure identity-based authentication. The example below shows how to add headers if needed, but for keyless scenarios, these may not be required."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b3dbe829",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"// Option 1: Completely keyless (if MCP server supports Azure identity)\n",
"MCPToolResource mcpToolResource = new(mcpServerLabel);\n",
"ToolResources toolResources = mcpToolResource.ToToolResources();\n",
"\n",
"// Option 2: With custom headers (if still needed for specific MCP servers)\n",
"// MCPToolResource mcpToolResource = new(mcpServerLabel);\n",
"// mcpToolResource.UpdateHeader(\"Authorization\", \"Bearer <your-token>\");\n",
"// ToolResources toolResources = mcpToolResource.ToToolResources();"
]
},
{
"cell_type": "markdown",
"id": "56469935",
"metadata": {},
"source": [
"## Start Agent Run\n",
"\n",
"Create and start a run to process the user's message. The agent will use the configured MCP tools and resources to generate a response."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "609f145c",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"ThreadRun run = await agentClient.Runs.CreateRunAsync(thread, agent, toolResources);"
]
},
{
"cell_type": "markdown",
"id": "80501bff",
"metadata": {},
"source": [
"## Monitor Run and Handle Tool Approvals (Keyless)\n",
"\n",
"Monitor the agent run status and handle any required tool approvals. This loop:\n",
"1. Waits for the run to complete or require action\n",
"2. Automatically approves MCP tool calls when required\n",
"3. For keyless authentication, headers may not be needed if the MCP server supports Azure identity"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "14056ceb",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Approving MCP tool call: microsoft_docs_search\n"
]
}
],
"source": [
"while (run.Status == RunStatus.Queued || run.Status == RunStatus.InProgress || run.Status == RunStatus.RequiresAction)\n",
"{\n",
" await Task.Delay(TimeSpan.FromMilliseconds(1000));\n",
" run = await agentClient.Runs.GetRunAsync(thread.Id, run.Id);\n",
"\n",
" if (run.Status == RunStatus.RequiresAction && run.RequiredAction is SubmitToolApprovalAction toolApprovalAction)\n",
" {\n",
" var toolApprovals = new List<ToolApproval>();\n",
" foreach (var toolCall in toolApprovalAction.SubmitToolApproval.ToolCalls)\n",
" {\n",
" if (toolCall is RequiredMcpToolCall mcpToolCall)\n",
" {\n",
" Console.WriteLine($\"Approving MCP tool call: {mcpToolCall.Name}\");\n",
" \n",
" // Option 1: Keyless approval (no headers needed)\n",
" toolApprovals.Add(new ToolApproval(mcpToolCall.Id, approve: true));\n",
" \n",
" // Option 2: With headers (if required by specific MCP server)\n",
" // toolApprovals.Add(new ToolApproval(mcpToolCall.Id, approve: true)\n",
" // {\n",
" // Headers = { [\"Authorization\"] = \"Bearer <your-token>\" }\n",
" // });\n",
" }\n",
" }\n",
"\n",
" if (toolApprovals.Count > 0)\n",
" {\n",
" run = await agentClient.Runs.SubmitToolOutputsToRunAsync(thread.Id, run.Id, toolApprovals: toolApprovals);\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "a87e050f",
"metadata": {},
"source": [
"## Display Conversation Results\n",
"\n",
"Retrieve and display all messages in the thread, showing both the user's question and the agent's response. The messages are displayed in chronological order with timestamps and role indicators."
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "f08a5dbe",
"metadata": {
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2025-07-16 06:39:43 - user: What's difference between Azure OpenAI and OpenAI?\n",
"2025-07-16 06:39:51 - assistant: The main difference between Azure OpenAI and OpenAI lies in their deployment, management, and integration options:\n",
"\n",
"1. **Azure OpenAI**:\n",
" - A cloud service offered through Microsoft Azure.\n",
" - Provides access to OpenAI models with additional enterprise features like security, compliance, and scale.\n",
" - Allows integration with other Azure services, enabling seamless use within existing Azure-based solutions.\n",
" - Offers managed deployment, monitoring, and support within the Azure ecosystem.\n",
" - Suitable for organizations looking for enterprise-grade security, compliance, and regional availability.\n",
"\n",
"2. **OpenAI (OpenAI API)**:\n",
" - A standalone API service provided directly by OpenAI.\n",
" - Accessible via the OpenAI platform without the need for Azure.\n",
" - Focused on providing GPT models, DALL-E, etc., primarily for developers and researchers.\n",
" - Suitable for individual developers, startups, and organizations preferring a direct connection to OpenAIs models.\n",
"\n",
"In summary, **Azure OpenAI** is essentially OpenAI models accessed via Microsoft Azure, with additional enterprise offerings and integrations, whereas **OpenAI API** provides direct access to OpenAI models without Azure integration.\n",
"\n",
"Would you like more detailed technical differences or usage scenarios?\n"
]
}
],
"source": [
"using Azure;\n",
"\n",
"AsyncPageable<PersistentThreadMessage> messages = agentClient.Messages.GetMessagesAsync(\n",
" threadId: thread.Id,\n",
" order: ListSortOrder.Ascending\n",
");\n",
"\n",
"await foreach (PersistentThreadMessage threadMessage in messages)\n",
"{\n",
" Console.Write($\"{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss} - {threadMessage.Role,10}: \");\n",
" foreach (MessageContent contentItem in threadMessage.ContentItems)\n",
" {\n",
" if (contentItem is MessageTextContent textItem)\n",
" {\n",
" Console.Write(textItem.Text);\n",
" }\n",
" else if (contentItem is MessageImageFileContent imageFileItem)\n",
" {\n",
" Console.Write($\"<image from ID: {imageFileItem.FileId}>\");\n",
" }\n",
" Console.WriteLine();\n",
" }\n",
"}"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".NET (C#)",
"language": "C#",
"name": ".net-csharp"
},
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelInfo": {
"defaultKernelName": "csharp",
"items": [
{
"aliases": [],
"name": "csharp"
}
]
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}