404 lines
18 KiB
Plaintext
404 lines
18 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "b8c57858",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Azure AI Agents with Model Context Protocol (MCP) Support - Python\n",
|
||
"\n",
|
||
"このノートブックでは、PythonでAzure AI AgentsをModel Context Protocol (MCP) ツールと共に使用する方法を示します。外部のMCPサーバー(例えばMicrosoft Learn)を活用し、キー不要の認証を使用して機能を強化するインテリジェントエージェントを作成する方法を紹介します。\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "2e6e4234",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 必要なPythonパッケージのインストール\n",
|
||
"\n",
|
||
"まず、必要なPythonパッケージをインストールします:\n",
|
||
"- **azure-ai-projects**: Azure AI ProjectsのコアSDK\n",
|
||
"- **azure-ai-agents**: エージェントの作成と管理用Azure AI Agents SDK\n",
|
||
"- **azure-identity**: DefaultAzureCredentialを使用したキー不要の認証を提供\n",
|
||
"- **mcp**: Python向けのModel Context Protocol実装\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "6a2e9a05",
|
||
"metadata": {},
|
||
"source": [
|
||
"## キーレス認証のメリット\n",
|
||
"\n",
|
||
"このノートブックでは、**キーレス認証**のデモを行います。これには以下のような多くの利点があります:\n",
|
||
"- ✅ **APIキーの管理が不要** - Azureのアイデンティティベース認証を使用\n",
|
||
"- ✅ **セキュリティの向上** - コードや設定ファイルに秘密情報を保存しない\n",
|
||
"- ✅ **資格情報の自動ローテーション** - Azureが資格情報のライフサイクル管理を担当\n",
|
||
"- ✅ **ロールベースのアクセス制御** - Azure RBACを使用して細かい権限設定が可能\n",
|
||
"- ✅ **マルチ環境対応** - 開発環境と本番環境の両方でシームレスに動作\n",
|
||
"\n",
|
||
"`DefaultAzureCredential` は、利用可能な最適な資格情報ソースを自動的に選択します:\n",
|
||
"1. **マネージドID**(Azure上で実行されている場合)\n",
|
||
"2. **Azure CLI** の資格情報(ローカル開発時)\n",
|
||
"3. **Visual Studio** の資格情報\n",
|
||
"4. **環境変数**(設定されている場合)\n",
|
||
"5. **インタラクティブブラウザ**認証(フォールバックとして)\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "43efa94d",
|
||
"metadata": {},
|
||
"source": [
|
||
"## キーレス認証のセットアップ\n",
|
||
"\n",
|
||
"**キーレス認証の前提条件:**\n",
|
||
"\n",
|
||
"### ローカル開発の場合:\n",
|
||
"```bash\n",
|
||
"# Install Azure CLI and login\n",
|
||
"az login\n",
|
||
"# Verify your identity\n",
|
||
"az account show\n",
|
||
"```\n",
|
||
"\n",
|
||
"### Azure環境の場合:\n",
|
||
"- Azureリソースで**システム割り当てマネージドID**を有効化する\n",
|
||
"- マネージドIDに適切な**RBACロール**を割り当てる:\n",
|
||
" - Azure OpenAIアクセス用の`Cognitive Services OpenAI User`\n",
|
||
" - Azure AIプロジェクトアクセス用の`AI Developer`\n",
|
||
"\n",
|
||
"### 環境変数 (オプション):\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",
|
||
"**APIキーや接続文字列は不要です!** 🔐\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": [
|
||
"## 必要なライブラリのインポート\n",
|
||
"\n",
|
||
"必要なPythonモジュールをインポートします:\n",
|
||
"- **os, time**: 環境変数や遅延処理のための標準Pythonライブラリ\n",
|
||
"- **AIProjectClient**: Azure AI Projectsのメインクライアント\n",
|
||
"- **DefaultAzureCredential**: Azureサービスのキー不要認証\n",
|
||
"- **MCP関連クラス**: MCPツールの作成と管理、承認処理のため\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": [
|
||
"## MCPサーバー設定の構成\n",
|
||
"\n",
|
||
"環境変数を使用してMCPサーバーの設定を構成し、デフォルト値をフォールバックとして設定します:\n",
|
||
"- **MCP_SERVER_URL**: MCPサーバーのURL (デフォルトはMicrosoft Learn API)\n",
|
||
"- **MCP_SERVER_LABEL**: MCPサーバーを識別するためのラベル (デフォルトは \"mslearn\")\n",
|
||
"\n",
|
||
"この方法により、異なる環境で柔軟な構成が可能になります。\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": [
|
||
"## Azure AI プロジェクトクライアントの作成(キー不要の認証)\n",
|
||
"\n",
|
||
"**キー不要の認証**を使用して Azure AI プロジェクトクライアントを初期化します:\n",
|
||
"- **endpoint**: Azure AI Foundry プロジェクトのエンドポイント URL\n",
|
||
"- **credential**: `DefaultAzureCredential()` を使用して安全なキー不要の認証を実現\n",
|
||
"- **API キーは不要**: 利用可能な最適な資格情報を自動的に検出して使用\n",
|
||
"\n",
|
||
"**認証フロー:**\n",
|
||
"1. マネージド ID を確認(Azure 環境内)\n",
|
||
"2. Azure CLI 資格情報にフォールバック(ローカル開発用)\n",
|
||
"3. 必要に応じて他の利用可能な資格情報ソースを使用\n",
|
||
"\n",
|
||
"このアプローチにより、コード内で API キーや接続文字列を管理する必要がなくなります。\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": [
|
||
"## MCPツール定義の作成\n",
|
||
"\n",
|
||
"Microsoft Learn MCPサーバーに接続するMCPツールを作成します:\n",
|
||
"- **server_label**: MCPサーバーの識別子\n",
|
||
"- **server_url**: MCPサーバーのURLエンドポイント\n",
|
||
"- **allowed_tools**: 使用可能なツールを制限するためのオプションのリスト(空のリストの場合、すべてのツールが許可されます)\n",
|
||
"\n",
|
||
"このツールを使用することで、エージェントが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": [
|
||
"## エージェントの作成と会話の実行(キー不要のワークフロー)\n",
|
||
"\n",
|
||
"この包括的なセクションでは、**キー不要のエージェントワークフロー**の全体像を示します:\n",
|
||
"\n",
|
||
"1. **AIエージェントの作成**: GPT-4.1 nanoモデルとMCPツールを使用してエージェントを設定\n",
|
||
"2. **スレッドの作成**: コミュニケーション用の会話スレッドを確立\n",
|
||
"3. **メッセージの送信**: Azure OpenAIとOpenAIの違いについてエージェントに質問\n",
|
||
"4. **ツール承認の処理**: 必要に応じてMCPツールの呼び出しを自動承認\n",
|
||
"5. **実行の監視**: エージェントの進捗を追跡し、必要なアクションを処理\n",
|
||
"6. **結果の表示**: 会話内容とツール使用の詳細を表示\n",
|
||
"\n",
|
||
"**キー不要の特徴:**\n",
|
||
"- ✅ **ハードコードされた秘密情報なし** - すべての認証はAzure IDで処理\n",
|
||
"- ✅ **デフォルトで安全** - ロールベースのアクセス制御を使用\n",
|
||
"- ✅ **簡素化されたデプロイ** - 資格情報管理が不要\n",
|
||
"- ✅ **監査対応** - すべてのアクセスはAzure IDを通じて追跡\n",
|
||
"\n",
|
||
"エージェントはMCPツールを使用してMicrosoft Learnリソースにアクセスし、完全なセキュリティと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**免責事項**: \nこの文書はAI翻訳サービス[Co-op Translator](https://github.com/Azure/co-op-translator)を使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確な部分が含まれる可能性があります。元の言語で記載された文書が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。この翻訳の使用に起因する誤解や誤解について、当社は責任を負いません。\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:25:47+00:00",
|
||
"source_file": "05-AdvancedTopics/mcp-foundry-agent-integration/mcp_support_python.ipynb",
|
||
"language_code": "ja"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
} |