Как создать серверы MCP с помощью FastMCP (с реальным инструментом на основе обхода)
TL;DR
FastMCP — самый быстрый способ превратить функцию Python в инструмент MCP. Один единственный декоратор @mcp.tool на типизированной функции генерирует JSON-схему, необходимую клиенту MCP, без ручной обработки протоколов.
Установите одной командой: pip install fastmcp. Этот учебник установил и проверил FastMCP 3.4.7 напрямую из PyPI.
Минимальному серверу нужно всего три строки настоящего кода. Создайте экземпляр FastMCP, декорируйте функцию с помощью @mcp.tool и вызовите mcp.run().
Серверы FastMCP можно тестировать без отдельного клиентского процесса. Класс fastmcp.Client может напрямую подключаться к объекту сервера в том же процессе Python, что этот учебник использовал для проверки того, что каждый пример действительно работает.
Инструмент, который только складывает два числа, не оправдывает создание сервера. Пример, приведенный в этом учебнике, соединяет инструмент FastMCP с Nstproxy Crawl, так что клиент MCP может передать URL и получить обратно очищенный Markdown.
Вызов реального внешнего API из инструмента означает обработку реальных режимов отказа. Пропущенные учетные данные, ответы не 200 и сетевые ошибки требуют явной обработки — этот учебник показывает реальный вывод ошибок, зафиксированных, когда API-ключ не настроен.
FastMCP является надмножеством официального MCP Python SDK, а не конкурентом ему. FastMCP 1.0 был объединен с официальным SDK; активно разрабатываемый пакет fastmcp на PyPI — это FastMCP 2.x, который добавляет слой опыта разработчика, на который полагается этот учебник.
Попробуйте Nstproxy - Начните бесплатный тест сегодня
Введение: почему FastMCP — это практическая точка входа в серверы MCP
FastMCP превращает типизированную функцию Python в инструмент, который может вызывать агент ИИ, не требуя от вас ручной записи обработки сообщений JSON-RPC. Протокол контекста модели (MCP) определяет, как приложение ИИ — "клиент MCP", такой как Claude Desktop, помощник IDE или пользовательский агент — обнаруживает и вызывает инструменты, ресурсы и подсказки, представленные отдельным процессом "сервера MCP". Реализация этого протокола вручную означает написание генерации схемы, маршрутизации сообщений и транспортной механики, прежде чем один единственный инструмент действительно начнёт что-либо полезное.
FastMCP устраняет эти сложности. Вы пишете обычную функцию Python, добавляете аннотации типов, декорируете её с помощью @mcp.tool, и FastMCP генерирует схему инструмента, обрабатывает цикл сообщений JSON-RPC и предоставляет его через любой транспорт на ваш выбор. Официальная документация по протоколу модели контекста описывает MCP как "опенсорсный стандарт для подключения приложений ИИ к внешним системам" — FastMCP это Python-фреймворк, который позволяет быстро построить серверную сторону этого соединения, а его исходный код опубликован в официальном репозитории FastMCP на GitHub по лицензии Apache-2.0.
Этот учебник установит FastMCP на самом деле, запустит минимальный сервер, а затем создаст что-то, что на самом деле понадобится агенту: инструмент MCP, который получает URL через API Nstproxy Crawl и возвращает очищенный Markdown вызывающему агенту. Каждый блок кода ниже был выполнен в реальной среде Python; когда шагу нужны были учетные данные, которые эта статья не может предоставить, этот разрыв раскрывается, а не скрывается под вымышленным ответом.
Дайте инструменту MCP реальный уровень извлечения и очистки
Как только вашему инструменту MCP нужно будет обращаться к реальному веб-сайту, а не лишь выполнять локальную арифметику, ему требуется надежный уровень извлечения и очистки — Nstproxy Crawl это API, к которому обращается рабочий пример этого учебника, чтобы превратить URL в читаемый агентом Markdown.
в изолированной среде Linux и подтвердил установку с помощью pip show fastmcp, что показало:
Name: fastmcp
Version: 3.4.7
Summary: Быстрый, Пайтонский способ создания MCP-серверов и клиентов.
Эта версия соответствует тому, что страница FastMCP на PyPI указала как актуальную на момент написания. requests установлен вместе с FastMCP, так как рабочий пример позже в этом учебнике делает исходящий HTTP вызов к Nstproxy Crawl API. Статус: запущен-в-реальном-времени — это фактический вывод из песочницы, использованной для написания этой статьи, а не скопированный номер версии.
Настройка минимального FastMCP сервера
Сервер FastMCP начинается с одного экземпляра FastMCP, который называет сервер и хранит каждый инструмент, который вы на него зарегистрируете. Создайте файл с именем hello_server.py:
from fastmcp import FastMCP
mcp = FastMCP("Сервер Hello MCP")@mcp.tooldefgreet(name:str)->str:"""Приветствие пользователя по имени."""returnf"Привет, {name}!"if __name__ =="__main__": mcp.run()
Декоратор @mcp.tool считывает подсказки типов функции (name: str на вход, str на выход) и её строку документации, затем строит JSON-схему, которую клиент MCP использует, чтобы знать, как вызывать greet и что ожидать в ответ — вы никогда не пишете эту схему вручную. mcp.run() без аргументов запускает сервер через транспорт stdio, стандартный транспорт, который такие клиенты MCP, как Claude Desktop, используют для запуска локального сервера как под процесса. Статус: только-настройка для этого блока сам по себе — он будет использоваться на практике в следующем разделе.
Основная реализация: запуск и вызов сервера
Запуск python hello_server.py стартует сервер и блокирует выполнение, ожидая подключения клиента MCP через stdio — в этом режиме нет видимого вывода по замыслу, поэтому полезным шагом проверки будет вызов его с клиентом, а не смотреть на заблокированный терминал. Собственный класс Client FastMCP может подключаться к объекту сервера непосредственно внутри того же процесса Python, что является самым быстрым способом подтвердить, что инструмент действительно работает, прежде чем подключать реальный клиент MCP:
import asyncio
from fastmcp import Client
from hello_server import mcp
asyncdefmain():asyncwith Client(mcp)as client: tools =await client.list_tools()print("ИНСТРУМЕНТЫ:",[t.name for t in tools]) result =await client.call_tool("greet",{"name":"Nstproxy"})print("РЕЗУЛЬТАТ:", result.data)if __name__ =="__main__": asyncio.run(main())
Статус: запущен-в-реальном-времени — это реальный захваченный stdout от выполнения обоих файлов вместе, подтверждающий, что регистрация инструментов, генерация схемы и путь вызова работают от начала до конца, прежде чем какое-либо внешнее API попадет в картину.
Чтобы запустить тот же сервер как отдельный процесс, а не как клиент в процессе, либо вызовите его напрямую (python hello_server.py, транспорт stdio), либо запустите его через HTTP для удаленного доступа:
mcp.run(transport="http", port=8000)
CLI FastMCP предлагает тот же выбор без редактирования файла: fastmcp run hello_server.py:mcp для stdio или fastmcp run hello_server.py:mcp --transport http --port 8000 для HTTP. CLI импортирует объект сервера напрямую и не выполняет блок if __name__ == "__main__":, так что эта проверка необязательна, когда вы запускаете только через CLI. Статус: иллюстративный — документированный синтаксис транспорта из официального руководства FastMCP, не запускается отдельно от уже проверенного пути stdio.
Расширенные шаблоны: дайте серверу инструмент, который стоит вызывать
Инструмент, который добавляет два числа, доказывает, что декоратор работает, но он не дает агенту причины запускать этот сервер, вместо того чтобы просто выполнять арифметику самостоятельно. Сценарий, который на самом деле нуждается в сервере MCP, — это передача агенту чего-то, что он не может сделать сам — доступ к внешнему API, получение страницы или чтение файловой системы, к которой он иным образом не имеет доступа. Рабочий пример этого руководства — инструмент crawl_url, который вызывает точку конечного скрипта Nstproxy Crawl для одностраничного скрапинга и возвращает содержимое страницы в формате Markdown, так что любой клиент MCP, который подключается к этому серверу, может передать URL и получить текст, который LLM может прочитать напрямую.
Точка конечного скрипта Nstproxy Crawl для одностраничного скрапинга находится по адресу POST https://api.nstproxy.com/api/v1/crawl/scrape, аутентифицирована с помощью заголовка x-api-key. Вызванная без дополнительных параметров, эта точка возвращает идентификатор задачи немедленно со статусом status: "processing" для асинхронного опроса; добавление параметра запроса async=true заставляет ту же точку ожидать и возвращать результат в одном ответе вместо этого, что и требуется для синхронного вызова инструмента MCP. Тело запроса принимает url, массив formats (markdown, html, rawData, screenshot, pdf), необязательный timeout в миллисекундах и onlyMainContent, чтобы убрать навигацию и шаблонный текст. Ответ включает поле markdown с очищенным содержимым или токен markdownRef, если результат слишком велик для inline — разрешается отдельно через GET /api/v1/crawl/storage/read?st={ref}. Эти детали подтверждены напрямую с документацией Nstproxy Crawl API, а не предполагаются из имени точки конечного скрипта.
import os
import requests
from fastmcp import FastMCP
mcp = FastMCP("Сервер MCP Nstproxy Crawl")NSTPROXY_API_KEY = os.environ.get("NSTPROXY_API_KEY","ВАШ_API_KEY")CRAWL_ENDPOINT ="https://api.nstproxy.com/api/v1/crawl/scrape"@mcp.tooldefcrawl_url(url:str)->str:"""Получите URL через Nstproxy Crawl и верните очищенный Markdown.
Требует установки NSTPROXY_API_KEY. Вызывает точку конечного скрипта одностраничного скрапинга Nstproxy Crawl с async=true, чтобы получить немедленный,
синхронный ответ.
"""try: response = requests.post( CRAWL_ENDPOINT, params={"async":"true"}, headers={"x-api-key": NSTPROXY_API_KEY,"Content-Type":"application/json",}, json={"url": url,"formats":["markdown"],"onlyMainContent":True,"timeout":60000,}, timeout=65,)except requests.RequestException as exc:returnf"Запрос завершился неудачей до получения ответа: {exc}"if response.status_code !=200:return(f"Nstproxy Crawl вернул HTTP {response.status_code}: "f"{response.text[:500]}") body = response.json()ifnot body.get("success",False):returnf"Запрос на скрапинг не удался: {body}"return body.get("data",{}).get("markdown","(поле markdown не возвращено)")if __name__ =="__main__": mcp.run()
Вам потребуется собственный API-ключ Nstproxy Crawl, установленный в виде переменной окружения NSTPROXY_API_KEY, прежде чем crawl_url сможет вернуть реальное содержимое страницы — без него функция по-прежнему выполняется, регистрируется как инструмент с правильной схемой и делает реальный исходящий запрос, но этот запрос не может быть аутентифицирован. Подключение клиента FastMCP к этому серверу и перечисление его инструментов работало точно так же, как и пример hello-world:
TOOL: ['crawl_url']
Вызов crawl_url против https://example.com в песочнице этой статьи — которая не имеет настроенного API-ключа Nstproxy и также имеет ограниченный исходящий сетевой доступ — выдал эту реальную, захваченную ошибку вместо вымышленного успешного ответа:
RESULT: Запрос не удался до получения ответа: HTTPSConnectionPool(host='api.nstproxy.com', port=443): Максимальное количество попыток превышено с URL: /api/v1/crawl/scrape?async=true (Вызвано ProxyError('Не удалось подключиться к прокси', OSError('Ошибка туннеля: 403 Запрещено')))
Статус: пробел-пререквизит для исходного вызова Crawl — регистрация инструмента и генерация схемы для crawl_urlвыполнены в живом режиме, но фактический fetch страницы не смог завершиться в этой среде, потому что не был доступен настоящий API ключ для тестирования, и эта статья не сгенерировала JSON ответ, чтобы сделать пример более завершенным, чем он есть. В нормальном развертывании с действительным NSTPROXY_API_KEY и открытым сетевым доступом тот же код возвращает поле markdown из успешного ответа Nstproxy Crawl вместо этой строки с ошибкой.
Честные ограничения
FastMCP обрабатывает генерацию схемы, транспортировку и цикл запрос/ответ, но он не обрабатывает то, что происходит внутри вашей функции инструмента — это обычный Python с обычными режимами сбоев. crawl_url выше возвращает обычную строку на каждом пути, включая пути с ошибками, потому что результаты инструмента MCP предназначены для чтения вызывающей моделью; выброс необработанного исключения вместо этого выведет как общую ошибку вызова инструмента для клиента без каких-либо диагностических деталей в строке. Производственная версия этого инструмента также должна ограничивать url ожидаемыми схемами, устанавливать тайм-аут запроса, короче терпения клиента, и явно решать, следует ли повторять 403/404 от целевого сайта (оба оплачиваются по тарифам за каждый fetch Crawl, поскольку сам fetch завершился) или возвращать их вызывающему как есть.
Сам FastMCP не управляет ограничениями по количеству вызовов API, повторными попытками или аутентификацией для любого внешнего сервиса, который вызывает ваш инструмент — все это принадлежит к коду вашего инструмента, точно так же, как показано выше. Он также не проверяет содержимое возвращаемого инструмента за пределами соответствия объявленному типу подсказки, поэтому инструмент, который обещает -> str и возвращает плохо сформированный Markdown, по-прежнему пройдет проверки FastMCP; проверка качества выходных данных — это работа автора инструмента.
Устранение неполадок
Сервер, который работает, но сообщает о нулевых инструментах, обычно означает, что функция никогда не была декорирована или была декорирована на другом экземпляре FastMCP, чем тот, который передан в mcp.run() — проверьте, что каждый @mcp.tool находится прямо над функцией и что только один экземпляр FastMCP() существует на файл. Клиент, который может перечислить инструменты, но выдает ошибку на каждом вызове, часто имеет несоответствие типу подсказки: если схема обещает int, а клиент отправляет строку, которую нельзя привести, FastMCP отклонит вызов до того, как тело вашей функции когда-либо выполнится. Когда инструмент, который вызывает внешний API, не возвращает ничего полезного, проверьте статус ответа и тело отдельно, как это делает crawl_url выше — ответ Nstproxy Crawl может прийти как обычный HTTP 200, в то время как его поле success равно false, и код, который только проверяет код состояния, пропустит это.
Заключение
Вся ценность FastMCP заключается в сокращении расстояния между рабочей функцией Python и инструментом, который может вызвать агент ИИ — этот учебник прошел от пустого каталога до сервера с реальным вызовом внешнего API за два файла. Путь от pip install fastmcp до зарегистрированного инструмента с проверенной схемой занимает минуты; более трудная, более ценная часть заключается в том, что инструмент на самом деле делает после его вызова агентом, именно поэтому приведенный здесь рабочий пример обращается к внешнему API, а не останавливается на арифметике.
Для инструмента, основная задача которого заключается в преобразовании URL в контент, читаемый агентом, Nstproxy Crawl создан именно для этого перехода. Это API для веб-сканирования, ориентированное на ИИ, которое принимает URL и возвращает чистый, структурированный вывод — Markdown, очищенный HTML, ссылки, скриншоты или PDF — с рендерингом JavaScript и собственным доступом через прокси Nstproxy, который обрабатывается за единственным вызовом API, вместо того чтобы требовать от вас запускать безголовый браузер и пул прокси самостоятельно внутри функции инструмента. Он идеально подходит для инструмента MCP, такого как crawl_url выше, потому что оба решают одну и ту же задачу: предоставить модели что-то, что она может прочитать, не делая код агента ответственным за автоматизацию браузера.
Вывод Markdown за один вызов — один запрос POST возвращает содержимое страницы, уже преобразованное в Markdown, поэтому функция инструмента MCP должна лишь проверить success и вернуть поле markdown, а не выполнять собственное преобразование HTML в текст.
Рендеринг JavaScript включен — страницы, которые строят свой контент на стороне клиента, полностью рендерятся до захвата ответа, поэтому инструмент, вызывающий Crawl, не нуждается в отдельной зависимости безголовго браузера наряду с FastMCP.
Круговое сканирование на уровне сайта для инструментов с несколькими страницами — помимо примера одностраничного crawl_url здесь, тот же аккаунт может вызвать POST /api/v1/crawl, чтобы просканировать много страниц в рамках одной задачи (с явными пределами maxDepth и maxPages), что полезно для инструмента, который должен передать агенту целый раздел сайта, а не один URL.
Повторные попытки и хранение больших результатов обрабатываются на сервере — неудачные запросы повторяются автоматически, а слишком большие полезные грузы Markdown/HTML/скриншотов возвращаются в виде токена ссылки, который разрешается через отдельный вызов чтения хранилища, так что функции инструмента не нужно иметь свой собственный цикл повторных попыток или обработку размера блоба.
Если вы уже используете инфраструктуру с поддержкой прокси для других работ по сбору данных, прокси-серверы Residential Lite от Nstproxy естественно сочетаются с инструментом MCP на основе Crawl в случаях, когда целевому сайту нужен прямой контроль прокси, а не полностью управляемый конвейер Crawl — Статья Nstproxy Proxy Manager о краулинге Amazon через управляемую инфраструктуру прокси подробно описывает этот более низкий путь. Полная справка по запросам/ответам для конечной точки, используемой в crawl_url выше, задокументирована в документации API Nstproxy Crawl.
ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
В: Является ли FastMCP тем же, что и официальный MCP Python SDK?
Нет — FastMCP 1.0 был объединён с официальным MCP Python SDK, но активно поддерживаемый пакет fastmcp на PyPI это FastMCP 2.x, расширенный фреймворк, построенный на этой основе с дополнительными функциями для разработчиков, такими как Client в процессе, используемый в этом учебнике, вспомогательные функции аутентификации и специализированный CLI. Установка fastmcp из PyPI предоставляет вам линию 2.x, а не код, который был поглощен основной SDK.
В: Нужно ли мне оплачиваемый API-ключ, чтобы следовать этому учебнику?
Только для второй половины. Пример hello_server.py работает совершенно бесплатно без внешнего аккаунта, а собственный вывод этого учебника TOOLS: ['greet'] / RESULT: Hello, Nstproxy! был зафиксирован без каких-либо учётных данных. Пример crawl_url требует ключ API Nstproxy Crawl, чтобы действительно вернуть содержимое страницы — без него инструмент всё равно регистрируется и пытается выполнить запрос, но вызов завершается неудачей, точно так же, как показано в зафиксированном выводе ошибок этой статьи.
В: Могу ли я использовать сервер FastMCP с Claude Desktop или другим клиентом MCP?
Да — любой клиент MCP, который поддерживает запуск локального сервера через stdio, включая Claude Desktop, может запустить сервер FastMCP так же, как он запускает любой другой сервер MCP, настроив свою конфигурацию на Python-файл и позволив клиенту управлять процессом. Этот учебник проверил поведение вызова инструмента с помощью Client класса FastMCP вместо этого, что быстрее для итераций при написании и тестировании инструментов, прежде чем подключить полный клиент на рабочем столе.
В: Что произойдет, если моя функция инструмента вызовет исключение вместо возврата строки?
Необработанное исключение внутри функции инструмента отображается клиенту MCP как общая ошибка вызова инструмента, без конкретных диагностических данных, которые может предоставить пойманная и возвращённая строка ошибки. Пример crawl_url в этом учебнике намеренно перехватывает requests.RequestException и проверяет статус ответа и поле success явно, возвращая описательную строку на каждом пути вместо того, чтобы позволить исключению распространяться.
В: Обрабатывает ли FastMCP ограничение по скорости или повторные попытки для внешних API, которые вызывает мой инструмент?
Нет — FastMCP управляет слоем протокола MCP (генерация схемы, маршрутизация сообщений, транспорт), а не внутренним устройством того, что делает ваша функция инструмента. Ограничение по скорости, логика повторных попыток и обработка времени ожидания для внешнего API, такого как Nstproxy Crawl, должны быть в коде вашего инструмента таким же образом, как и crawl_url выше устанавливает свой собственный таймаут запроса и проверяет тело ответа, а не предполагает, что FastMCP обрабатывает это.
В: Законно ли создавать инструмент MCP, который краулит веб-сайты?
Краулинг публично доступных страниц, к которым у вас есть разрешение на доступ, является стандартной практикой, но вы всё равно несёте ответственность за соблюдение условий обслуживания целевого сайта, уважение к robots.txt, где это применимо, и недопущение использования инструмента краулинга для извлечения непубличного или контролируемого доступа контента. Nstproxy Crawl построен вокруг легитимного, разрешённого сбора публичных веб-данных, а не для обхода аутентификации или платных стен, и такая же ответственность applies к тому, что делает ваша собственная функция инструмента с данными, которые она получает.
Сравните BeautifulSoup и Scrapy для веб-скрапинга на Python: архитектура, производительность, функции и руководство по принятию решений, основанное на живом коде и проверенных источниках.
Marcus Chen
Aug. 24th 2026
110M+ реальных IP с 99.9% успешных доступов
Средний отклик ~0.5с для задач высокой конкуренции
Всего от $0.1/GB
Мгновенный доступ к премиальным residential, datacenter, IPv6 и ISP пулам.