Как написать свой MCP-сервер на Python и подключить к агенту
Пишем MCP-сервер на Python в 30 строк, проверяем без агента, подключаем к Claude Code и смотрим, как агент вызывает инструмент.
5 мин · · разработка · агенты
Чтобы написать свой MCP-сервер на Python, достаточно официального SDK и обычной функции с типами и docstring: описание инструмента библиотека построит сама. Дальше сервер подключается к агенту, например к Claude Code, и модель начинает вызывать вашу функцию, когда это нужно для задачи. Ниже сделаем рабочий пример с одним инструментом, проверим его без агента, зарегистрируем в Claude Code, который ходит через шлюз Zukko, и разберём, что делать, если сервер «не появляется».
Что мы строим
Инструмент find_todos: принимает каталог проекта и возвращает строки с комментариями TODO и FIXME вместе с файлом и номером строки. Для агента это удобный способ получить сводку долга по коду, не гоняя поиск по всему репозиторию вручную. Инструмент только читает файлы, ничего не меняет.
По документации MCP сервер предоставляет клиентам три вида возможностей: инструменты (их вызывает модель), ресурсы (данные, которые подкладывает приложение) и промпты (шаблоны, которые выбирает пользователь). Нам нужен первый вид.
Установка
В README SDK требуется Python 3.11 или новее. Установка вместе с командой mcp для разработки (первая строка для pip, вторая для проекта на uv):
pip install "mcp[cli]"
uv add "mcp[cli]"Добавка cli ставит утилиту mcp с подкомандами mcp dev, mcp run и mcp install.
Как написать свой MCP-сервер на Python: код
Файл server.py:
from pathlib import Path
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
mcp = MCPServer("todo-scanner")
SUFFIXES = {".py", ".js", ".ts", ".java"}
SKIP_DIRS = {".git", "node_modules", ".venv"}
@mcp.tool()
def find_todos(directory: str, limit: int = 50) -> list[str]:
"""Find TODO and FIXME comments in source files under a directory.Разберём, что тут важно.
- Схему писать не нужно. Имя инструмента берётся из имени функции, описание из docstring, схема аргументов из аннотаций типов. Поэтому docstring пишите для модели: по нему она решает, когда звать инструмент.
- Ошибка для модели.
ToolErrorвозвращает понятное сообщение, а не падение сервера. - Лимит. Параметр
limitзащищает контекст агента от огромного ответа. Об этом ещё скажем в расчёте. mcp.run()без аргументов запускает сервер по stdio, а защитаif __name__ == "__main__"нужна, чтобы импорт файла не стартовал сервер.- Объект сервера лежит в глобальной переменной
mcp: командаmcp runищет объект с именемmcp,serverилиapp.
В SDK версии 2 класс называется MCPServer, а импорт идёт из mcp.server. В предыдущей линии (1.x) тот же класс назывался FastMCP и импортировался из mcp.server.fastmcp; в документации миграции указано, что FastMCP переименован в MCPServer. Декораторы инструментов работают так же, но часть параметров конструктора и run() в версии 2 изменилась, поэтому при переносе старого кода сверьтесь с руководством по миграции. Проверьте версию через pip show mcp.
Проверяем без агента
Самый короткий путь: открыть сервер в MCP Inspector.
uv run mcp dev server.pyОткройте адрес, который напечатает команда. На вкладке инструментов будет find_todos с формой из двух полей; вызовите его на каталоге с кодом. Если форма появилась и ответ пришёл, сервер исправен.
Для автотестов SDK предлагает подключаться к серверу прямо в памяти, без процесса и порта:
import anyio
from mcp import Client
from server import mcp
async def main() -> None:
async with Client(mcp) as client:
result = await client.call_tool("find_todos", {"directory": ".", "limit": 5})
print(result.structured_content)
anyio.run(main)Подключаем к Claude Code
Хост запускает ваш файл как дочерний процесс, поэтому подключение сводится к одной команде запуска. В документации SDK для Claude Code приведена такая форма, где всё после -- является командой сервера:
claude mcp add todo-scanner -- uv run --with "mcp[cli]" mcp run /абсолютный/путь/server.pyПуть обязательно абсолютный: хост стартует сервер из своего рабочего каталога. Если uv не находится в PATH хоста, укажите полный путь к нему (which uv). Проверка: внутри сессии Claude Code команда /mcp показывает, что сервер подключён и какие инструменты он отдал. Из терминала то же покажут claude mcp list и claude mcp get todo-scanner.
Чтобы сам Claude Code работал через Zukko, задайте переменные (инструкция по Claude Code):
export ANTHROPIC_BASE_URL=https://api.zukko.pro
export ANTHROPIC_AUTH_TOKEN=fetch_ваш_ключ
export ANTHROPIC_MODEL=claude-sonnet-5-5Адрес без /v1, переменная именно ANTHROPIC_AUTH_TOKEN. Запустите claude в каталоге проекта и напишите: «Найди все TODO в текущем проекте и сгруппируй по файлам». В выводе вы увидите вызов инструмента find_todos; при первом использовании Claude Code может спросить разрешение. Подробнее про настройку проекта — в заметках о подключении Claude Code к проекту и MCP-серверах в Claude Code.
Вариант по HTTP
Если сервер нужен не только локально, SDK умеет работать по Streamable HTTP:
uv run mcp run server.py --transport streamable-httpСервер слушает порт (в примерах SDK это http://localhost:8000/mcp), а в Claude Code его добавляют командой claude mcp add --transport http todo-scanner http://localhost:8000/mcp. Для чего-либо за пределами вашей машины заранее продумайте авторизацию.
Что это даёт в расходах
Результат инструмента попадает в контекст и пересылается модели в следующих запросах. Допустим, ответ find_todos занимает 1 250 токенов и после него агент делает ещё 10 запросов. Расчёт для claude-sonnet-5-5 (цены на 18 октября 2026, $ за 1M токенов: вход 0.4, чтение кэша 0.05):
- без кэша: 12 500 × 0.4 / 1 000 000 = $0.005;
- с чтением из кэша: 12 500 × 0.05 / 1 000 000 = $0.000625.
Claude Code использует Anthropic-формат, где шлюз видит кэш и учитывает скидку отдельно. Но даже так большой вывод инструмента стоит денег на каждом следующем шаге, поэтому ограничивайте ответы (limit) и отдавайте главное. Список моделей и цены: GET https://api.zukko.pro/v1/models.
Если сервер не появился
- Запустите команду сервера вручную. Тишина и отсутствие трассировки означают, что всё в порядке: stdio-сервер ждёт хост.
- Проверьте абсолютные пути (к
server.pyи кuv). - Не пишите в stdout: на stdio это канал протокола. Для логов используйте модуль
logging. - Перезапустите сессию агента после изменения конфигурации.
- Посмотрите, как называется ваш объект. Если не
mcp,serverилиapp, укажите имя явно:mcp run server.py:имя.
Частые вопросы
Чем MCP-сервер отличается от вызова функций в API?
Function calling описывает функции в самом запросе, и код выполняет ваше приложение. MCP выносит инструменты в отдельный процесс со стандартным протоколом, и любой совместимый хост подключает их без доработок. Сравнение разобрано в отдельной заметке про function calling.
Нужен ли async?
Нет: функции могут быть обычными. Асинхронные нужны, если внутри вы делаете сетевые вызовы и хотите не блокировать сервер.
Как обезопасить сервер?
Делайте инструменты узкими и по возможности только на чтение, проверяйте аргументы, не давайте произвольный доступ к файловой системе и командам. Не кладите секреты в описание инструмента.
Работает ли это из России?
Для оплаты из России есть три способа: СБП, карты MasterCard и криптовалюта. Сам MCP-сервер работает локально и от этого не зависит.
Создайте ключ в кабинете, подключите Claude Code и попросите агента вызвать ваш инструмент.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- Промпт-инъекция: что это и как защитить бота и агентаОбъясняем, как работает промпт-инъекция через пользовательский ввод и чужие документы, и какие меры снижают ущерб: изоляция данных, права инструментов, лимиты ключа.
- Claude Code YOLO: режимы разрешений и работа без подтвержденийОтдельного режима YOLO в Claude Code нет, зато есть шесть режимов разрешений и гибкие правила. Разбираем, как перестать нажимать «Да» и не лишиться файлов.
- Claude Code: чек-лист лучших практик для ежедневной работыПривычки, которые делают работу с Claude Code предсказуемой: короткий CLAUDE.md, план перед правками, мелкие задачи, проверка результата и контроль расхода.
- MCP-сервер на Java: минимальный пример с одним инструментомПишем минимальный MCP-сервер на Java с одним инструментом, регистрируем его в Claude Code и учимся находить причину, если агент его не видит.