A complete learning project implementing Model Context Protocol (MCP) in two ways:
- MCP From Scratch
- MCP Using Python SDK (FastMCP)
The goal of this project is to understand how modern AI agents connect LLMs with external tools using MCP.
MCP
├── MCP SERVER + CLIENT FROM SCRATCH
│
│ ├── MCP Server
│ │
│ │ ├── main.py
│ │ ├── router.py
│ │ ├── transport.py
│ │ ├── protocol.py
│ │ ├── models.py
│ │ ├── registry.py
│ │ │
│ │ └── tools
│ │ ├── calculator.py
│ │ ├── weather.py
│ │ └── joke.py
│ │
│ └── MCP Client
│ ├── main.py
│ ├── agent.py
│ ├── mcp_client.py
│ ├── ollama_client.py
│ ├── parser.py
│ └── prompts.py
│
└── MCP USING SDK
│
├── chat.py
├── mcp_config.json
│
├── servers
│ ├── calculator.py
│ └── weather.py
│
└── data
Model Context Protocol (MCP) is a standard protocol that allows AI models to communicate with external tools, APIs, databases, and data sources.
Without MCP:
LLM
|
+---- Weather API
|
+---- Database
|
+---- Filesystem
|
+---- Custom APIs
With MCP:
LLM
|
MCP Client
|
MCP Protocol
|
MCP Servers
|
---------------------
| | |
v v v
Weather Database Filesystem
The LLM only understands available tools and schemas.
The MCP Client manages communication with MCP servers.
This implementation recreates MCP internally without using any MCP SDK.
Implemented:
- Custom MCP Server
- Custom MCP Client
- JSON-RPC communication
- Tool registry
- Tool discovery
- Tool execution
- Ollama integration
- Agent loop
User
|
v
Agent Runtime
|
-------------------------
| |
v v
Ollama Gemma3 MCP Client
|
JSON-RPC over STDIO
|
v
MCP Server
|
--------------------------------------
| | |
v v v
Calculator Weather Joke
Responsibilities:
- Register tools
- Expose tools
- Receive requests
- Execute tools
- Return responses
The server does not know anything about the LLM.
It only provides capabilities.
Example initialize request:
{
"jsonrpc":"2.0",
"id":1,
"method":"initialize",
"params":{}
}Response:
{
"jsonrpc":"2.0",
"id":1,
"result":{
"protocolVersion":"0.1",
"serverInfo":{
"name":"Scratch MCP",
"version":"1.0"
}
}
}Returns available tools.
Example:
{
"jsonrpc":"2.0",
"method":"tools/list"
}Executes a tool.
Example:
{
"jsonrpc":"2.0",
"method":"tools/call",
"params":{
"name":"calculator",
"arguments":{
"operation":"multiply",
"operands":[10,20]
}
}
}Every tool follows a common structure:
class BaseTool:
name = ""
description = ""
input_schema = {}
def execute(self, arguments):
raise NotImplementedErrorSupports:
add
subtract
multiply
divide
Example:
User:
Calculate 20 multiplied by 30
LLM generates:
{
"tool":"calculator",
"arguments":{
"operation":"multiply",
"operands":[20,30]
}
}Uses external weather APIs.
Example:
{
"tool":"weather",
"arguments":{
"city":"Kathmandu"
}
}Returns random jokes.
Example:
{
"tool":"joke",
"arguments":{}
}Responsibilities:
- Start MCP servers
- Send JSON-RPC requests
- Receive responses
- Execute tools
- Connect LLM decisions with tools
User Question
|
v
LLM
|
Need Tool?
/ \
Yes No
| |
Tool Call Normal Answer
|
MCP Client
|
MCP Server
|
Tool Execution
|
Tool Result
|
Final Answer
This implementation uses the official MCP Python SDK.
Features:
- FastMCP
- Custom MCP servers
- Official MCP servers
- Ollama Agent
- Tool discovery
User
|
v
chat.py
MCP Client
|
Tool Discovery
-------------------------
| |
v v
Custom MCP Servers Official MCP Servers
Calculator Filesystem
Weather Fetch
SQLite
-------------------------
|
v
Ollama LLM
Tools:
add()
multiply()Uses Open-Meteo API.
Tool:
weather(city)Capabilities:
read_file()
write_file()
edit_file()
create_directory()
list_directory()
search_files()
Used for fetching external resources.
Example:
Summarize webpage
Capabilities:
Create tables
Execute queries
Read database data
Create environment:
python -m venv .venvActivate:
Windows:
.venv\Scripts\activateLinux:
source .venv/bin/activateInstall dependencies:
pip install mcp requestsInstall Ollama:
https://ollama.com
Pull model:
ollama pull llama3.1Run:
ollama servepython chat.pyWrong:
Server started
Waiting for request
{
json response
}
Correct:
{
"jsonrpc":"2.0"
}Logs should go to stderr.
Problem:
Client and server used different Python interpreters.
Solution:
sys.executableExample:
subprocess.Popen(
[
sys.executable,
"main.py"
]
)Problem:
Waiting for response...
Solution:
print(
json.dumps(response),
flush=True
)The LLM depends heavily on tool descriptions.
Bad:
calculator
Good:
{
"name":"calculator",
"description":"Performs arithmetic operations",
"inputSchema":{
}
}- Python
- JSON-RPC
- Ollama
- Gemma3
- Llama3.1
- MCP Python SDK
- FastMCP
- STDIO Communication
- Multiple MCP servers
- Authentication
- Streaming responses
- Memory MCP
- RAG MCP
- Vector Database MCP
- Browser Automation MCP
- Multi-Agent workflow
- A2A protocol integration
After completing this project:
You understand:
- MCP internals
- Client/server architecture
- Tool discovery
- Tool schemas
- LLM tool calling
- Agent execution loops
- Official MCP ecosystem
This project recreates the foundation behind:
- Claude MCP integrations
- Cursor AI tools
- AI coding assistants
- Modern agent frameworks
MCP Documentation:
https://modelcontextprotocol.io
MCP Python SDK:
https://github.com/modelcontextprotocol/python-sdk
Ollama:
Built as a learning project to understand MCP internals and LLM-powered agent architecture.