Усі уроки · 44
Шлях 3 · Дорожня карта AI-інженера·Урок 25 з 33

Створіть свій перший MCP-сервер

Покроковий MCP-сервер на Python з офіційним SDK: інструменти, ресурси, промпти, транспорт stdio та підключення до клієнта.

РівеньСереднійЧас~20 хв

Спершу вирішіть, що надавати

MCP-сервер може пропонувати три види можливостей, і цей вибір важливіший за код:

  • Інструменти (tools) — дії, які модель сама вирішує викликати: шукати, записувати, надсилати, створювати. Використовуйте їх для всього, що має побічні ефекти або потребує обчислень.
  • Ресурси (resources) — дані, які застосунок читає й підставляє в контекст: конфігурації, схеми, документи. Використовуйте їх для довідкових матеріалів.
  • Промпти (prompts) — готові шаблони, які постачає сервер; корисні, коли ваша команда має стандартний спосіб щось робити (рев’ю коду, розбір інциденту).

Хороший перший сервер робить одну невелику річ добре. Ми побудуємо сервер нотаток із двома інструментами: зберегти нотатку й показати список нотаток.

«Сервер» тут — не стійка в дата-центрі. Це невелика програма, яка тихо сидить, відповідає на запитання на кшталт «які у вас є інструменти?» та «запустіть цей інструмент із такими аргументами» і віддає відповідь. Ось і все.

Щоб повторювати за уроком, потрібні три речі: Python 3.10 або новіший, термінал і одна команда встановлення.

Скільки зусиль це забере. Код нижче займає близько сорока рядків, і запустити його можна за десять хвилин. Але на перший сервер усе одно заплануйте годину. Ось на що вона йде: налаштувати конфігураційний файл клієнта так, щоб він вказував на правильний абсолютний шлях; перезапустити застосунок, щоб він помітив зміну; навчитися налагоджувати програму, вивід якої ви не бачите. Причина в тому, що print stdio-сервера потрапляє прямо в потік протоколу й ламає його. Код пишеться легко, а труднощі починаються з підключення. Якщо ваш перший сервер не з’являється в клієнті, це звичайна справа.

Мінімальний сервер

Офіційний Python SDK (pip install "mcp[cli]") дає вам FastMCP, де інструмент — це просто функція Python із декоратором. Анотації типів стають JSON Schema, а докстрінг — описом, який читає модель:

сервер нотаток + конфігурація клієнта
1# Одноразове налаштування, виконайте в терміналі:
2# pip install "mcp[cli]"
3# Це встановлює офіційний Python SDK для MCP.
4 
5# FastMCP — простий спосіб написати сервер: ви пишете звичайні функції
6# Python, а він перетворює їх на інструменти MCP.
7from mcp.server.fastmcp import FastMCP
8 
9# У кожного сервера є ім’я. Клієнт показує його користувачеві.
10mcp = FastMCP(#98c379">"notes")
11 
12# Наша «база даних» — просто словник Python: заголовок нотатки -> текст нотатки.
13# Він живе в пам’яті, тому нотатки зникають, коли сервер зупиняється.
14_notes: dict[str, str] = {}
15 
16 
17# @mcp.tool() реєструє цю функцію як інструмент, який може викликати модель.
18# Докстрінг нижче читає МОДЕЛЬ — пишіть його для моделі,
19# а не для рецензента-людини.
20# Анотації типів (title: str, body: str) стають JSON Schema, за якою
21# модель будує правильний виклик.
22@mcp.tool()
23def save_note(title: str, body: str) -> str:
24 #98c379">"""Save a note under the given title. Overwrites if the title exists."""
25 _notes[title] = body
26 # Усе, що ви повернете, — єдине, що отримає модель.
27 # Зрозуміле повідомлення краще за «сирий» дамп даних.
28 return #98c379">"Saved: " + title
29 
30 
31@mcp.tool()
32def list_notes() -> str:
33 #98c379">"""List all saved note titles."""
34 if not _notes:
35 # Корисне повідомлення про помилку дає змогу моделі виправитися самій.
36 return #98c379">"No notes yet."
37 return "\n".join(sorted(_notes))
38 
39 
40# Ресурс — це довідковий матеріал, який ЗАСТОСУНОК може прочитати в контекст:
41# викликати його вирішує не модель, а застосунок.
42@mcp.resource(#98c379">"notes://help")
43def help_text() -> str:
44 #98c379">"""Short guide to the notes server."""
45 return #98c379">"Ask the model to save or list notes by title."
46 
47 
48# Транспорт stdio: клієнт сам запускає цей скрипт і спілкується з ним
49# через стандартний ввід і вивід. Мережеві порти ніде не відкриваються.
50if __name__ == #98c379">"__main__":
51 mcp.run(transport=#98c379">"stdio")

Три речі, на які варто звернути увагу:

  • Докстрінг — це інтерфейс. Модель ніколи не бачить ваш код — лише ім’я функції, анотації типів і докстрінг. Пишіть докстрінг для моделі.
  • Анотації типів задають схему виклику. title: str, body: str стає JSON Schema, за якою модель будує правильний виклик інструмента.
  • Транспорт stdio означає, що клієнт запускає ваш скрипт і спілкується з ним через стандартний ввід і вивід. Ніщо не слухає мережевий порт.

Перевірте, перш ніж чіпати клієнт

Не пропускайте цей крок. Він відділяє «сервер зламаний» від «клієнт не знаходить мій файл» — а без нього ці дві ситуації виглядають однаково. У SDK є налагоджувач, який запускає ваш сервер і дає змогу викликати інструменти вручну в браузері:

Запустіть сервер у MCP Inspector
# встановіть офіційний SDK (один раз)
pip install "mcp[cli]"

# запустіть сервер під Inspector, у браузері
mcp dev server.py

# ...або викличте його прямо з терміналу, без жодного клієнта
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | python server.py

# Якщо ви бачите тут список зі своїх двох інструментів, сервер працює.
# Якщо ні, помилка в коді, а не в конфігурації клієнта.

Дві речі, які ламають кожен перший сервер, і жодна не очевидна:

  • Налагодження через print усе ламає. За транспорту stdio print() пише в той самий потік, який використовує протокол, тож випадковий print псує розмову. Замість цього пишіть логи у файл (logging із FileHandler) або в stderr.
  • Відносні шляхи не працюють. Клієнт запускає ваш скрипт із довільного робочого каталогу. Використовуйте в конфігурації абсолютний шлях, а шляхи до файлів будуйте відносно __file__, а не поточного каталогу.

Зареєструйте його в клієнті

Конфігураційний файл вище — для Claude Desktop (Settings, потім Developer, потім Edit Config). command разом з args кажуть: запусти цей скрипт як локальний процес і підключися до нього через stdio. Після перезапуску застосунку обидва інструменти автоматично з’являються в контексті моделі — попросіть її «зберегти нотатку з назвою groceries: молоко та хліб» і подивіться, як відбувається виклик інструмента.

Cursor, VS Code (агентний режим Copilot), Zed і Claude Code використовують схожу структуру JSON або еквівалентну команду claude mcp add. У цьому й сенс протоколу: той самий сервер працює скрізь. Але гладко буває не завжди: клієнти відрізняються тим, де лежить конфігураційний файл, чи потрібен повний перезапуск і наскільки голосно вони повідомляють, що сервер не запустився (часто — узагалі ніяк). Спершу зазирніть у власну документацію клієнта з MCP, а потім повертайтеся сюди за розбором серверної частини.

Локально чи віддалено

Поки що сервер працює на вашій машині й запускається клієнтом (stdio). Для команди його розміщують віддалено, через HTTP:

{
  "mcpServers": {
    "notes": {
      "url": "https://notes.example.com/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}

Якщо в конфігурації вказано URL, клієнт підключається через Streamable HTTP, а не запускає процес. Обсяг роботи при цьому зростає стрибком. Віддалений сервер — це публічна точка доступу, а отже, вам знадобляться повноцінна автентифікація (у специфікації для цього передбачено OAuth), TLS, обмеження частоти запитів, логування, керування секретами й хтось, хто помітить, що сервер упав. Цей перелік не коротший, ніж у будь-якого API в реальній експлуатації. Практичне правило: поки розробляєте, починайте зі stdio, переходьте на HTTP, коли сервер потрібен більш ніж одній людині чи сервісу, і вважайте цей перехід окремим проєктом.

Найважливіші практики

  • Чіткі описи інструментів. Скажіть, що робить інструмент, коли його використовувати і коли не використовувати. «Зберігає нотатку. Використовуйте для тексту, створеного користувачем; не використовуйте для фрагментів коду» краще, ніж «зберігає дані».
  • Невеликі набори інструментів. Схема кожного інструмента займає місце в контексті, а надто багато схожих інструментів збиває модель з пантелику. Десять цілеспрямованих інструментів кращі за сорок, що перетинаються.
  • Корисні повідомлення про помилки. Коли виклик не вдався, поверніть повідомлення, з якого модель зрозуміє, що робити далі: «Нотатку ‘groceries’ не знайдено. Доступні: milk-list, ideas», а не «сире» трасування стека. Зі зрозумілим повідомленням про помилку модель дає собі раду без допомоги людини.
  • Повертайте структуровані, компактні результати. Обріжте дані до того, що потрібно моделі; величезні відповіді спалюють контекстне вікно.
  • Робіть інструменти безпечними за замовчуванням. Підтверджуйте руйнівні операції, обмежуйте права облікових даних і ніколи не дозволяйте інструментові робити більше, ніж обіцяно в його описі.

Перевірте себе

Перевірте себе

Що робить докстрінг функції-інструмента в MCP-сервері?

Що на практиці означає транспорт stdio?

Ви хочете надати довідковий матеріал, який застосунок читає в контекст, а не те, що модель вирішує викликати. Яку можливість використати?

Куди йти далі

Тепер ви вмієте створювати, підключати й доводити до надійного стану MCP-сервер — затребувана навичка, адже команди вбудовують MCP у все підряд. Якщо ви пропустили теорію, урок MCP: USB-порт для ШІ пояснює три ролі й шлях запиту, а Інструменти та виклик функцій розкриває механізм, на якому побудований MCP.