I Built an AI Agent with MCP and Python: Here’s How

Building AI agents used to be a messy, patchwork process. Not long ago, if I wanted an LLM to read a local file, query a database, or fetch live weather data, I had to write custom API wrappers for each integration. I also had to handle fragile JSON-RPC, manage each tool’s execution state by hand, and parse unpredictable model outputs, hoping they didn’t invent a parameter. Every new feature made my codebase more complicated. That all changed when the Model Context Protocol (MCP) arrived. In this article, I’ll show you how I built a reliable AI agent using MCP and Python.

My goal isn’t just to share code. I want to walk you through the design choices, the architecture, and the mindset changes that come with building agents the right way.

The Problem MCP Solves

You can think of the Model Context Protocol as the USB-C for AI models. Just as USB-C made it easier for hardware devices to connect, MCP makes it easier for AI models to connect to external data sources and tools.

Before MCP, every integration had to be custom-built. If you changed model providers, you usually had to rewrite your tool-calling code. MCP solves this by defining a universal client-server setup. You create an MCP server that shares your data and tools, and any MCP-compatible client—like Claude Desktop or your own Python script—can connect easily. This way, your application logic stays on the server, and the LLM client focuses on reasoning.

Here’s How I Built an AI Agent with MCP and Python

To build this agent for my client, I used only free and open-source tools. The main tool is FastMCP, a popular framework for building MCP applications in Python. FastMCP handles the protocol details, schema generation, validation, and connection management, so you can focus on writing regular Python functions.

Our agent’s architecture has three main parts:

  1. The Server: A standalone script that defines the tools our AI is allowed to use.
  2. The Transport: This is the communication layer. For local development, we use standard input and output (stdio), so the client starts the server as a background process and communicates with it directly.
  3. The Client: This is the agent loop. It takes a user’s prompt, asks the server which tools are available, sends those tools to an LLM, and manages the execution.

Step 1: Building the Server

When I first started building tools for LLMs, I spent hours manually writing large JSON schemas. FastMCP takes care of that for you. Here’s how I set up the server:

pip install fastmcp anthropic
from fastmcp import FastMCP

# 1. Create the server instance
mcp = FastMCP(name="My Agent Server")

# 2. Expose ordinary Python functions as tools
@mcp.tool
def calculate_shipping(weight: float, distance: float) -> float:
    """Calculates shipping cost based on weight (kg) and distance (km)."""
    base_rate = 5.0
    return base_rate + (weight * 0.5) + (distance * 0.1)

@mcp.tool
def get_customer_status(customer_id: str) -> str:
    """Fetches the current loyalty tier of a customer from the database."""
    # In reality, you would query a database here
    mock_db = {"CUST-01": "Gold", "CUST-02": "Silver"}
    return mock_db.get(customer_id, "Standard")

if __name__ == "__main__":
    mcp.run()

See the @mcp.tool decorator? That’s all you need. Here’s something I learned from experience: your type hints and docstrings aren’t just for developers anymore—they’re now the user interface for your AI.

FastMCP automatically reads your type hints (like weight: float) and your function’s docstring to create the JSON schema for the LLM. At first, I didn’t pay much attention to my docstrings, and my agent often made up inputs. When I started writing clear, detailed docstrings that explained what each tool did and what the parameters meant, the agent became much more accurate. If you’re building AI tools, treat your docstrings like specific prompts.

Step 2: Orchestrating the Agent Client

Now let’s talk about the core of the system. The client connects to the server, finds out which tools are available, and communicates with an LLM. I’m using Anthropic’s API here, but the main logic is the same for other providers:

import asyncio
from fastmcp import Client
from anthropic import AsyncAnthropic
import os

async def run_agent(user_prompt: str):
    # Connect to our local MCP server via stdio transport
    async with Client("my_mcp_server.py") as client:
        
        # 1. Ask the server what tools it has
        tools = await client.list_tools()
        
        # 2. Format the tools for the LLM
        formatted_tools = [
            {
                "name": tool.name,
                "description": tool.description,
                "input_schema": tool.input_schema
            } for tool in tools
        ]

        llm = AsyncAnthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
        
        print("Thinking...")
        
        # 3. Call the LLM with the available tools
        response = await llm.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=1024,
            tools=formatted_tools,
            messages=[{"role": "user", "content": user_prompt}]
        )

        # 4. Check if the LLM decided it needs to use a tool
        if response.stop_reason == "tool_use":
            for block in response.content:
                if block.type == "tool_use":
                    tool_name = block.name
                    tool_args = block.input
                    
                    print(f"Agent executing: {tool_name} with parameters {tool_args}")
                    
                    # 5. Tell the MCP server to actually run the Python code
                    result = await client.call_tool(tool_name, tool_args)
                    print(f"Result: {result}")

if __name__ == "__main__":
    asyncio.run(run_agent(
        "I need to ship a 15kg package over 200km. How much will it cost, and what is the status of customer CUST-01?"
    ))

One of the most important things to understand is that the LLM doesn’t run your code. It acts as a reasoning engine. It reads the prompt, decides it needs help, and then outputs a structured request like, “Please run calculate_shipping with weight=15 and distance=200.”

Your Python client script needs to catch that request, send the arguments to the MCP server using the call_tool() method, and get the answer back. The LLM is like the brain, while your Python script does the work.

This setup is based on the AI Agent I built for my client using MCP and Python. Here’s a beginner-friendly version you can try yourself.

Build Your Next AI Agent

If you want to keep building your AI agent skills, my book, Hands-on GenAI, LLMs and AI Agents, is a practical next step. It covers LLMs, RAG, AI agents, LangGraph, MCP, and hands-on projects to help you go from concepts to real-world AI applications.

If you like a more structured learning path, check out IBM’s RAG and Agentic AI Professional Certificate. It focuses on building AI agents, working with tools and LLMs, and developing practical agentic AI applications. It’s a great follow-up to this MCP and Python tutorial.

The Takeaway

In my years of mentoring, I’ve seen many learners get stuck when their AI projects move from simple experiments to production. They often struggle because they try to make the LLM do everything. The key to strong AI engineering is knowing what the model isn’t good at, such as math, logic, and state management, and letting traditional software handle those parts.

Understanding how a protocol like MCP standardizes communication between an LLM and external compute is far more valuable than memorizing the syntax of the latest trendy wrapper library. By separating your application logic (the server) from your AI reasoning (the client), you build systems that are testable, secure, and easy to upgrade.

I hope you enjoyed this article about building a robust AI agent with MCP and Python. If you’d like more tips on AI and machine learning, you can follow me on Instagram.

Aman Kharwal
Aman Kharwal

AI/ML Engineer | Published Author. My aim is to decode data science for the real world in the most simple words.

Articles: 2232

One comment

Leave a Reply

Discover more from AmanXai by Aman Kharwal

Subscribe now to keep reading and get access to the full archive.

Continue reading