Skip to main content
Glama
dsl-unibe-ch

mcp-tutorial

by dsl-unibe-ch

MCP Tutorial

This repository is a hands-on introduction to the Model Context Protocol (MCP). It contains a minimal MCP server that exposes two tools, and two interchangeable command-line clients that let a language model discover and call those tools in a live conversation.


What is MCP?

MCP is an open standard that defines how a language model client communicates with external tool servers. The client asks the server what tools are available, the server responds with a list of JSON-Schema-described functions, and the model can then decide to call them during a conversation. The transport used here is stdio: the client spawns the server as a subprocess and they talk over stdin/stdout using JSON-RPC messages.

This design keeps servers and clients fully decoupled. A server written in Python can be called by a client written in any language, and vice versa.


Related MCP server: MCP FastAPI Tutorial Server

Repository structure

mcp-tutorial/
  mcp_server.py                    # The MCP server - defines and exposes tools
  mcp_client_ollama.py             # Client using a local Ollama model
  mcp_client_openai_compatible.py  # Client using any OpenAI-compatible API
  requirements.txt                 # Python dependencies
  .env.example                     # Template for the required environment variables
  .env                             # Your local secrets (never committed, in .gitignore)

Prerequisites

  • Python 3.10 or newer

  • For the Ollama client: Ollama installed and running locally

  • For the OpenAI-compatible client: credentials for a compatible API (see the Configuration section below)


Getting started

1. Clone the repository

git clone <repository-url>
cd mcp-tutorial

2. Create a virtual environment

A virtual environment isolates the project dependencies from the rest of your system. This is strongly recommended and avoids conflicts with other Python projects on your machine.

python3 -m venv venv
source venv/bin/activate      # On Windows: venv\Scripts\activate

You will need to activate the virtual environment every time you open a new terminal session. When it is active you will see (venv) at the start of your prompt.

3. Install dependencies

pip install -r requirements.txt

Configuration

Ollama client

mcp_client_ollama.py does not require a configuration file. The model name is set as the OLLAMA_MODEL constant near the top of the script. Edit that line if you want to use a different locally available model.

Make sure Ollama is running before you start the client:

ollama serve              # start the Ollama daemon if it is not already running
ollama pull qwen3.5:9b    # download the model the first time. Or change the model name in the mcp_client_ollama.py script in line 18. the variable name is OLLAMA_MODEL

OpenAI-compatible client

mcp_client_openai_compatible.py reads its settings from a .env file so that secrets such as API keys are never hard-coded in source code and never accidentally committed to a repository.

Step 1 - Copy the example file:

cp .env.example .env

Step 2 - Open .env in a text editor and fill in the three variables.

The file looks like this:

OPENAI_API_KEY=your-key-or-token-here
API_BASE_URL=https://your-service.example.com/v1
MODEL_NAME=gpt-4o

Using real OpenAI:

  • Get your API key from https://platform.openai.com/api-keys (keys start with sk-)

  • Leave API_BASE_URL blank or remove the line entirely; the library defaults to https://api.openai.com/v1

  • Set MODEL_NAME to any model you have access to, for example gpt-4o

Using GPUStack or another self-hosted OpenAI-compatible service:

  • Set OPENAI_API_KEY to the access token generated by that service

  • Set API_BASE_URL to the service endpoint, for example https://gpustack.example.com/v1

  • Set MODEL_NAME to a model name that the service exposes

The .env file is listed in .gitignore and will never be committed to the repository. Your credentials stay on your machine only.


Running the clients

Both clients launch mcp_server.py automatically as a child process over stdio. You do not need to start the server separately.

Ollama client

python mcp_client_ollama.py

OpenAI-compatible client

python mcp_client_openai_compatible.py

Both clients open an interactive prompt. Type your message and press Enter. The model will reply, calling tools automatically when the question requires it. Type quit or exit to stop.

Example session:

You: what time is it in Tokyo?
[Client] Model requested 1 tool call(s).
  [Tool Execution] Calling 'get_current_time' with args: {'timezone': 'Asia/Tokyo'}
  [Tool Result] The current time is 2026-09-07 20:34:53. (Requested timezone: Asia/Tokyo)
[Client] Sending tool results back to the model...

Assistant: In Tokyo (Asia/Tokyo) the current time is 8:34 PM on September 7, 2026.

Adding more tools to the server

Open mcp_server.py. Every tool is a regular Python function decorated with @mcp.tool(). Adding a new tool is three steps:

Step 1 - Write the function with standard Python type hints on every parameter. The type hints are used to generate the JSON Schema that the model sees.

Step 2 - Write a docstring. The first line becomes the tool description that the model reads to decide when to call the tool. The Args block documents each parameter.

Step 3 - Apply the @mcp.tool() decorator.

Example - a tool that converts Celsius to Fahrenheit:

@mcp.tool()
def celsius_to_fahrenheit(celsius: float) -> float:
    """
    Convert a temperature from Celsius to Fahrenheit.

    Args:
        celsius (float): The temperature in degrees Celsius.
    """
    return (celsius * 9 / 5) + 32

That is all that is needed. The next time either client connects it will automatically discover and offer the new tool to the model.

A few things to keep in mind when writing tools:

  • The function name becomes the tool name the model calls. Use clear, descriptive names.

  • All parameters must have type annotations. Supported types include str, int, float, bool, and optional parameters with default values.

  • Tools can do anything: call external APIs, read files, run shell commands, query databases. The model only sees the name, description, and parameter schema - not the implementation.

  • Because the model cannot verify what a tool actually does, only expose tools from sources you trust. The commented-out example in mcp_server.py illustrates this risk: a tool named calculate_sum could silently delete a file.


How the tool-calling loop works

Understanding this flow helps when debugging:

  1. The client sends the conversation history and the list of available tools to the model.

  2. The model either responds with plain text (no tool needed) or with a tool_calls field naming which tool to call and with what arguments.

  3. The client executes the tool via the MCP session and captures the result.

  4. The client appends the tool result to the conversation history and sends everything back to the model.

  5. The model uses the result to compose a final human-readable answer.

Steps 3 to 5 repeat for each tool call. Some models request multiple tools in a single turn; both clients handle this by iterating over the tool_calls list.


Security note

MCP tool calls execute real code on your machine. Before connecting a client to any MCP server:

  • Read the tool implementations in the server source code.

  • Only use MCP servers from sources you trust.

  • Prefer running servers inside virtual environments or containers to limit their access to the rest of your system.

Related MCP Connectors

Related MCP Servers