Model Context Protocol Isn't Confusing If You Understand It This Way
Take a deep dive into how the Model Context Protocol (MCP) works and solidify your understanding by building an agentic system that uses it.
You must have heard about the Model Context Protocol, or MCP, by now if you’re active on any social media platform with tech influencers.
Yes, it might have been hyped a bit too much, but it's a good thing that you're aware of it, because MCP is not going away.
Instead, itself or improvements built upon it will be an irreplaceable part of the AI pipelines of the future.
Here is a lesson where we will discuss how MCP works and solidify our understanding by building an agentic system that uses it.
Let’s begin!
My latest book, called “LLMs In 100 Images”, is now out!
It is a collection of 100 easy-to-follow visuals that describe the most important concepts you need to master LLMs today.
Grab your copy today at a special early bird discount using this link.
Why Build Something Like MCP In The First Place?
Assume that it’s early 2024, and you’re building an application that uses LLMs for stock market analysis.
You would:
Write code specific to using different LLMs in the application
Write code specific to different databases if your data lives there
Define custom API endpoints for each financial data source (Yahoo Finance, Bloomberg, SEC filings, etc.)
Build custom data pre-processing pipelines
And so on!
Now that’s cumbersome!
A single change in any of these parts would force you to rewrite the code, making things difficult to scale.
Thanks to Anthropic open-sourcing MCP, building LLM-based apps post-November 2024 has become a lot easier.
Let’s learn how.
What’s MCP?
According to the official documentation:
Model Context Protocol (MCP) is an open protocol that standardises how applications provide context to LLMs.
Earlier, when we were using fragmented and unstable integrations to connect our LLMs to data sources, MCP replaces this with a single universal protocol, making these connections more reliable and our lives simpler.
Here is what Anthopic has to say about it.
Instead of maintaining separate connectors for each data source, developers can now build against a standard protocol.
Think of MCP like a USB-C port for AI applications.
Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools.
Put in a single line:
Model Context Protocol is a ‘Protocol’ that allows a ‘Model’ to get relevant ‘Context’.
Now that we understand the problems MCP solves, let’s learn about its components.
The Working Parts In The Machinery Of MCP
There are three main components of MCP:
Hosts
Servers
Clients
Let’s talk about them one by one.
MCP Host
These are the applications that users interact with.
For example, Claude Desktop, IDEs (such as Cursor and VS Code), or other AI-powered tools.
This is where an LLM lives.
MCP Server
These are small, focused programs that expose specific capabilities as per their use case.
These servers can securely connect to Resources via Tools that can be invoked by the LLM residing within the MCP host.
These resources could be:
local files/ services/ databases
web-based services such as databases, email, weather, calendar, etc. (via APIs)
The server also exposes Prompt templates that a client can use to get structured responses from the MCP server.
MCP Client
This is the component of the host that acts as a communication layer.
Each client maintains a dedicated connection to one MCP server, handling the protocol’s request-response patterns, handling errors, and managing the connection lifecycle.
Think of them as translators that speak both the host’s language and the MCP protocol.

How Do Clients Really Talk To Servers?
A Transport is a communication channel that handles the underlying mechanism of how information (messages) is exchanged between clients and servers.
There are three types of messages exchanged in MCP, and all of them are formatted in JSON-RPC 2.0.
These message types are:
Requests: Messages that ask for something, expecting a response back
In the example given below, the client requests that the server invoke the ‘weather’ tool for the query ‘San Francisco’ and expects a response.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "weather",
"arguments": {
"location": "San Francisco"
}
}
}
2. Responses: Messages that answer a previous request
In the example shown below, the server replies to the request with an ‘id’ of 1
with the weather data (‘temperature’ and ‘condition’) for the query ‘San Francisco'.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"temperature": "72°F",
"condition": "sunny"
}
}
3. Notifications: Messages that inform about something with no response expected
In the example shown below, the server sends a progress update message without expecting any reply (note that there is no ‘id’ field).
{
"jsonrpc": "2.0",
"method": "$/progress",
"params": {
"message": "Processing data...",
"progress": 0.8
}
}
There are two standard transport mechanisms that MCP uses to exchange these messages:
This mechanism allows communication through standard input and output streams on a computer.
It is a simpler mechanism that is best used for:
Local integrations (when the client and server are on the same machine)
Building command-line tools and working with shell scripts
This mechanism uses:
HTTP POST requests for client-to-server communication, and
optional Server-Sent Events (SSE) streams for server-to-client communication
It is best used for building web-based integrations that can also support multiple concurrent clients and resumable connections.
This is all the theory that we need to understand MCP for this lesson.
Let’s get hands-on writing some code!
Building A Physics QA Solving MCP-Based Agentic System
The number of MCP servers has exploded since its launch.
A comprehensive list of these servers can be found here:
GitHub - modelcontextprotocol/servers: Model Context Protocol Servers
Model Context Protocol Servers. Contribute to modelcontextprotocol/servers development by creating an account on…github.com
It is easy to integrate these servers with a host (such as Claude Desktop or an IDE) following the instructions associated with each server.
But since we are learning to build things from the basics, let’s implement an MCP server ourselves.
We will build a server that contains multiple tools for calculating solutions to physics problems.
Here are the steps to it.
1. Creating a new project using ‘uv’
We will be using ‘uv’ as our package manager in this tutorial.
If you’re new to it, please install it following the instructions on this page.
uv init physics-solver-mcp
cd physics-solver-mcp
uv venv .venv
source .venv/bin/activate
2. Installing Dependencies
We install the mcp
python package as follows:
uv add mcp crewai "crewai-tools[mcp]"
3. Setting up Environment Variables
We create a .env
file in the project folder, which contains our OpenAI API key.
This will be used when we call an agent based on the gpt-4o-mini
model.
OPENAI_API_KEY="YOUR_KEY_GOES_HERE"
4. Creating the MCP Server
We will use FastMCP, which is the standard framework for working with the Model Context Protocol in Python.
We create a file called physics_server.py
and write up some tools associated with the server, specifying each with the @mcp.tool()
decorator.
"""A Physics MCP server that implements the Model Context Protocol.
This server provides physics formulae as tools that can be discovered and used by MCP clients.
"""
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Physics-Server")
# Tool to calculate kinetic energy
@mcp.tool()
def kinetic_energy(mass: float, velocity: float) -> dict:
"""Calculate the kinetic energy of an object in motion.
Formula: KE = 1/2 × mass × velocity²
Args:
mass: Mass of the object in kilograms (kg). Must be positive.
velocity: Velocity of the object in meters per second (m/s). Can be positive or negative.
Returns:
Kinetic energy in Joules (J)
"""
if mass <= 0:
raise ValueError("Mass must be positive")
ke = 0.5 * mass * (velocity ** 2)
return ke
# Tool to calculate gravitational potential energy
@mcp.tool()
def gravitational_potential_energy(mass: float, height: float, g: float = 9.81) -> dict:
"""Calculate the gravitational potential energy of an object at a certain height.
Formula: PE = mass × gravitational_acceleration × height
Args:
mass: Mass of the object in kilograms (kg). Must be positive.
height: Height above reference point in meters (m). Must be non-negative.
g: Gravitational acceleration in m/s². Default is 9.81 (Earth's surface).
Returns:
Gravitational potential energy in Joules (J)
"""
if mass <= 0:
raise ValueError("Mass must be positive")
if height < 0:
raise ValueError("Height must be non-negative")
if g <= 0:
raise ValueError("Gravitational acceleration must be positive")
pe = mass * g * height
return pe
# Tool to subtract two numbers
@mcp.tool()
def subtract(a: float, b: float) -> dict:
"""Subtract two numbers.
Args:
a: First number.
b: Second number.
Returns:
Difference between a and b.
"""
return a - b
if __name__ == "__main__":
mcp.run(transport="stdio") # Use STDIO transport
5. Creating the MCP Client
Next, we will use the CrewAI framework to build an agentic system that will use our MCP server tools to solve a given physics problem.
If you’re new to CrewAI, consider checking out this tutorial on building your first AI agent using this framework.
The MCPServerAdapter
class from crewai-tools
is the primary way to connect to an MCP server and make its tools available to CrewAI agents.
Using a Python context manager (with
statement) is the recommended approach for this class as it automatically handles starting and stopping the connection to the MCP server.
from crewai import Agent, Task, Crew
from crewai_tools import MCPServerAdapter
from mcp import StdioServerParameters
import os
# Create a StdioServerParameters object for the physics server
server_params=StdioServerParameters(
command="python3",
args=["physics_server.py"],
env={"UV_PYTHON": "3.11", **os.environ},
)
# Use the StdioServerParameters object to create a MCPServerAdapter
with MCPServerAdapter(server_params) as tools:
print(f"Available physics tools: {[tool.name for tool in tools]}")
agent = Agent(
role="Physics Expert",
goal="Solve physics problems using fundamental energy calculations.",
backstory="An experienced physicist with deep knowledge of classical mechanics and energy principles. Can apply kinetic and potential energy concepts to solve practical problems.",
tools=tools,
verbose=True,
)
task = Task(
description="Solve this physics problem: {physics_problem}",
expected_output="A detailed step-by-step solution showing all calculations, intermediate values, and final answers with proper units. Use the available physics tools to perform kinetic energy and potential energy calculations.",
agent=agent,
)
crew = Crew(
agents=[agent],
tasks=[task],
verbose=True,
)
# Physics problem
crew_inputs = {
"physics_problem" : """
A roller coaster car with a mass of 800 kg starts from rest at the top of a hill that is 50 meters high.
The car then descends the hill and reaches a velocity of 25 m/s at the bottom.
Given:
- Mass of the car: 800 kg
- Initial height: 50 m
- Final velocity: 25 m/s
- Gravitational acceleration: 9.81 m/s²
Questions:
1. Calculate the initial gravitational potential energy of the car at the top of the hill.
2. Calculate the final kinetic energy of the car at the bottom of the hill.
3. Compare the initial potential energy with the final kinetic energy and explain any differences.
4. If the car were to climb another hill, what maximum height could it reach if all its kinetic energy were converted back to potential energy?
"""
}
result = crew.kickoff(inputs=crew_inputs)
print(result)
We run the MCP Client as follows.
uv run client.py
Here is the answer that we get, and it is correct!
1. Initial Gravitational Potential Energy: 392400 J
2. Final Kinetic Energy: 250000 J
3. The initial potential energy is greater than the final kinetic energy due to energy losses from friction and air resistance.
4. Maximum Height: 31.87 m
The logs tell us that our agent used these MCP server tools to successfully perform its operations.
That’s everything for this lesson on MCP.
Have you been using it in your applications? Please share your experience with me in the comments below.
Further Reading
Source Of Images
All images used in the article are created by the author unless stated otherwise.
Why can't you use Claude on the browser ? You are using some sort of terminal based app . What is that ? Why do you need it ? How do you install and configure it ? Do you have a book or articles that go from zero to installing all these tools you use otherwise it'd totally confusing what you are doing.