Protokół kontekstu modelu dla początkujących z FastMCP i Ollama
Przyswoić sobie role MCP – host, klient, serwer, transport – a następnie połączyć serwer narzędzia pogodowego z lokalnym modelem qwen3:8b za pomocą FastMCP i STDIO.
Model Context Protocol, zwykle skracany do MCP, to wspólny język służący do łączenia dużych modeli językowych z narzędziami i źródłami danych, do których same nie mogą uzyskać dostępu. Określanie go jako protokół podkreśla, że standaryzuje on sposób prowadzenia rozmowy; konkretne biblioteki realizują ten standard, dzięki czemu zespoły nie muszą samodzielnie tworzyć mechanizmów komunikacji i schematów wiadomości. FastMCP to jedna z takich implementacji, wykorzystywana w poniższym przewodniku.
Repozytorium towarzyszące: https://github.com/harshagangari747/MCPTutorial/tree/main
Wymagania wstępne
Demo polega na użyciu trzech pakietów: fastmcp, ollama oraz langchain-community. Proces inferymentu odbywa się przy użyciu lokalnego modelu qwen3:8b. Uruchom go za pomocą:
ollama run qwen3:8b
Przygotuj folder projektu, który zawiera już puste pliki szablonowe o nazwach weather_server_mcp.py i app.py, aby serwer i aplikacja miały określone miejsca przechowywania.
Rozumienie MCP
Samodzielnie LLM jest jedynie konwerterem tokenów – tokeny wchodzą, tokeny wychodzą. Nie łączy się z API pogody, nie otwiera baz danych ani nie odczytuje zegara systemowego, chyba że coś poza modelem wykona te czynności. Dostawcy chmury czasami dodają do swoich API własne narzędzia do uruchamiania, co jest wygodne w środowisku produkcyjnym, ale utrudnia zrozumienie samego protokołu. Uruchamianie lokalnego modelu za pomocą Ollamy sprawia, że eksperyment pozostaje zamknięty w sobie.
Spróbuj zadać pytanie w stylu „jaka jest pogoda dzisiaj we Włoszech?”. Typowa lokalna odpowiedź zaczyna się od przyznania, że nie ma aktualnych danych pogodowych. Mimo to zdanie zawiera trzy wskazówki, które system musi rozszyfrować: pogodę jako temat, „dzisiaj” jako datę oraz Włochy jako miejsce. Model potrzebuje sposobu na obliczenie lub pobraanie danych pogodowych, metody określenia daty „dzisiaj” oraz sposobu powiązania tej pogody z Włochami.
Oczywistym brakiem jest możliwość określenia daty w kalendarzu. Wagi modelu nie potrafią pewnie określić bieżącej daty. MCP staje się przydatne, gdy model może proponować narzędzia i argumenty, a otaczający go silnik faktycznie uruchamia te narzędzia, zwracając aktualne dane, które model może wykorzystać do sformułowania odpowiedzi.
Komponenty w MCP
W praktyce implementacja MCP zazwyczaj obejmuje kilka współpracujących elementów:
- Aprawna API — każda usługa, która już odpowiada na pytania z danej dziedziny, np. punkt końcowy pogodowy dostępny w Internecie.
- Server MCP — proces, który ukrywa sposób dostępu do API lub bazy danych i udostępnia narzędzia, które można wywołać.
- Host MCP — interfejs produktu, na przykład inteligentny planer podróży łączący rozumowanie modeli językowych z danymi w czasie rzeczywistym.
- Klient MCP — mostek znajdujący się wewnątrz hosta. Informuje model o dostępnych narzędziach, przekształca intencje modelu w żądania MCP oraz odpowiedzi MCP w kontekst przyjazny dla modelu.
- Szyna transportowa — JSON-RPC 2.0, przekazywany albo przez HTTP/SSE, gdy komponenty są zdalne, albo przez STDIO, gdy model i narzędzia znajdują się na tej samej maszynie.
- LLM — tutaj
qwen3:8budostępniany przez Ollamę.
Gdy te role są już określone, pytanie dotyczące pogody we Włoszech staje się kwestią choreografii zamiast pojedynczego wywołania modelu.
Analogia
Metafaora kierowania utrzymuje te role w stałej relacji. Intencją kierowania jest aplikacja gospodarzowa. Mózg stanowi LLM: odczytuje kontekst drogowy i decyduje się na przyspieszenie, hamowanie lub zmianę biegu, ale nie może nacisnąć pedałów. Kończyny odpowiadają serwerowi MCP; mięśnie i kości w obrębie kończyny to poszczególne narzędzia – jedna kończyna kieruje lub zmienia bieg, druga hamuje lub przyspiesza. Interfejs nerwowy pomiędzy mózgiem a mięśniem to klient MCP. Nerwy przenoszące impulsy elektryczne stanowią system transportu. Samochód to zewnętrzna API. Złożone ciało to zestaw elementów, które umożliwiają współpracę poszczególnych części.
Zmapowanie w formie skróconej:
- LLM → mózg
- Server MCP → kończyna
- Narzędzie → ruch mięśnia
- Gospodarz MCP → intencja kierowania
- Klient MCP → interfejs nerwowy
- Transport → nerwy
- API robocze → samochód
- Zestaw elementów → struktura ciała
To zdjęcie wystarcza, by serwer, klient i mechanizm transportu nie zmieniły się w jeden niewyraźny „plugin”.
Funkcjonalność MCP
Implementacja opiera się na określonych rolach: uruchomienie serwera, hosta, modelu LLM, mechanizmu transportu, opcjonalnie narzędzia pomocniczych oraz prawdziwej API lub usługi. Serwer abstrahuje API i udostępnia narzędzia. Każde narzędzie to pojedyncza akcja, o którą może poprosić model; model nigdy sam nie wykonuje żadnego wywołania HTTP. Klient zarówno publikuje katalog dostępnych funkcji, jak i przetwarza dane w obu kierunkach, dzięki czemu model i serwer pozostają luźno połączone.
W przypadku serwera oferującego funkcje get_todays_date() oraz get_weather_data(city, date), zapytanie typu „Jaka jest dziś pogoda w Paryżu?” może przebiegać w następujący sposób:
- Model zauważa, że potrzebuje daty dzisiejszej.
- Pożąda od klienta MCP użycia funkcji
get_todays_date. - Klient przekazuje żądanie do serwera.
get_weather_data z podanym miastem i datą.Zadania historyczne, które mieścią się w oknie szkoleniowym, mogą być rozwiązane wyłącznie na podstawie pamięci, ale celem MCP jest aktualny kontekst: daty i warunki pogodowe, które zmieniają się po szkoleniu.
Projekt
Przykład sprawia, że opis pogody jest konkretny. Serwer MCP zawiera logikę komunikacji z zewnętrznym API pogody. Aplikacja host tworzy klienta MCP, rejestruje serwer i wysyła zapytania do Ollamy. Izolacja dostępu do LLM w osobnym narzędziu ułatwia zrozumienie struktury komunikacji.
Serwer MCP
# MCP Server
# weather_server_mcp.py
from fastmcp import FastMCP
import requests
# This is a server instance that we register in our host
server = FastMCP("weather-mcp-server")
# Third party api data
WEATHER_API_KEY = "api_key_here"
WEATHER_BASE_URL = "https://api.weatherapi.com/v1/"
# Tool 1
@server.tool()
def get_weather_data(city: str) -> float:
"""Get current temperature in Celsius"""
response = requests.get(
WEATHER_BASE_URL + "current.json",
params={"key": WEATHER_API_KEY, "q": city},
)
response.raise_for_status()
return response.json()["current"]["temp_c"]
# Tool 2
@server.tool()
def get_historical_weather_data(city: str, date: str) -> float:
"""Get max temperature for a historical date"""
response = requests.get(
WEATHER_BASE_URL + "history.json",
params={"key": WEATHER_API_KEY, "q": city, "dt": date},
)
response.raise_for_status()
return response.json()["forecast"]["forecastday"][0]["day"]["maxtemp_c"]
if __name__ == "__main__":
server.run()
Funkcje, które łączą się z API, są oznaczone tagiem @server.tool(), co umożliwia ich publikację jako narzędzi. Dokumentacja na początku każdej funkcji nie służy jedynie dekoracji – informuje model, kiedy należy użyć danego narzędzia. W przykładzie dostępne są dwa takie narzędzia: jedno pobiera aktualną pogodę dla danej miasta, a drugie – pogodę z przeszłości dla tej samej miasta w określonym dniu.
MCP Host, Client, LLM, metoda transportu
import asyncio
import sys
import json
from pathlib import Path
from langchain_community.llms import Ollama
from fastmcp import Client
from fastmcp.client.transports import StdioTransport
async def main():
# We mention the mcp server path.
server_path = Path(__file__).parent / "weather_server_mcp.py"
# The transport method here is STDIO
transport = StdioTransport(
command=sys.executable,
args=[str(server_path)],
)
# Register the MCP Client
mcp_client = Client(transport)
# LLM via Ollama
llm = Ollama(model="qwen3:8b", temperature=0.5)
async with mcp_client:
print("✓ Connected to MCP server!")
# We can now access that tools are present in the weather server mcp now.
mcp_tools = await mcp_client.list_tools()
tools_info = "\n".join([f"- {t.name}: {t.description or t.name}" for t in mcp_tools])
print(f"✓ Available tools:\n{tools_info}\n")
# Interactive loop
while True:
question = input("🌤️ Ask: ").strip()
if question.lower() == 'exit':
break
try:
# Step 1: Ask LLM to decide which tool to use
decision_prompt = f"""Given the question: "{question}"
Available tools:
{tools_info}
Respond with ONLY a JSON object (no other text):
{{"tool": "tool_name", "params": {{"city": "city_name"}}}}
For get_historical_weather_data, use: {{"tool": "get_historical_weather_data", "params": {{"city": "city_name", "date": "YYYY-MM-DD"}}}}"""
print(f"\n📍 Processing: {question}")
llm_response = llm.invoke(decision_prompt)
# Step 2: Parse JSON from LLM response
json_start = llm_response.find('{')
json_end = llm_response.rfind('}') + 1
if json_start == -1 or json_end == 0:
print("❌ LLM didn't return valid tool call")
continue
json_str = llm_response[json_start:json_end]
tool_call = json.loads(json_str)
print("Tool call: ", tool_call)
# Handle array responses
if isinstance(tool_call, list):
tool_call = tool_call[0]
tool_name = tool_call.get("tool")
params = tool_call.get("params", {})
print(f"🔧 Calling: {tool_name} with {params}")
# Step 3: Call MCP tool. This is where we actually call the tool.
result = await mcp_client.call_tool(tool_name, params)
answer = result.content[0].text
print(f"✓ Answer: {answer}°C\n")
except json.JSONDecodeError as e:
print(f"❌ JSON parsing error: {e}")
except Exception as e:
print(f"❌ Error: {e}\n")
if __name__ == "__main__":
asyncio.run(main())
Co się dzieje?
Należy ustalić ścieżkę modułu serwera obok aplikacji host:
server_path = Path(__file__).parent / "weather_server_mcp.py"
Stwórz transport STDIO, który uruchomi ten moduł za pomocą bieżącego interpretera Pythona:
# The transport method here is STDIO
transport = StdioTransport(
command=sys.executable,
args=[str(server_path)],
)
Zainstaluj klienta MCP z tego transportu:
mcp_client = Client(transport)
Host posiada teraz zarejestrowaną ścieżkę serwera, wybrany transport oraz klienta. Przyłącz model za pośrednictwem Ollamy:
llm = Ollama(model="qwen3:8b", temperature=0.5)
Zapytaj klienta o katalog narzędzi opublikowany przez plik weather_server_mcp.py:
mcp_tools = await mcp_client.list_tools()
P przekaż ten katalog do promptu i poinstruuj model, aby odpowiadał jedynie nazwą narzędzia oraz parametrami. Po przetworzeniu wykonaj wybrane narzędzie:
result = await mcp_client.call_tool(tool_name, params)
Podstawa tego przewodnika polega zatem na: stworzeniu serwera, jego zarejestrowaniu, zarejestrowaniu klienta, przyłączeniu modelu LLM oraz wyborze transportu. Narzędzia typu Agent mogą ukrywać większość tych elementów; prosty pętla umożliwia widzenie każdego kroku w protokole podczas nauki.
Łącznie rzecz biorąc, MCP to raczej podział zadań niż pojedyncze wezwanie biblioteki. Model proponuje; klient tłumaczy; serwer działa; mechanizm transmisji przekazuje wiadomości JSON-RPC; host zarządza pętlą skierowaną do użytkownika. Gdy te granice będą jasne, zamiana funkcji pogodowych na kalendarze, systemy CRM czy wewnętrzne narzędzia wyszukiwania sprowadza się głównie do napisania nowych narzędzi i ich dobrze udokumentowania, aby model mógł dokonać prawidłowego wyboru. Podczas działania pętli obserwuj, co model wysyła przed każdym wezwaniem narzędzia. Poprawny zapis pokazuje, że model podaje nazwę rzeczywiście istniejącego narzędzia, dostarcza klucze argumentów opisane w dokumentacji i czeka na dane od klienta przed sformułowaniem zdania skierowanego do użytkownika. Jeśli model wymyśla nazwę narzędzia, należy uprościć prompt lub poprawić opisy narzędzi. Jeśli serwer zwraca błąd, ten powinien zostać wyświetlony przez klienta, aby model mógł spróbować ponownie lub przeprosić zamiast tworzyć fałszywe informacje.
Uzyskiwanie wartości pogodowych. Ta dyscyplina w zakresie informacji zwrotnych ma takie samo znaczenie jak początkowe połączenia.Literatura pokrewna
- Jak protokół contextu modelu pozwala agentom SI odkrywać i korzystać z narzędzi — Jasne wyjaśnienie MCP: jak hosty, klienci i serwery umożliwiają aplikacjom SI odkrywanie narzędzi, korzystanie z nich przy użyciu strukturyzowanych danych oraz określenie ich ograniczeń.
- Protokół contextu modelu: Dlaczego zespoły nazywają MCP USB-C SI — MCP standaryzuje sposób, w jaki aplikacje SI łączą się z narzędziami, danymi i systemami — podobnie jak USB-C w integracjach — bez konieczności zastępowania modeli czy pomijania zasad zarządzania.