404 lines
17 KiB
Plaintext
404 lines
17 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b8c57858",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Agen AI Azure dengan Dukungan Model Context Protocol (MCP) - Python\n",
|
|
"\n",
|
|
"Notebook ini menunjukkan cara menggunakan Agen AI Azure dengan alat Model Context Protocol (MCP) dalam Python. Ini memperlihatkan cara membuat agen cerdas yang dapat memanfaatkan server MCP eksternal (seperti Microsoft Learn) untuk kemampuan yang lebih baik menggunakan autentikasi tanpa kunci.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "2e6e4234",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Instal Paket Python yang Diperlukan\n",
|
|
"\n",
|
|
"Pertama, kita perlu menginstal paket Python yang diperlukan:\n",
|
|
"- **azure-ai-projects**: SDK inti untuk Azure AI Projects\n",
|
|
"- **azure-ai-agents**: SDK Azure AI Agents untuk membuat dan mengelola agen\n",
|
|
"- **azure-identity**: Menyediakan autentikasi tanpa kunci menggunakan DefaultAzureCredential\n",
|
|
"- **mcp**: Implementasi Model Context Protocol untuk Python\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6a2e9a05",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Manfaat Autentikasi Tanpa Kunci\n",
|
|
"\n",
|
|
"Notebook ini menunjukkan **autentikasi tanpa kunci** yang memberikan beberapa keuntungan:\n",
|
|
"- ✅ **Tidak ada API key yang perlu dikelola** - Menggunakan autentikasi berbasis identitas Azure\n",
|
|
"- ✅ **Keamanan yang lebih baik** - Tidak ada rahasia yang disimpan dalam kode atau file konfigurasi\n",
|
|
"- ✅ **Rotasi kredensial otomatis** - Azure menangani manajemen siklus hidup kredensial\n",
|
|
"- ✅ **Kontrol akses berbasis peran** - Menggunakan Azure RBAC untuk izin yang lebih terperinci\n",
|
|
"- ✅ **Dukungan multi-lingkungan** - Berfungsi dengan lancar di lingkungan pengembangan dan produksi\n",
|
|
"\n",
|
|
"`DefaultAzureCredential` secara otomatis memilih sumber kredensial terbaik yang tersedia:\n",
|
|
"1. **Managed Identity** (saat berjalan di Azure)\n",
|
|
"2. Kredensial **Azure CLI** (selama pengembangan lokal)\n",
|
|
"3. Kredensial **Visual Studio**\n",
|
|
"4. **Variabel lingkungan** (jika dikonfigurasi)\n",
|
|
"5. Autentikasi **browser interaktif** (sebagai cadangan)\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "43efa94d",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Pengaturan Autentikasi Tanpa Kunci\n",
|
|
"\n",
|
|
"**Prasyarat untuk autentikasi tanpa kunci:**\n",
|
|
"\n",
|
|
"### Untuk Pengembangan Lokal:\n",
|
|
"```bash\n",
|
|
"# Install Azure CLI and login\n",
|
|
"az login\n",
|
|
"# Verify your identity\n",
|
|
"az account show\n",
|
|
"```\n",
|
|
"\n",
|
|
"### Untuk Lingkungan Azure:\n",
|
|
"- Aktifkan **System-assigned Managed Identity** pada sumber daya Azure Anda\n",
|
|
"- Tetapkan **peran RBAC** yang sesuai untuk managed identity:\n",
|
|
" - `Cognitive Services OpenAI User` untuk akses Azure OpenAI\n",
|
|
" - `AI Developer` untuk akses Proyek AI Azure\n",
|
|
"\n",
|
|
"### Variabel Lingkungan (Opsional):\n",
|
|
"```python\n",
|
|
"# These are automatically detected by DefaultAzureCredential\n",
|
|
"# AZURE_CLIENT_ID=<your-client-id>\n",
|
|
"# AZURE_CLIENT_SECRET=<your-client-secret>\n",
|
|
"# AZURE_TENANT_ID=<your-tenant-id>\n",
|
|
"```\n",
|
|
"\n",
|
|
"**Tidak perlu kunci API atau string koneksi!** 🔐\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2e21387d",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"! pip install azure-ai-projects -U\n",
|
|
"! pip install azure-ai-agents==1.1.0b4 -U\n",
|
|
"! pip install azure-identity -U\n",
|
|
"! pip install mcp==1.11.0 -U"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b31c8873",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Impor Perpustakaan yang Diperlukan\n",
|
|
"\n",
|
|
"Impor modul Python yang diperlukan:\n",
|
|
"- **os, time**: Perpustakaan standar Python untuk variabel lingkungan dan penundaan\n",
|
|
"- **AIProjectClient**: Klien utama untuk Azure AI Projects\n",
|
|
"- **DefaultAzureCredential**: Autentikasi tanpa kunci untuk layanan Azure\n",
|
|
"- **Kelas terkait MCP**: Untuk membuat dan mengelola alat MCP serta menangani persetujuan\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "43667b32",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import os, time\n",
|
|
"from azure.ai.projects import AIProjectClient\n",
|
|
"from azure.identity import DefaultAzureCredential\n",
|
|
"from azure.ai.agents.models import McpTool, RequiredMcpToolCall, SubmitToolApprovalAction, ToolApproval\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "721355e5",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Konfigurasi Pengaturan Server MCP\n",
|
|
"\n",
|
|
"Atur konfigurasi server MCP menggunakan variabel lingkungan dengan nilai default sebagai cadangan:\n",
|
|
"- **MCP_SERVER_URL**: URL server MCP (defaultnya adalah Microsoft Learn API)\n",
|
|
"- **MCP_SERVER_LABEL**: Label untuk mengidentifikasi server MCP (defaultnya adalah \"mslearn\")\n",
|
|
"\n",
|
|
"Pendekatan ini memungkinkan konfigurasi yang fleksibel di berbagai lingkungan.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "189f3d55",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"mcp_server_url = os.environ.get(\"MCP_SERVER_URL\", \"https://learn.microsoft.com/api/mcp\")\n",
|
|
"mcp_server_label = os.environ.get(\"MCP_SERVER_LABEL\", \"mslearn\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "20612d9a",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Membuat Klien Proyek Azure AI (Autentikasi Tanpa Kunci)\n",
|
|
"\n",
|
|
"Inisialisasi klien Proyek Azure AI menggunakan **autentikasi tanpa kunci**:\n",
|
|
"- **endpoint**: URL endpoint proyek Azure AI Foundry\n",
|
|
"- **credential**: Menggunakan `DefaultAzureCredential()` untuk autentikasi yang aman tanpa kunci\n",
|
|
"- **Tidak memerlukan kunci API**: Secara otomatis mendeteksi dan menggunakan kredensial terbaik yang tersedia\n",
|
|
"\n",
|
|
"**Alur Autentikasi:**\n",
|
|
"1. Memeriksa Managed Identity (di lingkungan Azure)\n",
|
|
"2. Beralih ke kredensial Azure CLI (untuk pengembangan lokal)\n",
|
|
"3. Menggunakan sumber kredensial lain yang tersedia jika diperlukan\n",
|
|
"\n",
|
|
"Pendekatan ini menghilangkan kebutuhan untuk mengelola kunci API atau string koneksi dalam kode Anda.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "36b1dbd8",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"project_client = AIProjectClient(\n",
|
|
" endpoint=\"Your Azure AI Foundry Endpoint\",\n",
|
|
" credential=DefaultAzureCredential(),\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cdb6ab8c",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Membuat Definisi Alat MCP\n",
|
|
"\n",
|
|
"Buat alat MCP yang terhubung ke server Microsoft Learn MCP:\n",
|
|
"- **server_label**: Pengenal untuk server MCP\n",
|
|
"- **server_url**: URL endpoint dari server MCP\n",
|
|
"- **allowed_tools**: Daftar opsional untuk membatasi alat yang dapat digunakan (daftar kosong mengizinkan semua alat)\n",
|
|
"\n",
|
|
"Alat ini akan memungkinkan agen untuk mengakses dokumentasi dan sumber daya Microsoft Learn.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "51e7e136",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"mcp_tool = McpTool(\n",
|
|
" server_label=mcp_server_label,\n",
|
|
" server_url=mcp_server_url,\n",
|
|
" allowed_tools=[], # Optional: specify allowed tools\n",
|
|
")\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6e894b0b",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Membuat Agen dan Melakukan Percakapan (Alur Kerja Tanpa Kunci)\n",
|
|
"\n",
|
|
"Bagian ini menjelaskan secara lengkap **alur kerja agen tanpa kunci**:\n",
|
|
"\n",
|
|
"1. **Membuat AI Agent**: Siapkan agen dengan model GPT-4.1 nano dan alat MCP\n",
|
|
"2. **Membuat Thread**: Buat thread percakapan untuk komunikasi\n",
|
|
"3. **Mengirim Pesan**: Tanyakan kepada agen tentang perbedaan Azure OpenAI dan OpenAI\n",
|
|
"4. **Menangani Persetujuan Alat**: Secara otomatis menyetujui panggilan alat MCP jika diperlukan\n",
|
|
"5. **Memantau Eksekusi**: Lacak kemajuan agen dan tangani tindakan yang diperlukan\n",
|
|
"6. **Menampilkan Hasil**: Tunjukkan detail percakapan dan penggunaan alat\n",
|
|
"\n",
|
|
"**Fitur Tanpa Kunci:**\n",
|
|
"- ✅ **Tidak ada rahasia yang dikodekan secara langsung** - Semua autentikasi ditangani oleh identitas Azure\n",
|
|
"- ✅ **Aman secara default** - Menggunakan kontrol akses berbasis peran\n",
|
|
"- ✅ **Penyebaran yang disederhanakan** - Tidak diperlukan pengelolaan kredensial\n",
|
|
"- ✅ **Ramah audit** - Semua akses dilacak melalui identitas Azure\n",
|
|
"\n",
|
|
"Agen akan menggunakan alat MCP untuk mengakses sumber daya Microsoft Learn dengan keamanan penuh tanpa pengelolaan kunci API.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "68c49af5",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"with project_client:\n",
|
|
" agents_client = project_client.agents\n",
|
|
"\n",
|
|
" # Create a new agent with keyless authentication\n",
|
|
" # NOTE: To reuse existing agent, fetch it with get_agent(agent_id)\n",
|
|
" agent = agents_client.create_agent(\n",
|
|
" model=\"Your Azure OpenAI Model Deployment Name\",\n",
|
|
" name=\"my-mcp-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=mcp_tool.definitions,\n",
|
|
" )\n",
|
|
" print(f\"Created agent, ID: {agent.id}\")\n",
|
|
" print(f\"MCP Server: {mcp_tool.server_label} at {mcp_tool.server_url}\")\n",
|
|
"\n",
|
|
" # Create thread for communication\n",
|
|
" thread = agents_client.threads.create()\n",
|
|
" print(f\"Created thread, ID: {thread.id}\")\n",
|
|
"\n",
|
|
" # Create message to thread\n",
|
|
" message = agents_client.messages.create(\n",
|
|
" thread_id=thread.id,\n",
|
|
" role=\"user\",\n",
|
|
" content=\"What's difference between Azure OpenAI and OpenAI?\",\n",
|
|
" )\n",
|
|
" print(f\"Created message, ID: {message.id}\")\n",
|
|
"\n",
|
|
" # KEYLESS APPROACH: Handle tool approvals without hardcoded secrets\n",
|
|
" \n",
|
|
" # Option 1: Completely keyless (recommended for Azure identity-enabled MCP servers)\n",
|
|
" # run = agents_client.runs.create(thread_id=thread.id, agent_id=agent.id, tool_resources=mcp_tool.resources)\n",
|
|
" \n",
|
|
" # Option 2: With minimal headers (if MCP server requires specific headers)\n",
|
|
" # For demonstration purposes, using a placeholder header\n",
|
|
" mcp_tool.update_headers(\"SuperSecret\", \"123456\") # Replace with actual auth if needed\n",
|
|
" \n",
|
|
" # Set approval mode - uncomment next line to disable approval requirement completely\n",
|
|
" # mcp_tool.set_approval_mode(\"never\") # Fully automated, no approval needed\n",
|
|
" \n",
|
|
" run = agents_client.runs.create(thread_id=thread.id, agent_id=agent.id, tool_resources=mcp_tool.resources)\n",
|
|
" print(f\"Created run, ID: {run.id}\")\n",
|
|
"\n",
|
|
" while run.status in [\"queued\", \"in_progress\", \"requires_action\"]:\n",
|
|
" time.sleep(1)\n",
|
|
" run = agents_client.runs.get(thread_id=thread.id, run_id=run.id)\n",
|
|
"\n",
|
|
" if run.status == \"requires_action\" and isinstance(run.required_action, SubmitToolApprovalAction):\n",
|
|
" tool_calls = run.required_action.submit_tool_approval.tool_calls\n",
|
|
" if not tool_calls:\n",
|
|
" print(\"No tool calls provided - cancelling run\")\n",
|
|
" agents_client.runs.cancel(thread_id=thread.id, run_id=run.id)\n",
|
|
" break\n",
|
|
"\n",
|
|
" tool_approvals = []\n",
|
|
" for tool_call in tool_calls:\n",
|
|
" if isinstance(tool_call, RequiredMcpToolCall):\n",
|
|
" try:\n",
|
|
" print(f\"Approving tool call: {tool_call}\")\n",
|
|
" \n",
|
|
" # KEYLESS APPROVAL OPTIONS:\n",
|
|
" \n",
|
|
" # Option 1: No headers (fully keyless)\n",
|
|
" # tool_approvals.append(\n",
|
|
" # ToolApproval(\n",
|
|
" # tool_call_id=tool_call.id,\n",
|
|
" # approve=True,\n",
|
|
" # headers={} # No headers needed for keyless\n",
|
|
" # )\n",
|
|
" # )\n",
|
|
" \n",
|
|
" # Option 2: With headers (if MCP server requires them)\n",
|
|
" tool_approvals.append(\n",
|
|
" ToolApproval(\n",
|
|
" tool_call_id=tool_call.id,\n",
|
|
" approve=True,\n",
|
|
" headers=mcp_tool.headers, # Uses configured headers if needed\n",
|
|
" )\n",
|
|
" )\n",
|
|
" except Exception as e:\n",
|
|
" print(f\"Error approving tool_call {tool_call.id}: {e}\")\n",
|
|
"\n",
|
|
" print(f\"tool_approvals: {tool_approvals}\")\n",
|
|
" if tool_approvals:\n",
|
|
" agents_client.runs.submit_tool_outputs(\n",
|
|
" thread_id=thread.id, run_id=run.id, tool_approvals=tool_approvals\n",
|
|
" )\n",
|
|
"\n",
|
|
" print(f\"Current run status: {run.status}\")\n",
|
|
"\n",
|
|
" print(f\"Run completed with status: {run.status}\")\n",
|
|
" if run.status == \"failed\":\n",
|
|
" print(f\"Run failed: {run.last_error}\")\n",
|
|
"\n",
|
|
" # Display run steps and tool calls\n",
|
|
" run_steps = agents_client.run_steps.list(thread_id=thread.id, run_id=run.id)\n",
|
|
"\n",
|
|
" # Loop through each step\n",
|
|
" for step in run_steps:\n",
|
|
" print(f\"Step {step['id']} status: {step['status']}\")\n",
|
|
"\n",
|
|
" # Check if there are tool calls in the step details\n",
|
|
" step_details = step.get(\"step_details\", {})\n",
|
|
" tool_calls = step_details.get(\"tool_calls\", [])\n",
|
|
"\n",
|
|
" if tool_calls:\n",
|
|
" print(\" MCP Tool calls:\")\n",
|
|
" for call in tool_calls:\n",
|
|
" print(f\" Tool Call ID: {call.get('id')}\")\n",
|
|
" print(f\" Type: {call.get('type')}\")\n",
|
|
"\n",
|
|
" print() # add an extra newline between steps\n",
|
|
"\n",
|
|
" # Fetch and log all messages\n",
|
|
" messages = agents_client.messages.list(thread_id=thread.id)\n",
|
|
" print(\"\\nConversation:\")\n",
|
|
" print(\"-\" * 50)\n",
|
|
" for msg in messages:\n",
|
|
" if msg.text_messages:\n",
|
|
" last_text = msg.text_messages[-1]\n",
|
|
" print(f\"{msg.role.upper()}: {last_text.text.value}\")\n",
|
|
" print(\"-\" * 50)\n",
|
|
"\n",
|
|
" # Example of dynamic tool management (keyless)\n",
|
|
" print(f\"\\nDemonstrating keyless dynamic tool management:\")\n",
|
|
" print(f\"Current allowed tools: {mcp_tool.allowed_tools}\")\n",
|
|
" print(\"✅ All operations completed using keyless authentication!\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Penafian**: \nDokumen ini telah diterjemahkan menggunakan layanan penerjemahan AI [Co-op Translator](https://github.com/Azure/co-op-translator). Meskipun kami berusaha untuk memberikan hasil yang akurat, harap diingat bahwa terjemahan otomatis mungkin mengandung kesalahan atau ketidakakuratan. Dokumen asli dalam bahasa aslinya harus dianggap sebagai sumber yang otoritatif. Untuk informasi yang bersifat kritis, disarankan menggunakan jasa penerjemahan profesional oleh manusia. Kami tidak bertanggung jawab atas kesalahpahaman atau penafsiran yang keliru yang timbul dari penggunaan terjemahan ini.\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "demo",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.10.15"
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "39a035fea0d10767dfcb0662bd3528fa",
|
|
"translation_date": "2025-08-26T21:37:13+00:00",
|
|
"source_file": "05-AdvancedTopics/mcp-foundry-agent-integration/mcp_support_python.ipynb",
|
|
"language_code": "id"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
} |