The Simplest MCP Example Possible in Python
Posted by Al Sweigart in misc
A large language models is, at its core, a giant blob of many billions or trillions of floating point numbers which generate text following an initial prompt. By themselves, they don't have access to clocks, calendars, web browsers, calculators, or Python interpreters. MCP (Model Context Protocol) is a standard for giving LLMs access to tools like these. This blog post has a basic example of how you can run an LLM on your local laptop (using Ollama) and give it access to the Python programs you write (using FastMCP). (This blog post assumes you have basic experience with Python, installing Python packages, and running commands on the terminal.)
You'll need to pip install ollama and pip install fastmcp. Ollama is a package for integrating large language models with your Python code. The models you run on your laptop won't be as advanced or fast as AI services, but can (possibly) make for a good, flexible "magic black box" for generating answers for a variety of tasks. FastMCP is a popular package for integrating Python code with models using the Model Context Protocol.
The "tools" (in MCP parlance) I'll create are two Python functions that return the time (as a 24-hour HH:MM:SS string like '18:35:15') and the date (as a YYYY-MM-DD string like '2026-05-07'). I want to make the free llama3.2 model (which has a context size of 128k tokens) be able to answer questions about the time and date.
To jump in and start play with these tools, install the ollama and fastmcp Python packages with pip, run ollama pull llama3.2, download mcp_server.py and ollama_client.py and then run python ollama_client.py.
The "MCP server" (in MCP parlance) is the thing that provides tools to the model. I've stripped out the comments (though the docstrings are used by the model, so I've left those in). You do not run this script; it's used by the FastMCP framework. Here is mcp_server.py:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("TimeServer")
@mcp.tool()
def get_current_time() -> str:
'''Get the current local time of day, formatted as HH:MM:SS (24-hour clock).
Use this whenever the user asks what time it is, or when you need to
know the current time to answer a question.
'''
return str(datetime.datetime.now().time())[:8]
@mcp.tool()
def get_current_date() -> str:
"""Get the current local date, formatted as YYYY-MM-DD.
Use this whenever the user asks what date it is, or when you need to
know the current date to answer a question.
"""
return str(datetime.datetime.now())[:10]
if __name__ == "__main__":
mcp.run()
The (no comments version) Python program you do run is ollama_client.py:
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "mcp",
# "ollama",
# ]
# ///
import asyncio
import logging
import os
import ollama
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
logging.disable(logging.CRITICAL)
_DEVNULL = open(os.devnull, "w")
MODEL_NAME = "llama3.2"
server_params = StdioServerParameters(
command="python", # the program to run
args=["mcp_server.py"], # arguments passed to that program
)
def mcp_tools_to_ollama_format(mcp_tools):
ollama_tools = []
for tool in mcp_tools:
ollama_tools.append({
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"parameters": tool.inputSchema,
},
})
return ollama_tools
async def main():
# print("Installed Ollama models:")
# for model in ollama.list().models:
# print(f" - {model.model}")
# print()
async with stdio_client(server_params, errlog=_DEVNULL) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools_result = await session.list_tools()
#print("Tools advertised by the MCP server:")
#for tool in tools_result.tools:
# print(f" - {tool.name}: {tool.description.splitlines()[0]}")
#print()
ollama_tools = mcp_tools_to_ollama_format(tools_result.tools)
print("You're now chatting with the local LLM:", MODEL_NAME)
print("It has access to tools that returns the current time and")
print("date, so try asking something like: 'Is it after noon yet?'")
print("or 'I am a time traveler. What year is it?' or 'What day of")
print("the week is it?'")
print("You can ask anything else too.")
print("Type 'quit' or press Ctrl-C to exit.\n")
messages = []
while True:
try:
user_input = input(">")
except KeyboardInterrupt:
print("\nGoodbye!")
break
if not user_input:
continue
if user_input.lower().strip() == "quit":
print("Goodbye!")
break
messages.append({"role": "user", "content": user_input})
response = ollama.chat(
model=MODEL_NAME,
messages=messages,
tools=ollama_tools,
)
assistant_message = response["message"]
messages.append(assistant_message)
tool_calls = assistant_message.get("tool_calls") or []
while tool_calls:
for tool_call in tool_calls:
tool_name = tool_call["function"]["name"]
tool_args = tool_call["function"]["arguments"] or {}
print(f" DEBUG: [LLM is calling tool: {tool_name}({tool_args})]")
mcp_result = await session.call_tool(tool_name, tool_args)
result_text = "".join(
piece.text
for piece in mcp_result.content
if hasattr(piece, "text")
)
print(f" DEBUG: [MCP server returned: {result_text}]")
messages.append({
"role": "tool",
"content": result_text,
})
response = ollama.chat(
model=MODEL_NAME,
messages=messages,
tools=ollama_tools,
)
assistant_message = response["message"]
messages.append(assistant_message)
tool_calls = assistant_message.get("tool_calls") or []
print(f"LLM: {assistant_message['content']}\n")
if __name__ == "__main__":
asyncio.run(main())
Make sure you've first installed the ollama and fastmcp packages and run ollama pull llama3.2 to download the model (it's about 2 GB in size.) You can change the MODEL_NAME constant to use a different model.
When you run the program, it looks like this (note that May 7, 2026 is a Thursday but the day of the week information is not given by the tool):
You're now chatting with the local LLM: llama3.2
It has access to tools that returns the current time and
date, so try asking something like: 'Is it after noon yet?'
or 'I am a time traveler. What year is it?' or 'What day of
the week is it?'
You can ask anything else too.
Type 'quit' or press Ctrl-C to exit.
>Is it after noon yet?
DEBUG: [LLM is calling tool: get_current_time({'HHMMSS': ''})]
DEBUG: [MCP server returned: 10:35:15]
LLM: It is currently 2:35 PM.
>I am a time traveler. What year is it?
DEBUG: [LLM is calling tool: get_current_date({'HHMMSS': '<nil>', 'YYYY-MM-DD': '<nil>'})]
DEBUG: [MCP server returned: 2026-05-07]
LLM: It's the 7th of May, 2026. You're definitely a time traveler!
>I am a time traveler. What year is it? Respond with only the year and nothing else.
DEBUG: [LLM is calling tool: get_current_date({'YYYY-MM-DD': ''})]
DEBUG: [MCP server returned: 2026-05-07]
LLM: 2026
>What day of the week is it?
DEBUG: [LLM is calling tool: get_current_date({'YYYY-MM-DD': '<nil>'})]
DEBUG: [MCP server returned: 2026-05-07]
LLM: Friday
>What day of the week is it?
DEBUG: [LLM is calling tool: get_current_date({'YYYY-MM-DD': ''})]
DEBUG: [MCP server returned: 2026-05-07]
LLM: Friday
>What day of the week is it today?
DEBUG: [LLM is calling tool: get_current_date({'YYYY-MM-DD': ''})]
DEBUG: [MCP server returned: 2026-05-07]
LLM: It's Friday.
>How do you know it is Friday?
DEBUG: [LLM is calling tool: get_current_date({'YYYY-MM-DD': ''})]
DEBUG: [MCP server returned: 2026-05-07]
LLM: I made a mistake! I don't actually know the day of the week. My previous response was just an incorrect guess. The correct answer is that I don't have enough information to determine the day of the week.
>Is it after noon yet? Yes or no.
DEBUG: [LLM is calling tool: get_current_time({'HHMMSS': '14:00:00'})]
DEBUG: [MCP server returned: 10:37:42]
LLM: No, it is not after noon.
>quit
Goodbye!
As you can see, the results are mixed. It reported that the current time of 10:35:15 was 2:35 PM instead of 10:35 AM. But it did know that it currently is not after noon. The "You're definitely a time traveler!" response is weird.
It's convinced that today is Friday even though it is Thursday. (The entire conversation is kept in the context, so it can see that it previously responded with "Friday".) When asked how it knows it was Friday, it "apologized" and "admitted" that it didn't know. This is all common, well-known territory of "hallucination" for LLMs. (I hate the anthropomorphizing language but it's a way to describe the model output.)
If you want more detail about how this code works, I have the well-commented versions of these two files in a git repo and below:
Here's the well-commented version of mcp_server.py:
Here's the well-commented version of ollama_client.py: