284 lines
11 KiB
Plaintext
284 lines
11 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Lesson 11 - Model Context Protocol (MCP)\n",
|
|
"\n",
|
|
"The **Model Context Protocol (MCP)** is an open standard that enables agents to dynamically discover and use tools, resources, and data sources at runtime. Instead of hardcoding tools into an agent, MCP lets agents connect to external servers that expose capabilities on demand.\n",
|
|
"\n",
|
|
"In this lesson, you'll learn:\n",
|
|
"- What MCP is and why it matters for agent systems\n",
|
|
"- How the MCP client-server architecture works\n",
|
|
"- How to build agents that use MCP-style tool discovery"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Setup\n",
|
|
"\n",
|
|
"**Prerequisites:**\n",
|
|
"- Microsoft Foundry project with a deployed model\n",
|
|
"- Run `az login` for authentication"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%pip install agent-framework azure-ai-projects azure-identity python-dotenv -q"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import logging\n",
|
|
"logging.getLogger(\"agent_framework.foundry\").setLevel(logging.ERROR)\n",
|
|
"\n",
|
|
"import os\n",
|
|
"import dotenv\n",
|
|
"from typing import Annotated\n",
|
|
"from agent_framework import tool\n",
|
|
"from agent_framework.foundry import FoundryChatClient\n",
|
|
"from azure.identity import DefaultAzureCredential\n",
|
|
"\n",
|
|
"dotenv.load_dotenv()\n",
|
|
"\n",
|
|
"endpoint = os.getenv(\"AZURE_AI_PROJECT_ENDPOINT\")\n",
|
|
"deployment_name = os.getenv(\"AZURE_AI_MODEL_DEPLOYMENT_NAME\")\n",
|
|
"\n",
|
|
"missing = [k for k, v in {\n",
|
|
" \"AZURE_AI_PROJECT_ENDPOINT\": endpoint,\n",
|
|
" \"AZURE_AI_MODEL_DEPLOYMENT_NAME\": deployment_name\n",
|
|
"}.items() if not v]\n",
|
|
"\n",
|
|
"if missing:\n",
|
|
" raise ValueError(\n",
|
|
" f\"Missing required environment variables: {', '.join(missing)}. \"\n",
|
|
" \"Please set them as environment variables (e.g., in your .env file or shell environment).\"\n",
|
|
" )\n",
|
|
"\n",
|
|
"# Create the Microsoft Foundry client\n",
|
|
"client = FoundryChatClient(\n",
|
|
" project_endpoint=endpoint,\n",
|
|
" model=deployment_name,\n",
|
|
" credential=DefaultAzureCredential()\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## What is the Model Context Protocol (MCP)?\n",
|
|
"\n",
|
|
"MCP defines a standard way for AI agents to discover and interact with external tools and data sources:\n",
|
|
"\n",
|
|
"- **MCP Server**: Exposes tools, resources, and prompts via a standard protocol\n",
|
|
"- **MCP Client**: The agent runtime that connects to servers and discovers available capabilities\n",
|
|
"- **Dynamic Discovery**: Agents don't need hardcoded tools — they discover what's available at runtime\n",
|
|
"\n",
|
|
"This is powerful for building extensible agent systems where new capabilities can be added without modifying the agent code."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## How MCP Works\n",
|
|
"\n",
|
|
"```\n",
|
|
"┌─────────────┐ discover ┌─────────────────┐\n",
|
|
"│ MCP Client │ ──────────────► │ MCP Server │\n",
|
|
"│ (Agent) │ │ (Tool Provider) │\n",
|
|
"│ │ ◄────────────── │ │\n",
|
|
"│ │ tool results │ • list_tools() │\n",
|
|
"│ │ │ • call_tool() │\n",
|
|
"└─────────────┘ │ • resources │\n",
|
|
" └─────────────────┘\n",
|
|
"```\n",
|
|
"\n",
|
|
"1. The agent (MCP client) connects to an MCP server\n",
|
|
"2. The server responds with a list of available tools and their schemas\n",
|
|
"3. The agent can then call any discovered tool during its reasoning\n",
|
|
"4. Results flow back through the same protocol"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Simulating MCP Tool Discovery\n",
|
|
"\n",
|
|
"Since a real MCP server requires a running server process, we'll demonstrate the pattern using `@tool` functions that simulate what an MCP-connected accommodation service would provide.\n",
|
|
"\n",
|
|
"In production, these tools would be discovered dynamically from an MCP server rather than defined locally."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"@tool(approval_mode=\"never_require\")\n",
|
|
"def search_accommodations(\n",
|
|
" location: Annotated[str, \"The city to search for accommodations\"],\n",
|
|
" check_in: Annotated[str, \"Check-in date (YYYY-MM-DD)\"],\n",
|
|
" check_out: Annotated[str, \"Check-out date (YYYY-MM-DD)\"],\n",
|
|
" guests: Annotated[int, \"Number of guests\"] = 2\n",
|
|
") -> str:\n",
|
|
" \"\"\"Search for accommodations (simulating an MCP-connected Airbnb tool).\n",
|
|
" In production, this would be discovered via MCP from an accommodation service.\"\"\"\n",
|
|
" listings = {\n",
|
|
" \"Tokyo\": [\n",
|
|
" {\"name\": \"Shinjuku Modern Apartment\", \"price\": 120, \"rating\": 4.8},\n",
|
|
" {\"name\": \"Traditional Ryokan in Asakusa\", \"price\": 200, \"rating\": 4.9},\n",
|
|
" {\"name\": \"Shibuya Studio\", \"price\": 85, \"rating\": 4.5},\n",
|
|
" ],\n",
|
|
" \"Paris\": [\n",
|
|
" {\"name\": \"Le Marais Charming Flat\", \"price\": 150, \"rating\": 4.7},\n",
|
|
" {\"name\": \"Montmartre Artist Loft\", \"price\": 110, \"rating\": 4.6},\n",
|
|
" ],\n",
|
|
" \"Barcelona\": [\n",
|
|
" {\"name\": \"Gothic Quarter Penthouse\", \"price\": 130, \"rating\": 4.8},\n",
|
|
" {\"name\": \"Barceloneta Beach Flat\", \"price\": 95, \"rating\": 4.4},\n",
|
|
" ],\n",
|
|
" }\n",
|
|
" results = listings.get(location, [])\n",
|
|
" if not results:\n",
|
|
" return f\"No accommodations found in {location}\"\n",
|
|
" output = f\"Accommodations in {location} ({check_in} to {check_out}, {guests} guests):\\n\"\n",
|
|
" for listing in results:\n",
|
|
" output += f\" - {listing['name']}: ${listing['price']}/night (★{listing['rating']})\\n\"\n",
|
|
" return output\n",
|
|
"\n",
|
|
"\n",
|
|
"@tool(approval_mode=\"never_require\")\n",
|
|
"def get_local_experiences(\n",
|
|
" location: Annotated[str, \"The city to find experiences in\"],\n",
|
|
" interest: Annotated[str, \"Type of experience (food, culture, adventure, etc.)\"] = \"all\"\n",
|
|
") -> str:\n",
|
|
" \"\"\"Get local experiences and activities (simulating an MCP-connected tourism tool).\"\"\"\n",
|
|
" experiences = {\n",
|
|
" \"Tokyo\": {\n",
|
|
" \"food\": [\"Tsukiji Market Tour ($45)\", \"Ramen Making Class ($60)\", \"Sake Tasting ($35)\"],\n",
|
|
" \"culture\": [\"Tea Ceremony ($50)\", \"Samurai Museum ($15)\", \"Sumo Tournament ($80)\"],\n",
|
|
" \"adventure\": [\"Mt. Fuji Day Trip ($120)\", \"Go-kart City Tour ($80)\"],\n",
|
|
" },\n",
|
|
" \"Paris\": {\n",
|
|
" \"food\": [\"Wine & Cheese Tasting ($55)\", \"Cooking Class ($90)\", \"Market Tour ($40)\"],\n",
|
|
" \"culture\": [\"Louvre Guided Tour ($35)\", \"Montmartre Art Walk ($25)\"],\n",
|
|
" },\n",
|
|
" }\n",
|
|
" city_exp = experiences.get(location, {})\n",
|
|
" if not city_exp:\n",
|
|
" return f\"No experiences found in {location}\"\n",
|
|
" if interest != \"all\" and interest in city_exp:\n",
|
|
" items = city_exp[interest]\n",
|
|
" return f\"{interest.title()} experiences in {location}:\\n\" + \"\\n\".join(f\" - {e}\" for e in items)\n",
|
|
" output = f\"All experiences in {location}:\\n\"\n",
|
|
" for cat, items in city_exp.items():\n",
|
|
" output += f\"\\n {cat.title()}:\\n\"\n",
|
|
" for item in items:\n",
|
|
" output += f\" - {item}\\n\"\n",
|
|
" return output"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Building an Agent with MCP-Style Tools"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"agent = client.as_agent(\n",
|
|
" tools=[search_accommodations, get_local_experiences],\n",
|
|
" name=\"AccommodationAgent\",\n",
|
|
" instructions=\"\"\"You are an accommodation and travel experiences specialist powered by MCP-connected services.\n",
|
|
"\n",
|
|
"Help travelers find the perfect place to stay and things to do. When searching:\n",
|
|
"1. Use the search_accommodations tool to find listings\n",
|
|
"2. Use the get_local_experiences tool to suggest activities\n",
|
|
"3. Compare options and make personalized recommendations\n",
|
|
"4. Consider the traveler's budget, interests, and travel style\"\"\",\n",
|
|
")\n",
|
|
"\n",
|
|
"response = await agent.run(\n",
|
|
" \"I'm visiting Tokyo for 5 nights in April with my partner. We love traditional Japanese culture and food. \"\n",
|
|
" \"Find us a place to stay and suggest some experiences.\",\n",
|
|
" )\n",
|
|
"print(response)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## MCP in Production\n",
|
|
"\n",
|
|
"In a production environment, MCP enables powerful patterns:\n",
|
|
"\n",
|
|
"- **Dynamic tool discovery**: Agents connect to MCP servers and discover tools at runtime\n",
|
|
"- **Decoupled architecture**: Tool providers can update independently of the agent\n",
|
|
"- **Cross-organization sharing**: Teams can expose capabilities via MCP servers that any agent can use\n",
|
|
"- **Microsoft Agent Framework support**: MAF has built-in MCP client support via the `mcp` integration\n",
|
|
"\n",
|
|
"To use a real MCP server with MAF, you would connect via `hosted_mcp_tool()` or the MCP client integration.\n",
|
|
"\n",
|
|
"**Learn more:**\n",
|
|
"- [MCP Specification](https://modelcontextprotocol.io/)\n",
|
|
"- [Microsoft Agent Framework MCP Support](https://github.com/microsoft/agent-framework/tree/main/python/samples/02-agents/mcp)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Summary\n",
|
|
"\n",
|
|
"In this lesson, you learned:\n",
|
|
"- **MCP** is an open standard for dynamic tool discovery between agents and tool providers\n",
|
|
"- The **client-server architecture** lets agents discover capabilities at runtime\n",
|
|
"- MCP enables **extensible, decoupled agent systems** where tools can be added without code changes\n",
|
|
"- Microsoft Agent Framework provides **built-in MCP support** for production use"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"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.12.13"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
}
|