Кому подойдёт
Урок для разработчиков на Python, которым нужно подключить модель к своим базам и внутренним API, и для тех, кто хочет понимать устройство серверов MCP, прежде чем ставить чужие.
Что понадобится
Python 3.10 или новее, Node.js (инспектор запускается через npx), редактор и терминал; пакет mcp и инспектор бесплатны и ключей не требуют. Чтобы инструменты вызывала живая модель, нужен хост с платным доступом, а сервисы Anthropic из России открываются только через VPN.
Задача, ради которой появился протокол
До MCP каждая связка «модель плюс внешняя система» писалась заново: свой формат описания функций, свой способ вернуть результат, своя авторизация. Пять источников данных и три приложения — пятнадцать интеграций, и каждая ломается по-своему. Anthropic опубликовала MCP в конце 2024 года как открытую спецификацию против такого умножения; официальные SDK есть для Python, TypeScript, Java, Go и других языков.
Смысл — в разделении ответственности: кто владеет данными, описывает их один раз по общим правилам, а кто владеет моделью — один раз учится эти описания читать. Так же работает Language Server Protocol в редакторах кода. Ваш сервер одинаково подключается и к настольному приложению, и к агенту в терминале, и к своему скрипту.
MCP не заменяет ваш HTTP API и не делает модель умнее: он отвечает только за то, как модель узнаёт о возможностях и в каком виде получает результат. Есть библиотека для работы с базой — сервер будет тонкой обёрткой над ней.
Кто с кем говорит: хост, клиент, сервер
Ролей три. Хост — приложение, в котором живёт модель: настольный клиент, агент в терминале, ваш скрипт. Клиент — объект внутри хоста, держащий соединение ровно с одним сервером: серверов десять, значит и клиентов десять. Сервер — ваш процесс, отвечающий на «что ты умеешь» и «сделай вот это». Напрямую модель с сервером не говорит: между ними хост, он и спрашивает разрешение.
Разговор идёт сообщениями JSON-RPC 2.0: запрос с полем id, ответ с тем же id, уведомление без id. Соединение открывает рукопожатие: клиент шлёт initialize с версией протокола и своими возможностями, сервер отвечает своими, клиент подтверждает notifications/initialized. Дальше спрашивают списки: {"jsonrpc":"2.0","id":1,"method":"tools/list"}, так же resources/list и prompts/list. Изменился набор — сервер шлёт notifications/tools/list_changed.
Транспортов два. При stdio хост сам запускает ваш процесс и общается через стандартный ввод-вывод, отсюда правило: в stdout ничего, кроме протокольных сообщений. Streamable HTTP нужен, когда сервер живёт отдельно от пользователя: один endpoint, POST от клиента, поток событий в ответ. Отдельный SSE-канал из ранних редакций спецификации заменён на Streamable HTTP.
Три примитива: инструменты, ресурсы, промпты
Инструменты (tools) — действия. У каждого есть имя, описание и схема входа в JSON Schema; список забирают через tools/list, вызов делают через tools/call с полями name и arguments. Инициатор — модель: она читает описания и решает, что дёрнуть. Результат приходит блоками содержимого: текст, изображение, ссылка на ресурс. Ошибку отдавайте результатом с флагом isError — протокольную ошибку модель не увидит.
Ресурсы (resources) — данные для чтения по URI: file:///home/user/notes.md или своя схема orders://2026-08-21. Список даёт resources/list, шаблоны с параметрами в фигурных скобках — resources/templates/list, содержимое — resources/read с указанием mimeType. Ресурс выбирает приложение или человек, а не модель: типичный интерфейс — кнопка «прикрепить». Чтение не должно иметь побочных эффектов.
Промпты (prompts) — именованные заготовки диалога: prompts/list отдаёт список, prompts/get — сообщения с подставленными аргументами. Запускает их человек, обычно командой со слэшем. Здесь фиксируют отлаженную формулировку: «сверь сумму заказа с прайсом и верни таблицу расхождений».
Есть и обратное направление: сервер может попросить хост сходить к модели за коротким ответом (sampling), узнать разрешённые каталоги (roots) или спросить пользователя посреди выполнения (elicitation). Поддержка у клиентов разная — смотрите ответ на initialize.
Сервер на Python: минимальный рабочий каркас
Установка одна: pip install "mcp[cli]" в виртуальном окружении. Дальше файл server.py с объектом FastMCP: его имя пользователь увидит в списке подключений. Рукопожатие, маршрутизацию и сериализацию FastMCP берёт на себя.
Инструмент — функция под @mcp.tool(): имя функции становится именем инструмента, докстринг — описанием, аннотации типов — схемой входа. Лаконичность тут вредит: описание читает модель, и «ищет заказ по номеру вида SCG-12345, возвращает статус, сумму и дату оплаты» полезнее, чем «поиск заказа». Для сложных правил — Pydantic и Field(description=...).
Ресурс объявляется как @mcp.resource("orders://{date}"), параметры из URI приезжают аргументами; промпт — @mcp.prompt(). Запуск в конце файла: mcp.run() поднимает stdio, mcp.run(transport="streamable-http") — сетевой транспорт. Аргумент ctx: Context даёт ctx.info() и ctx.report_progress().
- pip install "mcp[cli]"
- from mcp.server.fastmcp import FastMCP
- mcp = FastMCP("orders")
- @mcp.tool() над def find_order(number: str) -> str: с докстрингом
- @mcp.resource("orders://{date}") над def orders_by_day(date: str)
- if __name__ == "__main__": mcp.run()
Проверка инспектором до того, как к серверу пустят модель
Отлаживать сервер сразу в чате — худший вариант: непонятно, кто ошибся, вы или модель. Инспектор поднимается командой mcp dev server.py или npx @modelcontextprotocol/inspector python server.py. Внутри — вкладки примитивов, форма для аргументов и журнал сообщений.
Главная ценность инспектора — сырые сообщения: initialize, ответ сервера, tools/list и каждый tools/call с аргументами и результатом. Если сервер не стартует, там же traceback, и причина скучная: не тот интерпретатор, зависимости в другом окружении, опечатка в пути.
- Рукопожатие прошло, сервер отвечает
- Схема как задумана: необязательный параметр не стал обязательным
- Корректные аргументы дают ожидаемый результат
- Мусор на входе даёт ошибку, а не роняет процесс
- Ресурс читается по URI, шаблон подставляет параметр
- Промпт разворачивается в осмысленные сообщения
Подключение к хосту и собственный клиент
Настольному клиенту сервер прописывают в claude_desktop_config.json (%APPDATA%\Claude на Windows, ~/Library/Application Support/Claude на macOS): объект mcpServers, внутри запись с command и args, секреты — блоком env. Пути указывайте абсолютные, python берите из своего окружения, иначе процесс не найдёт зависимости. После правки конфига приложение закрывают полностью; в терминальном агенте то же делает claude mcp add.
Свой клиент — несколько десятков строк: StdioServerParameters с командой запуска, stdio_client, ClientSession, затем await session.initialize(), list_tools() и call_tool("find_order", {"number": "SCG-12345"}). Так же работают read_resource и get_prompt.
Дальше клиент соединяют с моделью: список из list_tools переводится в описание инструментов вашего API почти один в один. Модель просит вызов — вы выполняете его через call_tool, отдаёте результат и повторяете цикл, пока она не закончит. Здесь начинаются расходы: токены тарифицируются, доступ из России требует VPN, сам сервер остаётся локальным и бесплатным.
- from mcp import ClientSession, StdioServerParameters
- from mcp.client.stdio import stdio_client
- await session.initialize()
- tools = await session.list_tools()
- result = await session.call_tool("find_order", {"number": "SCG-12345"})
Как выбрать примитив под задачу
Правило простое. Есть побочный эффект, параметры или поиск — инструмент. Нужно отдать данные, которые человек выберет сам, — ресурс. Хотите зафиксировать формулировку задачи целиком — промпт. Спорное решает вопрос: кто должен решать, что это вызывается прямо сейчас.
На каталоге договоров: список файлов и содержимое файла — ресурсы, договор выбирает юрист. Поиск с фильтрами по дате и контрагенту — инструмент, запрос формулирует модель. Отправка уведомления — инструмент с подтверждением на стороне хоста. «Сверь редакцию с шаблоном и выпиши отличия» — промпт.
Учтите ограничение: часть клиентов умеет только инструменты. Если сервер должен работать везде, продублируйте ключевые ресурсы инструментами list_contracts и read_contract.
Набор держите компактным: описания всех инструментов уходят в контекст модели на каждом шаге и сбивают выбор, когда имена близки по смыслу. Универсальный do_anything с полем action тоже плох — модель лишается подсказки в виде схемы.
Ошибки, которые встречаются чаще всего
Самая обидная — обычный print в stdio-сервере: stdout занят протоколом, посторонняя строка ломает разбор JSON, и соединение падает без объяснений. Логи пишите в stderr или через контекст сервера.
Вторая по частоте — плохие описания: модель выбирает инструмент по имени и докстрингу, больше у неё ничего нет. Название proc_data и три слова описания гарантируют, что вызовут не то и не там. Пишите, что функция делает и что вернёт.
Третья — объём ответа. Инструмент, вываливающий весь дамп таблицы, съедает контекст и деньги: добавьте limit и offset, отдавайте страницу или сводку вместо сырых строк.
И про безопасность: локальный сервер работает с вашими правами, а его ответ попадает в контекст модели, где могут оказаться строки под видом системных указаний. Ставьте серверы, авторам которых доверяете, и подтверждайте необратимые действия руками.
- Относительные пути и системный python в конфиге
- Забыли перезапустить хост после правки конфига
- Секреты в коде, а не в блоке env
Практика
- Создайте виртуальное окружение и установите пакет: pip install "mcp[cli]".
- Напишите server.py: объект FastMCP и инструмент под @mcp.tool() с аннотациями типов и честным докстрингом — поиск заказа в словаре-заглушке.
- Запустите mcp dev server.py и вызовите инструмент в инспекторе: с корректными аргументами, с пустой строкой, с числом вместо строки.
- Добавьте ресурс через @mcp.resource с параметром в URI и промпт через @mcp.prompt(), перечитайте списки и проверьте подстановку.
- Вставьте print("debug") в тело инструмента, посмотрите, как рвётся соединение, и замените вывод на логи в stderr.
- Пропишите сервер в claude_desktop_config.json с абсолютными путями, перезапустите приложение и дайте модели задачу под ваш инструмент.
- Напишите client.py: stdio_client, ClientSession, initialize, list_tools и call_tool — выведите список инструментов и результат вызова.
Проверьте себя
- Объясняю разницу между хостом, клиентом и сервером и называю оба транспорта
- Сервер проходит рукопожатие и отдаёт tools/list, вызов в инспекторе возвращает ожидаемый результат
- Понимаю, кто инициирует вызов инструмента, ресурса и промпта, и выбираю примитив под задачу
- Подключаю сервер к хосту через конфиг и нахожу по журналу причину, если он не поднялся
- Написал свой клиент и провёл цикл: список инструментов, вызов, возврат результата модели
- Знаю, почему вывод в stdout ломает stdio-сервер, и возвращаю ошибку так, чтобы её прочитала модель
Частые вопросы
Нужен ли платный доступ, чтобы попробовать MCP?
Чтобы написать сервер и прогнать его через инспектор — нет: пакет mcp и инспектор работают локально, без ключей и без оплаты. Деньги начинаются там, где подключается модель: подписка на приложение и обращения к API тарифицируются отдельно. Доступ к сервисам Anthropic из России требует VPN — и для приложений, и для API.
MCP работает только с Claude?
Нет, спецификация открытая, серверы подключают разные хосты, редакторы и агентские фреймворки. Различается не протокол, а глубина поддержки: где-то есть только инструменты, где-то ещё ресурсы, промпты и обратные вызовы. Что умеет конкретный клиент, видно в его ответе на initialize.
Что выбрать: stdio или HTTP?
Для инструмента, работающего с файлами и программами на машине пользователя, берите stdio: ни порта, ни авторизации, процесс живёт ровно столько, сколько открыт хост. Streamable HTTP нужен, когда сервер один на команду или ходит в закрытую сеть. Тогда закладывайте авторизацию и проверку заголовка Origin: открытый сетевой сервер — открытый доступ к вашим действиям.
Как проверить чужой сервер перед установкой?
Прочитайте код и список инструментов: что каждый делает с вашими данными и куда ходит по сети. Посмотрите, какие пути и переменные окружения сервер просит в конфиге — доступ к домашнему каталогу целиком нужен редко. Первый запуск делайте на тестовых данных, в отдельном окружении или контейнере.
Чем MCP отличается от вызова функций через API модели?
Вызов функций (tool use) — формат одного запроса: вы перечисляете инструменты в теле запроса и сами исполняете вызовы. MCP добавляет уровень выше: обнаружение возможностей, транспорт, единый способ отдавать данные и шаблоны сообщений. Разница в переносимости — один сервер подключается к разным приложениям без переписывания.
Чтобы пройти практику, нужен рабочий доступ
Подключим подписку на ваш аккаунт: оплата картой РФ, по СБП или криптой, пароль от аккаунта не нужен. Обычно за 15 минут в рабочее время.
Подключить Claude Pro — 2 490 ₽ Все уроки