
MCP без воды и шаблонного кода на практике: разбираем протокол, поднимаем сервер, тестируем через Inspector и учим LLM торговать через Finam API. Разберёмся, когда MCP выгоднее «обычных функций», как изолировать интеграции и упростить отладку инструментов.
2025 год негласно признан годом ИИ-агентов - именно этот год подарил нам такое понятие MCP. Что стоит за этим словом за ширмой хайпа? Когда это действительно стоит применять (и стоит ли?)? Разберём это на практике.
Если вы точно знаете, зачем вам это нужно, проматывайте сразу к практической части (с установкой, разработкой, развертыванием). А я вначале подробно раскрою смысл технологии.
На десерт сделаем MCP-сервер для финансового ИИ-помощника в инвестициях. Поехали!
Что это и для чего это нужно?
Итак, вы хотите дать LLM больше возможностей чем выдача простого текста. Чтобы превратить его из обычной говорилки в “ИИ-агента”, который может думать, совершать какие-то действия (например получать данные из сервисов, отправлять их куда-то, создавать файлы) и получать результат выполнения этих действий, вам нужно написать инструменты (tools, functions) - это такие функции, описание которых будет передано в LLM и которые она может в ходе ответов вызывать и получать результаты прям в контекстное окно.
По сути целый стандарт и у разных поставщиков LLM он реализован по разному. Здесь приходит MCP - Model Context Protocol, open-source способ унифицировать соединение между разными интеграциями и такими же разнородными большими языковыми моделями.

Инициатором MCP выступила Anthropic, после чего крупные компании выпустили собственные серверы: Figma, GitLab, Slack, Google. Вы тоже можете реализовать свой.

Использовать готовые MCP-сервер для разных интеграций больших сервисов и докруток возможностей ИИ агента, это круто. Но зачем реализовывать свой MCP-сервер, есть же обычные функции, которые агент может вызывать?
Пока агент выполняет две‑три операции — условно запрос к БД, ответ через RAG, передача чата человеку — проблем немного. Однако с ростом функциональности интеграции неизбежно множатся, усложняется и вся система подключений этих функций. А вслед за этим усложняется поддержка и отладка, увеличивается количество мест, где код может отказать.
Почему стоит внедрить MCP:
Используя MCP мы изолируем интеграции и выносим в отдельный сервис. Так что по сути это шаг к будущей микросервисной агентной архитектуре.
Удобство разработки, отладки и тестирования. Вам не надо каждый раз запускать агента и тестировать tool через него. Вы можете это сделать отдельно и дальше я покажу как.
Ну и да, вы можете давать доступ к нем извне, для внешних агентов как некоторое API.
Поэтому для серьёзных систем с ИИ‑агентами стоит научиться использовать и применять MCP. Чем мы и займемся.
Основные понятия
Начнем с краткой теории по факту. Есть условный MCP-сервер и 3 участника, которые взаимодействуют с ним - пользователь, LLM и приложение, через которое пользователь общается с LLM (например Claude Desktop, ChatGPT, Cursor). Соответственно MCP-протокол для каждого участника устанавливает свои возможности
Tools (для LLM) - функции, которые непосредственно будет вызывать LLM
Resources (для приложения) - статические read-only данные, которые может получать приложение
Prompts (для пользователя) - шаблоны промптов, которые может использовать пользователь

В MCP есть много других интересных идей, те же resources, когда клиент может запросить состояние сервера или метаданные. Или например запрос пользовательского ввода данных перед вызовом tools (User Elicitation). Или Sampling, когда MCP-сервер вызывает LLM на стороне клиента для внутренних операций. Но по большей части они не поддерживаются большинством MCP-клиентов, так как эти возможности относительно новые. Поэтому мы будем использовать только tools. Для самостоятельного изучения оставляю спецификацию Model Context Protocol.
Установка и первые шаги
Для MCP существуют SDK для любого языка программирования. В случае Python, сообщество создало даже целый фреймворк - FastMCP. Его и будем использовать для реализации кастомного MCP-сервера. Устанавливаем, используя самый современный пакетный менеджер зависимостей - uv.
uv add fastmcp
По синтаксису FastMCP очень похож на FastAPI, так как они оба берут начала от общего предка Starlette. И кстати между собой неплохо интегрируются. Но нам это пока не нужно, а нам нужно создать отдельный инстанс MCP-сервера и добавить к нему инструментов аналогично эндпоинтам в FastAPI. В FastMCP это делается вот так:
from fastmcp import FastMCP
mcp = FastMCP("FinamMCP")
@mcp.tool
def greet(name: str) -> str:
""" Поприветствовать пользователя под именем name """
return f"Hello, {name}!"
В этом примере мы реализуем инструмент greet, который попадет в контекст LLM, и который она сможет вызывать, сама подставляя нужный аргумент name.
Давайте пробовать запускать. MCP предлагает разные транспортные протоколы для сервера: stdio и http. stdio идет по умолчанию и подходит для локальной разработки, но не поддерживает сразу несколько клиентов и hot-reloading, а также усложняет отладку в IDE, поэтому я запускаю на проколеhttp через uvicorn.
uvicorn main:mcp --port 3000 --reload
Итак, сервак запустился. Но FastMCP в отличии от FastAPI не создает никакого визуального дашборда с документацией и возможностью запуска эндпоинтов. На помощь приходит полезная утилита MCP - MCP Inspector. Запускаем и устанавливаем ее одной командой.
npx @modelcontextprotocol/inspector
Открывается страница MCP Inspector. Ставим протокол Streamable HTTP, вводим URL адрес нашего сервера с путем /mcp и нажимаем кнопочку Connect. После успешного соединения с сервером загорается зеленая лампочка с припиской Connected.

Окружение мы подготовили, можем приступать к написанию логики MCP-сервера на реальном примере.
А теперь к реальному созданию MCP-сервера
Я хочу сделать персонального ИИ-помощника для инвестирования. Хочу чтоб GPT мог за один запрос получить мой портфель, проанализировать торги интересующей меня бумаги и сделать ордер на покупку или продажу. Получится такой “вайб-трейдинг”)
⚠️ Предупреждение: Не является инвестиционной рекомендацией! Всегда оценивайте риски и свои финансовые возможности. Но мы тут собственно по другому вопросу собрались, так что давайте вернемся к MCP.
В качестве торговой платформы буду использовать Финам. Начнем с его API. Если пошариться в официальной документации Finam API, можно увидеть 4 основных сервиса API: AccountsService - cервис аккаунтов, AssetsService - сервис счетов, OrdersService - сервис ордеров, MarketDataService - сервис рыночных данных.
Я хочу сохранить эту структуру, и разделить свой MCP-сервер на 4 подсервера, каждый из которых будет отвечать за свой сервис Finam API. В FastAPI это делается через routing. В FastMCP cделаю это с помощью метода mount главного инстанса MCP-сервера.
from fastmcp import FastMCP
from src.servers.account import account_mcp
from src.servers.assets import assets_mcp
from src.servers.market_data import market_data_mcp
from src.servers.order import order_mcp
finam_mcp = FastMCP("FinamMCP")
finam_mcp.mount(account_mcp, prefix="account") # TODO: account_mcp
finam_mcp.mount(market_data_mcp, prefix="market_data") # TODO: market_data_mcp
finam_mcp.mount(assets_mcp, prefix="assets") # TODO: assets_mcp
finam_mcp.mount(order_mcp, prefix="order") # TODO: order_mcp
К моему большому счастью, у Finam есть Python SDK на базе REST API. Мне остается просто написать прослойку с авторизацией, устраняя возникающие косяки с библиотекой и добавив подробные описания методов для LLM. За дело!
Начнем с авторизации. При использовании Finam API, нужно предоставить свой API-ключ и номер счета, с которым ИИ-агент будет работать. В случае stdin протокола достаточно задать для этого переменные среды (FINAM_API_KEY, FINAM_ACCOUNT_ID), но в случае сервера на http протоколе имеет смысл передавать такие данные, используя заголовки (”finam-api-key”, “finam-account-id").
При каждом запросе на сервер мы будем авторизироваться на Финам, получать токен и создавать на его основе API-клиент. Ключевое словосочетание здесь “при каждом запросе”. Это означает нам нужно сделать Middleware, которое будет это делать. В документации указан метод on_call_tool, который вызывается для tools. То что нам нужно, реализуем всю логику авторизации в нем.
from fastmcp.exceptions import ToolError
from fastmcp.server.dependencies import get_http_headers
from fastmcp.server.middleware import Middleware, MiddlewareContext
from src.tradeapi.finam import FinamClient
class FinamCredentialsMiddleware(Middleware):
async def on_call_tool(self, context: MiddlewareContext, call_next):
"""Перехватываем все вызовы tools."""
# Получаем заголовки из HTTP запроса
headers = get_http_headers()
# Извлекаем необходимые заголовки
api_key = headers.get("finam-api-key")
account_id = headers.get("finam-account-id")
# Проверяем наличие обязательных заголовков
if not api_key or not account_id:
raise ToolError(
"Missing required headers: FINAM-API-KEY and FINAM-ACCOUNT-ID are required"
)
# Создаем клиент Finam
finam_client = await FinamClient.create(
api_key=api_key,
account_id=account_id
)
# Сохраняем клиента в state контекста
if context.fastmcp_context:
context.fastmcp_context.set_state("finam_client", finam_client)
# Продолжаем выполнение
return await call_next(context)
Сохраняю объект клиента в state контекста. Таким образом смогу его доставать внутри tools-функций. Больше возможностей читайте в документации.
А теперь перейдем и к ним. Основной упор нужно сделать на документацию и сигнатуру - ведь именно так наш агент будет понимать, что делают эти инструменты и как ими пользоваться. Здесь стоит отметить потрясающую интеграцию с Pydantic. Вы можете просто указать Pydantic тип и на его основе сгенерируется документация по входным параметрам. Учитывая то, что Pydantic модели в библиотеке FinamTradeApiPy уже были реализованы мне остается просто правильно разметить все функции.
Я приведу фрагмент кода с сервисом Account. Тут можно увидеть, как я получаю объект клиента через ранее упомянутый контекст методом get_context().get_state("finam_client"). Кстати, ссылка на весь код в github будет ниже.
"""Finam Account MCP - действия связанные с получением данных об аккаунте """
from fastmcp import FastMCP
from fastmcp.server.dependencies import get_context
from finam_trade_api.account import GetAccountResponse, GetTransactionsResponse, GetTradesResponse
account_mcp = FastMCP(name="FinamAccountServer")
@account_mcp.tool(tags={"account"})
async def get_info() -> GetAccountResponse:
"""Получение информации по конкретному счету (статус и тип аккаунта, доступные средства, дневная прибыль, открытые позиции (количество, средняя цена, прибыль/убыток), тип портфеля)"""
finam_client = get_context().get_state("finam_client")
return await finam_client.get_account_info()
@account_mcp.tool(tags={"account"})
async def get_transactions(start_time: str, end_time: str, limit: int = 10) -> GetTransactionsResponse:
"""Получение списка транзакций аккаунта"""
finam_client = get_context().get_state("finam_client")
return await finam_client.get_transactions(start_time, end_time, limit)
@account_mcp.tool(tags={"account"})
async def get_trades(start_time: str, end_time: str, limit: int = 10) -> GetTradesResponse:
"""Получение истории по сделкам аккаунта"""
finam_client = get_context().get_state("finam_client")
return await finam_client.get_trades(start_time, end_time, limit)
Все готово. Запускаем uvicorn. В MCP inspector нажимаем "Reconnect", чтобы соединение возобновилось. Переходим во вкладку "Tools" и подтягиваем список инструментов через кнопку "List Tools". Покажутся все написанные в коде MCP-сервера инструменты с описаниями. Каждый инструмент мы можем запускать вписав входные параметры и таким образом отлаживать и тестировать наш MCP-сервер. Супер замена Swagger UI!


Итак Finam MCP-сервер готов. Могу подключить его ко всем основным приложениям LLM - ChatGPT, Claude, Gemini. И могу использовать также в своем коде через библиотеку MCP-клиента, которая тоже входит в FastMCP

LLM инструменты видит и может запускать, API интеграция вызывается и данные приходят. Вдобавок все модульно и в виде отдельных сервисов. Шик ?.
Итоги
Полный код примера здесь: https://github.com/Alexander-Panov/finam-mcp
Резюмируя:
MCP - Model Context Protocol
Упрощает подключение внешних интеграций к ИИ‑приложениям.
Состоит из трёх сущностей: Resources, Tools, Prompts.
SDK есть для многих языков; для Python оптимален FastMCP.
Сервер запускаем по
HTTPи отлаживаем через MCP Inspector.Логику tools описываем строго: понятное назначение и типизированные входные и выходные параметры.
Подключение к клиентам MCP — по URL с авторизационными заголовками.
MCP достаточно мощная штука, и в будущем будет стандартом реализации ИИ-агентов. Я точно взял себе на вооружение и буду использовать в проектах.
Переходите в мой тг канал, больше практических инсайтов о применении ИИ в разработке и не только. Спасибо за внимание! Да прибудет сила в ваших ИИ-агентах!