Головна / Статті / Протокол контексту моделей для початківців з FastMCP та Ollama

Протокол контексту моделей для початківців з FastMCP та Ollama

Дізнайтеся про ролі MCP — хост, клієнт, сервер, транспорт — а потім під’єднайте сервер інструменту для прогнозування погоди до локальної моделі qwen3:8b за допомогою FastMCP та STDIO.

1841 слів

Model Context Protocol, який зазвичай скорочують до MCP, — це спільна мова для підключення великих моделей мов до інструментів та джерел даних, до яких вони не можуть отримати доступ самостійно. Називання його протоколом підкреслює те, що він стандартизує формат спілкування; конкретні бібліотеки потім реалізують цей стандарт, щоб команди не мусили самостійно розробляти сокети та схеми повідомлень. FastMCP — це одна з таких реалізацій, яка використовується у наведеному нижче посібнику.

Супутній репозиторій: https://github.com/harshagangari747/MCPTutorial/tree/main

Попередні вимоги

Демонстрація залежить від трьох пакетів: fastmcp, ollama та langchain-community. Обробка даних відбувається за допомогою локальної моделі qwen3:8b. Запустіть її за допомогою:

ollama run qwen3:8b

Підготуйте папку проекту, яка вже містить порожні шаблони під назвами weather_server_mcp.py та app.py, щоб сервер та господар мали чіткі місця розташування.

Розуміння MCP

У самостійному режимі ШІ — це пристрій для перетворення токенів. Токени надходять; токени виходять. Він не звертається до API погоди, не відкриває баз даних та не читає системний годинник, якщо лише щось ззовні моделі не виконує ці дії. Провайдери хмарних послуг іноді додають до своїх API власні засоби для їх запуску, що зручно у продакшені, але ускладнює справу, коли метою є вивчення самого протоколу. Запуск локальної моделі через Ollama забезпечує автономність експерименту.

Спробуйте поставити запитання на кшталт „Яка погода сьогодні в Італії?“ Типова місцева відповідь починається з визнання того, що живий потік даних про погоду відсутній. Проте у цьому реченні містяться три підказки, які система повинна з’ясувати: погода як тема, „сьогодні“ як дата та Італія як місце. Моделі потрібен шлях для обчислення чи отримання даних про погоду, спосіб визначення „сьогодні“ та спосіб пов’язати цю погоду з Італією.

Очевидною проблемою є відсутність точного визначення дати. Ваги моделі не можуть надійно визначити поточну дату. MCP стає корисним, коли модель може пропонувати інструменти та аргументи, а середовище виконання фактично запускає ці інструменти, повертаючи актуальні дані, які модель може використати для формування відповіді.

Компоненти MCP

Практичне впровадження MCP зазвичай передбачає назву кількох взаємодіючих елементів:

  1. Робочий API — будь-який сервіс, який вже відповідає на запитання конкретної галузі, наприклад кінцева точка погоди, доступна в Інтернеті.
  2. Сервер MCP — процес, який приховує спосіб доступу до API чи бази даних та публікує інструменти, які можна викликати.
  3. Хост MCP — інтерфейс продукту, наприклад розумний планувальник поїздок, який поєднує логіку LLM із актуальними даними.
  4. Клієнт MCP — міст, розташований всередині хоста. Він повідомляє моделі, які інструменти доступні, перетворює наміри моделі на запити MCP та перетворює відповіді MCP у контекст, зрозумілий для моделі.
  5. Шар транспортування — JSON-RPC 2.0, який передається через HTTP/SSE, коли компоненти знаходяться на відстані, або через STDIO, коли модель та інструменти знаходяться на одній машині.
  6. LLM — тут qwen3:8b, який надається Ollama.
  • Harness — необов’язковий інструмент оркестрації, який об’єднує компоненти стека з меншою кількістю вручну написаних кодових елементів; у початковому описі як приклад наводиться Goose AI.
  • Після того, як ці ролі були названі, запит щодо погоди в Італії перетворюється на складну послідовність дій замість одного виклику моделі.

    Аналогія

    Приваблива метафора допомагає краще зрозуміти ролі кожного елемента. Намір керувати автомобілем — це головний додаток. Мозок відповідає ШІ: він аналізує ситуацію на дорозі та вирішує прискоритися, гальмувати чи змінити передачу, проте не може натиснути на педалі. Кінцівки відповідають серверу MCP; м’язи та кістки в кожній кінцівці є окремими інструментами — одна кінцівка керує рухом чи змінює передачу, інша — гальмує чи прискорює. Нервовий інтерфейс між мозком та м’язами — це клієнт MCP. Нерви, які передають електричні імпульси, виконують функцію транспорту. Автомобіль — це зовнішній API. Об’єднана структура кінцівок та м’язів — це система, яка забезпечує їхню взаємодію.

    Стисле зображення взаємозв’язків:

    • ШІ → мозок
    • Сервер MCP → кінцівка
    • Інструмент → дія м’яза
    • Головний додаток MCP → намір керування
    • Клієнт MCP → нервовий інтерфейс
    • Транспорт → нерви
    • Робочий API → автомобіль
    • Система кріплень → об’єднана структура тіла

    Цієї картинки достатньо, щоб сервер, клієнт та механізм передачі даних не злилися в один розпливчастий „плагін“.

    Функціонування MCP

    Реалізація відбувається з урахуванням певних ролей: створення сервера, хоста, моделі LLM, механізму передачі даних, за потреби — інструментарію та справжнього API чи сервісу. Сервер абстрагує API та надає інструменти. Кожен інструмент — це окрема дія, яку може звернути за допомогою модель; сама модель ніколи не виконує HTTP-запит. Клієнт одночасно публікує каталог та здійснює переклад у обох напрямках, щоб модель та сервер залишалися слабко пов’язаними.

    Якщо сервер пропонує функції get_todays_date() та get_weather_data(city, date), запит на кшталт „Яка погода сьогодні в Парижі?“ може розгортатися так:

    1. Модель усвідомлює, що їй потрібна дата сьогодні.
    2. Вона просить клієнта MCP використати функцію get_todays_date.
    3. Клієнт надсилає запит на сервер.
  • Сервер його виконує.
  • Клієнт переробляє відповідь сервера для моделі.
  • Маючи дату, моделі все одно потрібна інформація про погоду в Парижі.
  • Вона просить клієнта викликати функцію get_weather_data з назвою міста та датою.
  • Клієнт перетворює цю інтенцію на запит до сервера.
  • Сервер викликає API погоди та повертає необхідні дані.
  • Клієнт знову перетворює ці дані для моделі.
  • Модель подає остаточну відповідь користувачеві.
  • Історичні запитання, які потрапляють у період навчання, можна відповісти лише за допомогою пам’яті, але сенс MCP полягає у поточному контексті: датах та погоді, які змінюються після навчання.

    Проект

    Цей приклад робить опис погоди більш конкретним. Сервер MCP керує логікою взаємодії з зовнішнім API погоди. Додаток-хост створює клієнта MCP, реєструє сервер та здійснює запити до Ollama. Ізоляція доступу до LLM у власному помічнику забезпечує читабельність схеми передачі даних.

    Сервер 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()
    

    Функції, які взаємодіють з API, позначаються анотацією @server.tool(), що робить їх інструментами. Документація на початку кожної функції не є декорацією — вона пояснює моделі, коли слід використовувати цей інструмент. У прикладі надано два інструменти: один для отримання поточної погоди в місті, а інший — для отримання історичних даних про погоду в місті у певну минулу дату.

    MCP Host, Client, LLM, метод передачі

    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())
    

    Що відбувається?

    Необхідно визначити шлях до модуля сервера поруч із додатком-хостом:

    server_path = Path(__file__).parent / "weather_server_mcp.py"
    

    Створіть транспорт STDIO, який запустить цей модуль із поточним інтерпретатором Python:

      # The transport method here is STDIO
        transport = StdioTransport(
            command=sys.executable,
            args=[str(server_path)],
        )
    

    Інстанціюйте клієнта MCP з цього транспорту:

    mcp_client = Client(transport)
    

    Тепер у хоста є зареєстрований шлях сервера, обраний транспорт та клієнт. Під’єднайте модель через Ollama:

    llm = Ollama(model="qwen3:8b", temperature=0.5)
    

    Запитайте у клієнта каталог інструментів, опублікований файлом weather_server_mcp.py:

    mcp_tools = await mcp_client.list_tools()
    

    Передайте цей каталог у запит та накажіть моделі відповідати лише назвою інструменту та параметрами. Після обробки виконайте обраний інструмент:

    result = await mcp_client.call_tool(tool_name, params)
    

    Отже, основна структура навчального посібника полягає у: створенні сервера, його реєстрації, реєстрації клієнта, під’єднанні LLM та виборі транспорту. Інструменти для керування агентами можуть приховати більшу частину цих елементів; простий цикл дозволяє бачити кожен етап взаємодії під час навчання.

    У сукупності MCP — це радше розподіл обов’язків, ніж один виклик бібліотеки. Модель пропонує; клієнт перекладає; сервер діє; протокол передачі даних транспортує повідомлення JSON-RPC; хост керує циклом, орієнтованим на користувача. Як тільки ці межі стануть зрозумілими, заміна погоди на календарі, CRM-системи чи внутрішнє пошукове забезпечення полягатиме переважно у створенні нових інструментів та їх належному документуванні, щоб модель могла правильно вибрати. Коли цикл працює, стежте за тим, що модель виводить перед кожним викликом інструменту. Здоровий запис відображає назву інструменту, який дійсно існує, надання ключів аргументів, описаних у документації, та очікування повернення даних від клієнта перед формуванням речення для користувача. Якщо модель вигадує назву інструменту, уточніть запит чи покращіть описи інструментів. Якщо сервер викидає помилку, вона має бути відображена через клієнта, щоб модель могла спробувати знову чи вибачитися замість того, щоб створювати хибну інформацію.

    Отримання значень погоди. Ця дисципліна зворотного зв’язку має таке ж значення, як і початкове підключення.