{"id":2635,"date":"2025-03-26T07:02:20","date_gmt":"2025-03-26T07:02:20","guid":{"rendered":"https:\/\/mailitics.com\/index.php\/2025\/03\/26\/clear-intro-to-mcp\/"},"modified":"2025-03-26T07:02:20","modified_gmt":"2025-03-26T07:02:20","slug":"clear-intro-to-mcp","status":"publish","type":"post","link":"https:\/\/mailitics.com\/index.php\/2025\/03\/26\/clear-intro-to-mcp\/","title":{"rendered":"A Clear Intro to MCP (Model Context Protocol) with Code Examples"},"content":{"rendered":"<p>    A Clear Intro to MCP (Model Context Protocol) with Code Examples<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n    <!-- no image --><br \/>\n \t<BR><br \/>\n<BR><\/BR><\/p>\n<div>\n<p class=\"wp-block-paragraph\"><mdspan datatext=\"el1742887159309\" class=\"mdspan-comment\">As the race<\/mdspan> to move AI agents from prototype to production heats up, the need for a standardized way for agents to call tools across different providers is pressing. This transition to a standardized approach to agent tool calling is similar to what we saw with REST APIs. Before they existed, developers had to deal with a mess of proprietary protocols just to pull data from different services. REST brought order to chaos, enabling systems to talk to each other in a consistent way. MCP (Model Context Protocol) is aiming to, as it sounds, provide context for AI models in a standard way. Without it, we\u2019re headed towards tool-calling mayhem where multiple incompatible versions of \u201cstandardized\u201d tool calls crop up simply because there\u2019s no shared way for agents to organize, share, and invoke tools. MCP gives us a shared language and the democratization of tool calling.<\/p>\n<p class=\"wp-block-paragraph\">One thing I\u2019m personally excited about is how tool-calling standards like MCP can actually make <a href=\"https:\/\/towardsdatascience.com\/tag\/ai-systems\/\" title=\"Ai Systems\">Ai Systems<\/a> <em>safer<\/em>. With easier access to well-tested tools more companies can avoid reinventing the wheel, which reduces security risks and minimizes the chance of malicious code. As Ai systems start scaling in 2025, these are valid concerns.<\/p>\n<p class=\"wp-block-paragraph\">As I dove into MCP, I realized a huge gap in documentation. There\u2019s plenty of high-level \u201cwhat does it do\u201d content, but when you actually want to understand <em>how<\/em> it works, the resources start to fall short\u2014especially for those who aren\u2019t native developers. It\u2019s either high level explainers or deep in the source code.<\/p>\n<p class=\"wp-block-paragraph\">In this piece, I\u2019m going to break MCP down for a broader audience\u2014making the concepts and functionality clear and digestible. If you\u2019re able, follow along in the coding section, if not it will be well explained in natural language above the code snippets.<\/p>\n<h2 class=\"wp-block-heading has-text-align-left has-heading-4-font-size\">An Analogy to Understand MCP: The Restaurant<\/h2>\n<p class=\"wp-block-paragraph\">Let\u2019s imagine the concept of MCP as a restaurant where we have:<\/p>\n<p class=\"wp-block-paragraph\">The Host = The restaurant building (the environment where the agent runs)<\/p>\n<p class=\"wp-block-paragraph\">The Server = The kitchen (where tools live)<\/p>\n<p class=\"wp-block-paragraph\">The Client = The waiter (who sends tool requests)<\/p>\n<p class=\"wp-block-paragraph\">The Agent = The customer (who decides what tool to use)<\/p>\n<p class=\"wp-block-paragraph\">The Tools = The recipes (the code that gets executed)<\/p>\n<h2 class=\"wp-block-heading has-heading-4-font-size\">The Components of MCP<\/h2>\n<p class=\"wp-block-paragraph\"><strong>Host<\/strong><strong><br \/><\/strong>This is where the agent operates. In our analogy, it\u2019s the restaurant building; in MCP, it\u2019s wherever your agents or LLMs actually run. If you\u2019re using Ollama locally, <em>you\u2019re<\/em> the host. If you\u2019re using Claude or GPT, then Anthropic or OpenAI are the hosts.<\/p>\n<p class=\"wp-block-paragraph\"><strong>Client<\/strong><\/p>\n<p class=\"wp-block-paragraph\">This is the environment that sends tool call requests from the agent. Think of it as the waiter who takes your order and delivers it to the kitchen. In practical terms, it\u2019s the application or interface where your agent runs. The client passes tool call requests to the <strong>Server<\/strong> using MCP.<\/p>\n<p class=\"wp-block-paragraph\"><strong>Server<\/strong><\/p>\n<p class=\"wp-block-paragraph\">This is the kitchen where recipes, or tools, are housed. It centralizes tools so agents can access them easily. Servers can be local (spun up by users) or remote (hosted by companies offering tools). Tools on a server are typically either grouped by function or integration. For instance, all Slack-related tools can be on a \u201cSlack server,\u201d or all messaging tools can be grouped together on a \u201cmessaging server\u201d. That decision is based on architectural and developer preferences.<\/p>\n<p class=\"wp-block-paragraph\"><strong>Agent<\/strong><\/p>\n<p class=\"wp-block-paragraph\">The \u201cbrains\u201d of the operation. Powered by an LLM, it decides which tools to call to complete a task. When it determines a tool is needed, it initiates a request to the server. The agent doesn\u2019t need to natively understand MCP because it learns how to use it through the metadata associated with each of the tools. This metadata associated with each tool tells the agent the protocol for calling the tool and the execution method. But it is important to note that the platform or agent needs to support MCP so that it handles tool calls automatically. Otherwise it is up to the developer to write the complex translation logic of how to parse the metadata from the schema, form tool call requests in MCP format, map the requests to the correct function, execute the code, and return the result in MCP complaint format back to the agent.<\/p>\n<p class=\"wp-block-paragraph\"><strong>Tools<\/strong><\/p>\n<p class=\"wp-block-paragraph\">These are the functions, such as calling APIs or custom code, that \u201cdoes the work\u201d. Tools live on servers and can be:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Custom tools you create and host on a local server.<\/li>\n<li class=\"wp-block-list-item\">Premade tools hosted by others on a remote server.<\/li>\n<li class=\"wp-block-list-item\">Premade code created by others but hosted by you on a local server.<\/li>\n<\/ul>\n<h2 class=\"wp-block-heading has-heading-4-font-size\">How the components fit together<\/h2>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">\n<strong>Server Registers Tools<\/strong><strong><br \/><\/strong> Each tool is defined with a name, description, input\/output schemas, a function handler (the code that runs) and registered to the server. This usually involves calling a method or API to tell the server \u201chey, here\u2019s a new tool and this is how you use it\u201d.\n<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Server Exposes Metadata<\/strong><strong><br \/><\/strong> When the server starts or an agent connects, it exposes the tool metadata (schemas, descriptions) via MCP.\n<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Agent Discovers Tools<\/strong><strong><br \/><\/strong>The agent queries the server (using MCP) to see what tools are available. It understands how to use each tool from the tool metadata. This typically happens on startup or when tools are added.\n<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Agent Plans Tool Use<\/strong><strong><br \/><\/strong>When the agent determines a tool is needed (based on user input or task context), it forms a tool call request in a standardized MCP JSON format which includes tool name, input parameters that match the tool\u2019s input schema, and any other metadata.<strong> <\/strong>The client acts as the transport layer and sends the MCP formatted request to the server over HTTP.\n<\/li>\n<li class=\"wp-block-list-item\">\n<strong>Translation Layer Executes<\/strong><br \/>The translation layer takes the agent\u2019s standardized tool call (via MCP), maps the request to the corresponding function on the server, executes the function, formats the result back to MCP, and sends it back to the agent. A framework that abstracts MCP for you deos all of this without the developer needing to write the translation layer logic (which sounds like a headache).<\/li>\n<\/ol>\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/03\/AD_4nXeeW11YxoD4PFmiDyq3U05WG_plNlrzy7IZUa1bcWQfG2_ECnwJ3xlGSFGMX94R_f0ZwmrZyqUBu4u-uIfvwiJD74XKtCu94FTE0vkfdxg1Ig_iZH3MPJOdL64qvctItpOxkCcA.png?ssl=1\" alt=\"\" class=\"wp-image-600152\"><figcaption class=\"wp-element-caption\">Image by Sandi Besen<\/figcaption><\/figure>\n<h2 class=\"wp-block-heading has-heading-4-font-size\">Code Example of A Re-Act Agent Using MCP Brave Search Server<\/h2>\n<p class=\"wp-block-paragraph\">In order to understand what MCP looks like when applied, let\u2019s use the beeAI framework from IBM, which natively supports MCP and handles the translation logic for us.<\/p>\n<p class=\"wp-block-paragraph\">\u00a0If you plan on running this code you will need to:<\/p>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Clone the <a href=\"https:\/\/github.com\/i-am-bee\/beeai-framework\">beeai framework repo<\/a> to gain access to the helper classes used in this code\u00a0<\/li>\n<li class=\"wp-block-list-item\">Create a <a href=\"https:\/\/github.com\/modelcontextprotocol\/servers\/blob\/main\/src\/brave-search\/README.md\">free Brave developer account<\/a> and get your API key. There are free subscriptions available (credit card required).\u00a0<\/li>\n<li class=\"wp-block-list-item\">Create an OpenAI developer account and create an API Key<\/li>\n<li class=\"wp-block-list-item\">Add your Brave API key and OpenAI key to the .env file at the python folder level of the repo.<\/li>\n<li class=\"wp-block-list-item\">Ensure you have npm installed and have set your path correctly.\n<\/li>\n<\/ol>\n<h3 class=\"wp-block-heading has-heading-6-font-size\"><strong>Sample .env file<\/strong><\/h3>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-markup\">BRAVE_API_KEY= \"&lt;Your API Key Here&gt;\"\nBEEAI_LOG_LEVEL=INFO\nOPENAI_API_KEY= \"&lt;Your API Key Here&gt;\"<\/code><\/pre>\n<h3 class=\"wp-block-heading has-heading-6-font-size\"><strong>Sample mcp_agent.ipynb<\/strong><\/h3>\n<p class=\"wp-block-paragraph\"><strong>1. Import the necessary libraries<\/strong><\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import asyncio\nimport logging\nimport os\nimport sys\nimport traceback\nfrom typing import Any\nfrom beeai_framework.agents.react.runners.default.prompts import SystemPromptTemplate\nfrom mcp import ClientSession, StdioServerParameters\nfrom mcp.client.stdio import stdio_client\nfrom beeai_framework import Tool\nfrom beeai_framework.agents.react.agent import ReActAgent\nfrom beeai_framework.agents.types import AgentExecutionConfig\nfrom beeai_framework.backend.chat import ChatModel, ChatModelParameters\nfrom beeai_framework.emitter.emitter import Emitter, EventMeta\nfrom beeai_framework.errors import FrameworkError\nfrom beeai_framework.logger import Logger\nfrom beeai_framework.memory.token_memory import TokenMemory\nfrom beeai_framework.tools.mcp_tools import MCPTool\nfrom pathlib import Path\nfrom beeai_framework.adapters.openai.backend.chat import OpenAIChatModel\nfrom beeai_framework.backend.message import SystemMessa<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>2. Load the environment variables and set the system path (if needed)<\/strong><\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import os\nfrom dotenv import load_dotenv\n\n# Absolute path to your .env file\n# sometimes the system can have trouble locating the .env file\nenv_path = &lt;Your path to your .env file&gt;\n# Load it\nload_dotenv(dotenv_path=env_path)\n\n# Get current working directory\npath = &lt;Your path to your current python directory&gt; #...beeai-framework\/python'\n# Append to sys.path\nsys.path.append(path)\n<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>3. Configure the logger<\/strong><\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># Configure logging - using DEBUG instead of trace\nlogger = Logger(\"app\", level=logging.DEBUG)<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>4. Load helper functions like process_agent_events,observer, and create an instance of ConsoleReader<\/strong><\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\"> process_agent_events: Handles agent events and logs messages to the console based on the event type (e.g., error, retry, update). It ensures meaningful output for each event to help track agent activity.<\/li>\n<li class=\"wp-block-list-item\">observer: Listens for all events from an emitter and routes them to process_agent_events for processing and display.<\/li>\n<li class=\"wp-block-list-item\">ConsoleReader: Manages console input\/output, allowing user interaction and formatted message display with color-coded roles.<\/li>\n<\/ul>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">#load console reader\nfrom examples.helpers.io import ConsoleReader\n#this is a helper function that makes the assitant chat easier to read\nreader = ConsoleReader()\n\ndef process_agent_events(data: dict[str, Any], event: EventMeta) -&gt; None:\n\u00a0 \"\"\"Process agent events and log appropriately\"\"\"\n\n\u00a0 if event.name == \"error\":\n\u00a0 \u00a0 \u00a0 reader.write(\"Agent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : \", FrameworkError.ensure(data[\"error\"]).explain())\n\u00a0 elif event.name == \"retry\":\n\u00a0 \u00a0 \u00a0 reader.write(\"Agent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : \", \"retrying the action...\")\n\u00a0 elif event.name == \"update\":\n\u00a0 \u00a0 \u00a0 reader.write(f\"Agent({data['update']['key']}) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : \", data[\"update\"][\"parsedValue\"])\n\u00a0 elif event.name == \"start\":\n\u00a0 \u00a0 \u00a0 reader.write(\"Agent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : \", \"starting new iteration\")\n\u00a0 elif event.name == \"success\":\n\u00a0 \u00a0 \u00a0 reader.write(\"Agent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : \", \"success\")\n\u00a0 else:\n\u00a0 \u00a0 \u00a0 print(event.path)\n\ndef observer(emitter: Emitter) -&gt; None:\n\u00a0 emitter.on(\"*.*\", process_agent_events)<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>5. Set the Brave API Key and server parameters. <\/strong><\/p>\n<p class=\"wp-block-paragraph\">Anthropic has a list of MCP servers <a href=\"https:\/\/modelcontextprotocol.io\/examples\">here<\/a>.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">brave_api_key = os.environ[\"BRAVE_API_KEY\"]\n\nbrave_server_params = StdioServerParameters(\n\u00a0 command=\"\/opt\/homebrew\/bin\/npx\",\u00a0 # Full path to be safe\n\u00a0 args=[\n\u00a0 \u00a0 \u00a0 \"-y\",\n\u00a0 \u00a0 \u00a0 \"@modelcontextprotocol\/server-brave-search\"\n\u00a0 ],\n\u00a0 env={\n\u00a0 \u00a0 \u00a0 \"BRAVE_API_KEY\": brave_api_key,\n\u00a0 \u00a0 \u00a0 \u00a0 \"x-subscription-token\": brave_api_key\n\u00a0 },\n)<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>6. Create the brave tool that initiates the connection to the MCP server, discovers tools, and returns the discovered tools to the Agents so it can decide what tool is appropriate to call for a given task.\u00a0<\/strong><\/p>\n<p class=\"wp-block-paragraph\">In this case 2 tools are discoverable on the Brave MCP Server:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">brave_web_search: Execute web searches with pagination and filtering<\/li>\n<li class=\"wp-block-list-item\">brave_local_search: Search for local businesses and services<\/li>\n<\/ul>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">async def brave_tool() -&gt; MCPTool:\n\u00a0 brave_env = os.environ.copy()\n\u00a0 brave_server_params = StdioServerParameters(\n\u00a0 \u00a0 \u00a0 command=\"\/opt\/homebrew\/bin\/npx\",\n\u00a0 \u00a0 \u00a0 args=[\"-y\", \"@modelcontextprotocol\/server-brave-search\"],\n\u00a0 \u00a0 \u00a0 env=brave_env\n\u00a0 )\n\n\u00a0 print(\"Starting MCP client...\")\n\u00a0 try:\n\u00a0 \u00a0 \u00a0 async with stdio_client(brave_server_params) as (read, write), ClientSession(read, write) as session:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 print(\"Client connected, initializing...\")\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 await asyncio.wait_for(session.initialize(), timeout=10)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 print(\"Initialized! Discovering tools...\")\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 bravetools = await asyncio.wait_for(\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 MCPTool.from_client(session, brave_server_params),\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 timeout=10\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 )\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 print(\"Tools discovered!\")\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return bravetools\n\u00a0 except asyncio.TimeoutError as e:\n\u00a0 \u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/274c.png?ssl=1\" alt=\"\u274c\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> Timeout occurred during session initialization or tool discovery.\")\n\u00a0 except Exception as e:\n\u00a0 \u00a0 \u00a0 print(\"<img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/274c.png?ssl=1\" alt=\"\u274c\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> Exception occurred:\", e)\n\u00a0 \u00a0 \u00a0 traceback.print_exc()<\/code><\/pre>\n<p class=\"wp-block-paragraph\">(Optional) Check the connection to the MCP server and ensure it returns all the available tools before providing it to the agent.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">tool = await brave_tool()\nprint(\"Discovered tools:\", tool)\n\nfor tool in tool:\n\u00a0 print(f\"Tool Name: {tool.name}\")\n\u00a0 print(f\"Description: {getattr(tool, 'description', 'No description available')}\")\n\u00a0 print(\"-\" * 30)<\/code><\/pre>\n<h3 class=\"wp-block-heading\"><em>OUTPUT:<\/em><\/h3>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-markup\">Starting MCP client...\n\nClient connected, initializing...\n\nInitialized! Discovering tools...\n\nTools discovered!\n\nDiscovered tools: [&lt;beeai_framework.tools.mcp_tools.MCPTool object at 0x119aa6c00&gt;, &lt;beeai_framework.tools.mcp_tools.MCPTool object at 0x10fee3e60&gt;]\n\nTool Name: brave_web_search\n\nDescription: Performs a web search using the Brave Search API, ideal for general queries, news, articles, and online content. Use this for broad information gathering, recent events, or when you need diverse web sources. Supports pagination, content filtering, and freshness controls. Maximum 20 results per request, with offset for pagination.\u00a0\n\n------------------------------\n\nTool Name: brave_local_search\n\nDescription: Searches for local businesses and places using Brave's Local Search API. Best for queries related to physical locations, businesses, restaurants, services, etc. Returns detailed information including:\n\n- Business names and addresses\n\n- Ratings and review counts\n\n- Phone numbers and opening hours\n\nUse this when the query implies 'near me' or mentions specific locations. Automatically falls back to web search if no local results are found.<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>7. Write the function that creates the agent:\u00a0\u00a0<\/strong><\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">assign an LLM<\/li>\n<li class=\"wp-block-list-item\">create an instance of the brave_tool() function and assign it to a tools variable<\/li>\n<li class=\"wp-block-list-item\">create a re-act agent and assign it the chosen llm, tools, memory (so it can have constinous conversation)<\/li>\n<li class=\"wp-block-list-item\">Add a system prompt to the re-act agent.\u00a0\u00a0<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">Note: You might notice that I added a sentence to the system prompt that reads \u201cIf you need to use the brave_tool you must use a count of 5.\u201d This is a bandaid work-around becasue of a bug I found in the <code>index.ts<\/code> file of the brave server. I will contribute to the repo to fix it.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">async def create_agent() -&gt; ReActAgent:\n\u00a0 \"\"\"Create and configure the agent with tools and LLM\"\"\"\n\u00a0 #using openai api instead\n\u00a0 llm = OpenAIChatModel(model_id=\"gpt-4o\")\n\u00a0\n\u00a0 # Configure tools\n\u00a0 tools: list[Tool] = await brave_tool()\n\u00a0 #tools: list[Tool] = [await brave_tool()]\n\n\u00a0 # Create agent with memory and tools\n\u00a0 agent = ReActAgent(llm=llm, tools=tools, memory=TokenMemory(llm), )\n\u00a0\n\u00a0 await agent.memory.add(SystemMessage(content=\"You are a helpful assistant. If you need to use the brave_tool you must use a count of 5.\"))\n\n\u00a0 return agent<\/code><\/pre>\n<p class=\"wp-block-paragraph\"><strong>8. Create the main function<\/strong> <\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Creates the agent<\/li>\n<li class=\"wp-block-list-item\">Enters a conversation loop with the user and runs the agent with the user prompt and some configuration settings. Finishes the conversation if the user types \u201cexit\u201d or \u201cquit\u201d.<\/li>\n<\/ul>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import asyncio\nimport traceback\nimport sys\n\n# Your async main function\nasync def main() -&gt; None:\n\u00a0 \"\"\"Main application loop\"\"\"\n\n\u00a0 # Create agent\n\u00a0 agent = await create_agent()\n\n\u00a0 # Main interaction loop with user input\n\u00a0 for prompt in reader:\n\u00a0 \u00a0 \u00a0 # Exit condition\n\u00a0 \u00a0 \u00a0 if prompt.strip().lower() in {\"exit\", \"quit\"}:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 reader.write(\"Session ended by user. Goodbye! <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f44b.png?ssl=1\" alt=\"\ud83d\udc4b\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\">n\")\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 break\n\n\u00a0 \u00a0 \u00a0 # Run agent with the prompt\n\u00a0 \u00a0 \u00a0 try:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 response = await agent.run(\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 prompt=prompt,\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 execution=AgentExecutionConfig(max_retries_per_step=3, total_max_retries=10, max_iterations=20),\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ).observe(observer)\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 reader.write(\"Agent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : \", response.result.text)\n\u00a0 \u00a0 \u00a0 except Exception as e:\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 reader.write(\"An error occurred: \", str(e))\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 traceback.print_exc()<\/code><\/pre>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\"># Run main() with error handling\ntry:\n\u00a0 await main()\nexcept FrameworkError as e:\n\u00a0 traceback.print_exc()\n\u00a0 sys.exit(e.explain())<\/code><\/pre>\n<h3 class=\"wp-block-heading\">OUTPUT:<\/h3>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-markup\">Starting MCP client...\n\nClient connected, initializing...\n\nInitialized! Discovering tools...\n\nTools discovered!\n\nInteractive session has started. To escape, input 'q' and submit.\n\nAgent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : starting new iteration\n\nAgent(thought) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : I will use the brave_local_search function to find the open hours for La Taqueria on Mission St in San Francisco.\n\nAgent(tool_name) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : brave_local_search\n\nAgent(tool_input) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : {'query': 'La Taqueria Mission St San Francisco'}\n\nAgent(tool_output) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : [{\"annotations\": null, \"text\": \"Error: Brave API error: 422 Unprocessable Entityn{\"type\":\"ErrorResponse\",\"error\":{\"id\":\"ddab2628-c96e-478f-80ee-9b5f8b1fda26\",\"status\":422,\"code\":\"VALIDATION\",\"detail\":\"Unable to validate request parameter(s)\",\"meta\":{\"errors\":[{\"type\":\"greater_than_equal\",\"loc\":[\"query\",\"count\"],\"msg\":\"Input should be greater than or equal to 1\",\"input\":\"0\",\"ctx\":{\"ge\":1}}]}},\"time\":1742589546}\", \"type\": \"text\"}]\n\nAgent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : starting new iteration\n\nAgent(thought) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : The function call resulted in an error. I will try again with a different approach to find the open hours for La Taqueria on Mission St in San Francisco.\n\nAgent(tool_name) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : brave_local_search\n\nAgent(tool_input) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : {'query': 'La Taqueria Mission St San Francisco', 'count': 5}\n\nAgent(tool_output) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : [{\"annotations\": null, \"text\": \"Title: LA TAQUERIA - Updated May 2024 - 2795 Photos &amp; 4678 Reviews - 2889 Mission St, San Francisco, California - Mexican - Restaurant Reviews - Phone Number - YelpnDescription: LA TAQUERIA, &lt;strong&gt;2889 Mission St, San Francisco, CA 94110&lt;\/strong&gt;, 2795 Photos, Mon - Closed, Tue - Closed, Wed - 11:00 am - 8:45 pm, Thu - 11:00 am - 8:45 pm, Fri - 11:00 am - 8:45 pm, Sat - 11:00 am - 8:45 pm, Sun - 11:00 am - 7:45 pmnURL: https:\/\/www.yelp.com\/biz\/la-taqueria-san-francisco-2nnTitle: La Taqueria: Authentic Mexican Cuisine for Every TastenDescription: La Taqueria - &lt;strong&gt;Mexican Food Restaurant&lt;\/strong&gt; welcomes you to enjoy our delicious. La Taqueria provides a full-service experience in a fun casual atmosphere and fresh flavors where the customer always comes first!nURL: https:\/\/lataqueria.gotoeat.net\/nnTitle: r\/sanfrancisco on Reddit: Whats so good about La Taqueria in The Mission?nDescription: 182 votes, 208 comments. Don't get me wrong its good but I failed to see the hype. I waited in a long line and once I got my food it just tastes like\u2026nURL: https:\/\/www.reddit.com\/r\/sanfrancisco\/comments\/1d0sf5k\/whats_so_good_about_la_taqueria_in_the_mission\/nnTitle: LA TAQUERIA, San Francisco - Mission District - Menu, Prices &amp; Restaurant Reviews - TripadvisornDescription: La Taqueria still going strong. &lt;strong&gt;Historically the most well known Burrito home in the city and Mission District&lt;\/strong&gt;. Everything is run like a clock. The fillings are just spiced and prepared just right. Carnitas, chicken, asada, etc have true home made flavors. The Tortillas both are super good ...nURL: https:\/\/www.tripadvisor.com\/Restaurant_Review-g60713-d360056-Reviews-La_Taqueria-San_Francisco_California.htmlnnTitle: La Taqueria \u2013 San Francisco - a MICHELIN Guide RestaurantnDescription: San Francisco Restaurants \u00b7 La Taqueria \u00b7 4 \u00b7 &lt;strong&gt;2889 Mission St., San Francisco, 94110, USA&lt;\/strong&gt; \u00b7 $ \u00b7 Mexican, Regional Cuisine \u00b7 Visited \u00b7 Favorite \u00b7 Find bookable restaurants near me \u00b7 &lt;strong&gt;2889 Mission St., San Francisco, 94110, USA&lt;\/strong&gt; \u00b7 $ \u00b7 Mexican, Regional Cuisine \u00b7nURL: https:\/\/guide.michelin.com\/us\/en\/california\/san-francisco\/restaurant\/la-taqueria\", \"type\": \"text\"}]\n\nAgent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : starting new iteration\n\nAgent(thought) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : I found the open hours for La Taqueria on Mission St in San Francisco. I will provide this information to the user.\n\nAgent(final_answer) <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : La Taqueria, located at 2889 Mission St, San Francisco, CA 94110, has the following opening hours:\n\n- Monday: Closed\n\n- Tuesday: Closed\n\n- Wednesday to Saturday: 11:00 AM - 8:45 PM\n\n- Sunday: 11:00 AM - 7:45 PM\n\nFor more details, you can visit their [Yelp page](https:\/\/www.yelp.com\/biz\/la-taqueria-san-francisco-2).\n\nAgent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : success\n\nAgent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : success\n\nrun.agent.react.finish\n\nAgent <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/s.w.org\/images\/core\/emoji\/15.0.3\/72x72\/1f916.png?ssl=1\" alt=\"\ud83e\udd16\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\"> : La Taqueria, located at 2889 Mission St, San Francisco, CA 94110, has the following opening hours:\n\n- Monday: Closed\n\n- Tuesday: Closed\n\n- Wednesday to Saturday: 11:00 AM - 8:45 PM\n\n- Sunday: 11:00 AM - 7:45 PM\n\nFor more details, you can visit their [Yelp page](https:\/\/www.yelp.com\/biz\/la-taqueria-san-francisco-2).<\/code><\/pre>\n<h2 class=\"wp-block-heading has-heading-4-font-size\">Conclusion, Challenges, and Where MCP is Headed<\/h2>\n<p class=\"wp-block-paragraph\">In this article you\u2019ve seen how MCP can provide a standardized way for agents to discover tools on an MCP server and then interact with them without the developer needing to specify the implementation details of the tool call. The level of abstraction that MCP offers is powerful. It means developers can focus on creating valuable tools while agents can seamlessly discover and use them through standard protocols.<\/p>\n<p class=\"wp-block-paragraph\">Our Restaurant example helped us visualize how MCP concepts like the host, client, server, agent, and tools work together \u2013 each with their own important role. The code example, where we used a Re-Act Agent in the Beeai framework, which handles MCP tool calling natively, to call the Brave MCP server with access to two tools provided a real world understanding of MCP can be used in practice.<br \/>Without protocols like MCP, we face a fragmented landscape where every AI provider implements their own incompatible tool-calling mechanisms\u2013 creating complexity, security vulnerabilities, and wasted development effort.<\/p>\n<h3 class=\"wp-block-heading has-heading-6-font-size\"><strong>In the coming months, we\u2019ll likely see MCP gain significant traction for several reasons:<\/strong><\/h3>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">As more tool providers adopt MCP, the network effect will accelerate adoption across the industry.<\/li>\n<li class=\"wp-block-list-item\">Standardized protocols mean better testing, fewer vulnerabilities, and reduced risks as AI systems scale.<\/li>\n<li class=\"wp-block-list-item\">The ability to write a tool once and have it work across multiple agent frameworks will dramatically reduce development overhead.<\/li>\n<li class=\"wp-block-list-item\">Smaller players can compete by focusing on building excellent tools rather than reinventing complex agent architectures.<\/li>\n<li class=\"wp-block-list-item\">Organizations can integrate AI agents more confidently knowing they\u2019re built on stable, interoperable standards.\n<\/li>\n<\/ul>\n<h3 class=\"wp-block-heading\"><strong>That said, MCP faces important challenges that need addressing as adoption grows:<\/strong><\/h3>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">As demonstrated in our code example, agents can only discover tools once connected to a server<\/li>\n<li class=\"wp-block-list-item\">The agent\u2019s functionality becomes dependent on server uptime and performance, introducing additional points of failure.<\/li>\n<li class=\"wp-block-list-item\">As the protocol evolves, maintaining compatibility while adding new features will require governance.<\/li>\n<li class=\"wp-block-list-item\">Standardizing how agents access potentially sensitive tools across different servers introduces security considerations.<\/li>\n<li class=\"wp-block-list-item\">The client-server architecture introduces additional latency.\n<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">For developers, AI researchers, and organizations building agent-based systems, understanding and adopting MCP now\u2014while being mindful of these challenges\u2014will provide a significant advantage as more AI solutions begin to scale.<\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dotted\">\n<p class=\"wp-block-paragraph\"><em>Note: The opinions expressed both in this article and paper are solely those of the authors and do not necessarily reflect the views or policies of their respective employers.<\/em><\/p>\n<p class=\"wp-block-paragraph\">Interested in connecting? Drop me a DM on <a href=\"https:\/\/www.linkedin.com\/in\/sandibesen\/\">Linkedin<\/a>! I\u2018m always eager to engage in food for thought and iterate on my work.<\/p>\n<p>The post <a href=\"https:\/\/towardsdatascience.com\/clear-intro-to-mcp\/\">A Clear Intro to MCP (Model Context Protocol) with Code Examples<\/a> appeared first on <a href=\"https:\/\/towardsdatascience.com\/\">Towards Data Science<\/a>.<\/p>\n<\/div>\n<p> \t<BR><br \/>\n <BR><\/BR><br \/>\n    Sandi Besen<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n<a href=\"https:\/\/towardsdatascience.com\/clear-intro-to-mcp\/\">Go to original source<\/a><br \/>\n \t<BR><br \/>\n <BR><\/BR><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A Clear Intro to MCP (Model Context Protocol) with Code Examples As the race to move AI agents from prototype to production heats up, the need for a standardized way for agents to call tools across different providers is pressing. This transition to a standardized approach to agent tool calling is similar to what we [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[678,2117,62,69,240,70,160],"tags":[368,2118,449],"class_list":["post-2635","post","type-post","status-publish","format-standard","hentry","category-agentic-ai","category-ai-systems","category-aimldsaimlds","category-artificial-intelligence","category-editors-pick","category-machine-learning","category-programming","tag-code","tag-mcp","tag-tool"],"_links":{"self":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/2635"}],"collection":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/comments?post=2635"}],"version-history":[{"count":0,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/2635\/revisions"}],"wp:attachment":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/media?parent=2635"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/categories?post=2635"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/tags?post=2635"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}