Компании и энтузиасты стремятся автоматизировать процессы, но не каждый готов писать код с нуля. Поэтому в последние годы особую популярность набрала no-code платформа n8n. С её помощью можно быстро собирать пайплайны различной сложности: от простых чат-ботов до умных ассистентов, которые управляют календарем и напоминают о задачах.  Обычно в статьях про n8n затрагивают только готовые блоки, собирают из них пайплайны автоматизации, но в то же время упоминают об ограниченности использования этой платформы. Действительно, базовых блоков в n8n может не хватать, чтобы закрыть все потребности пользователя, но сегодня я покажу, как можно обойти эти ограничения и расширить базовый функционал n8n.

Привет, Хабр! Меня зовут Музафаров Данил, я Data Scientist в компании Raft. В этом туториале я шаг за шагом покажу: как локально развернуть n8n, как добавить кастомные API и создать полноценного AI-агента с MCP tools с расширенным функционалом. Придется немного писать код, но главное, что это позволит оставить архитектуру решения на n8n, дополнив его кастомными тулами.

План

С самого начала у меня была какая-то тактика и я ее придерживался
С самого начала у меня была какая-то тактика и я ее придерживался

Из названия статьи вы уже поняли, что мы пройдем путь от чат-бота до агента с MCP серверами. Для удобства я разделил статью по главам, чтобы перед глазами был план и мы его придерживались.

  1. Как развернуть n8n локально

  2. Простой чат-бот

  3. RAG для ответов на вопросы о компании

  4. Объединяем все одно c помощью свича: узнаем погоду, обращаемся к LLM и  RAG

  5. Объединяем все одно c помощью тулов AI Агента: узнаем погоду, обращаемся к LLM и  RAG 

  6. Final Boss: AI Агент с MCP серверами 

Как развернуть n8n локально

Развернуть n8n локально достаточно просто. Для этого мы будем использовать docker compose, а в качестве базы данных подключим Postgres DB.

Достаточно просто говорит он...
Достаточно просто говорит он...

Такой подход удобен сразу по нескольким причинам:

  • легко поднять и запустить все необходимые сервисы одной командой;

  • каждый сервис работает в отдельном контейнере (похоже на микросервисную архитектуру);

  • при необходимости можно быстро обновлять или изменять проект.

Создадим файл docker-compose.yml со следующим содержимым:

docker-compose.yml
version: '3.8'

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=db
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=n8n
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      - db

  db:
    image: postgres:12
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=n8n
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  n8n_data:
  db_data:

Запускаем через команду в терминале:

docker compose up -d

После того, как все сервисы запустятся, мы можем перейти по адресу http://localhost:5678, там доступен веб-интерфейс нашего локального n8n. Итак, теперь мы можем приступить к следующему шагу.

Простой чат-бот 

При первом запуске n8n попросит создать учётную запись. Так как мы работаем локально, можно задать любые логин и пароль – они будут использоваться только для входа в интерфейс. Можем начинать собирать пайплайны. 

Начнем с самого простого чат-бота, которому мы сможем задавать вопрос и получать ответ.

Итак, каждый блок в n8n называется нода (node). Вот так будет выглядеть собранный пайплайн из трех нод:

Workflow чат-бота
Workflow чат-бота

Здесь есть базовые ноды: Webhook и Respond to Webhook. Они нужны чтобы принимать запрос и возвращать ответ. В центре пайплайна находится нода OpenAI, которая требует API Key. В n8n есть удобный функционал хранения credentials для различных сервисов. То есть стоит только один раз внести API Key и сохранить его, чтобы при следующих инициализациях нод OpenAI можно было просто один раз кликнуть и всё заработало. Вот так выглядит пример того как происходит регистрация credentials OpenAI:

Инициализация Credentials OpenAI
Инициализация Credentials OpenAI

То есть просто вносится API Key и Base url в соответствующие поля.

Нода Webhook

Нода Webhook
Нода Webhook

В нашем случае она должна принимать запросы от пользователя, чтобы передавать их дальше по пайплайну. Выставляем HTTP метод POST, при желании меняем рандомный path и/или добавляем аутентификацию и в конце мы выбираем Using 'Respond to Webhook' Node. Последнее дает нам возможность получать ответ с последней ноды, которая стоит в конце цепочки: Respond to Webhook.

Теперь можем запустить пайплайн попробовать отправить curl запрос:

curl -X POST "http://localhost:5678/webhook-test/my\_first\_chain" \
  -H "Content-Type: application/json" \
  -d '{"message":"Что такое n8n?"}'

Получаем ответ:

n8n — это бесплатная и открытая платформа для автоматизации рабочих процессов (no-code/low-code workflow automation). С её помощью можно связывать различные сервисы и приложения между собой без программирования, чтобы автоматизировать рутинные задачи.

Всё работает, теперь можно прикрутить UI, сделанный через gradio. 

Пример интерфейса gradio
import gradio as gr
import requests

# production webhook из n8n
N8N_WEBHOOK = <ВАШ АДРЕС ИЗ НОДЫ WEBHOOK>

def chat_with_n8n(user_input):
    response = requests.post(
        N8N_WEBHOOK,
        json={"question": user_input}, 
        headers={"Content-Type": "application/json"}
    )
    if response.ok:
        return response.text
    else:
        return f"Ошибка: {response.status_code}, {response.text}"

# Интерфейс Gradio
demo = gr.Interface(
    fn=chat_with_n8n,
    inputs=gr.Textbox(lines=2, placeholder="Напиши что-нибудь..."),
    outputs="text",
    title="n8n Chat",
    description="Простое Gradio-приложение, которое ходит в n8n"
)

if __name__ == "__main__":
    demo.launch()
Чат-бот с веб-интерфейсом на gradio
Чат-бот с веб-интерфейсом на gradio

Первый простой пайплайн готов, теперь вы можете пользоваться чат-ботом!

RAG

В предыдущей главе мы разобрали простейший пайплайн чат-бота с LLM. Вторая задача по частоте обращений бизнеса к ИИ - это системы умного поиска. В этой главе я предлагаю реализовать систему RAG, которая будет подтягивать релевантные ответы из базы знаний. 

В качестве векторной базы знаний будем использовать Qdrant. Также поднимем его локально, доработав наш docker-compose.yml.

Обновленный docker-compose.yml
version: '3.8'

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=db
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=n8n
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      - db
      - qdrant

  db:
    image: postgres:12
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=n8n
    volumes:
      - db_data:/var/lib/postgresql/data

  qdrant:
    image: qdrant/qdrant
    restart: unless-stopped
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant_data:/qdrant/storage

volumes:
  n8n_data:
  db_data:
  qdrant_data:

Любым удобным способом загружаем в векторную базу знаний ваши документы. В моем случае это следующая таблица:

ID

Вопрос

Ответ

1

Где находится офис?

Наш офис в Санкт-Петербурге на Лиговском проспекте.

2

Как связаться с поддержкой?

Поддержка доступна по email support@company.com.

3

Какие продукты есть?

Мы предлагаем чат-ботов, автоматизацию и NLP-аналитику.

4

Как работает пробная версия?

Тестовый период 14 дней, лимит 100 запросов в день.

5

Есть ли скидки для студентов?

Да, студенты получают скидку 50%.

Я загрузил данные с помощью python скрипта. Использовал эмбеддер от OpenAI text-embedding-3-small (dim=1536). Эмбеддером я называю LLM-модели, которые превращают текст в эмбеддинг (вектор), почитать что такое эмбеддинги можно тут.

Python скрипт, который я использовал для загрузки данных в Qdrant:
import os
from dotenv import load_dotenv
from openai import OpenAI
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, PointStruct, Distance

load_dotenv()

# -----------------------------
# 1. Настройка OpenAI
# -----------------------------
OPENAI_KEY = os.getenv("OPENAI_API_KEY_ORIG")
if not OPENAI_KEY:
    raise ValueError("❌ Не найден OPENAI_API_KEY_ORIG в .env")

client_openai = OpenAI(api_key=OPENAI_KEY, base_url="https://api.openai.com/v1")

# -----------------------------
# 2. Настройка Qdrant
# -----------------------------
qdrant = QdrantClient(host="localhost", port=6333)
COLLECTION = "faq"
DIM = 1536

# Создаем коллекцию только если её нет
if not qdrant.collection_exists(COLLECTION):
    qdrant.create_collection(
        COLLECTION,
        vectors_config=VectorParams(size=DIM, distance=Distance.COSINE)
    )
    print("✅ Коллекция создана:", COLLECTION)
else:
    print("ℹ️ Коллекция уже существует, переиспользуем:", COLLECTION)

# -----------------------------
# 3. База FAQ
# -----------------------------
faq = [
    {"id": 1, "q": "Где находится офис?", "a": "Наш офис в Санкт-Петербурге на Лиговском проспекте."},
    {"id": 2, "q": "Как связаться с поддержкой?", "a": "Поддержка доступна по email support@company.com."},
    {"id": 3, "q": "Какие продукты есть?", "a": "Мы предлагаем чат-ботов, автоматизацию и NLP-аналитику."},
    {"id": 4, "q": "Как работает пробная версия?", "a": "Тестовый период 14 дней, лимит 100 запросов в день."},
    {"id": 5, "q": "Есть ли скидки для студентов?", "a": "Да, студенты получают скидку 50%."},
]

# -----------------------------
# 4. Функция для получения эмбеддингов
# -----------------------------
def embed(text: str):
    resp = client_openai.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    vector = resp.data[0].embedding
    if not vector or len(vector) != DIM:
        raise ValueError(f"Эмбеддинг некорректен для текста: {text}")
    return vector

# -----------------------------
# 5. Подготовка и загрузка точек
# -----------------------------
points = []
for item in faq:
    vec = embed(f"Вопрос: {item['q']} | Ответ: {item['a']}")
    points.append(
        PointStruct(
            id=item["id"],
            vector=vec,
            payload={
                "pageContent": f"Вопрос: {item['q']} Ответ: {item['a']}",
                "metadata": {
                    "question": item["q"],
                    "answer": item["a"],
                }
            }
        )
    )
    print(f"Вектор создан для ID {item['id']}")

# Upsert — обновляет или добавляет точки (индексы сохраняются)
qdrant.upsert(collection_name=COLLECTION, points=points)

Далее создаем пайплайн:

RAG пайплайн
RAG пайплайн

В n8n есть готовая нода Qdrant Vector Store. Для ее инициализации необходимо указать credentials для Qdrant, также как ранее мы делали с OpenAI.

Credentials для Qdrant
Credentials для Qdrant

Указываем название контейнера и его порт в поле url, а также API Key из env-переменных docker-compose.

Данная нода требует подключения эмбеддера, чтобы превращать запрос пользователя в эмбеддинг. Указываем credentials OpenAI и выбираем такой же эмбеддер, который мы использовали при формировании векторной базы знаний.

Перейдем к самой ноде Qdrant Vector Store.

Нода Qdrant Vector Store
Нода Qdrant Vector Store

Так как мы ранее подключились к нашей локальной векторной базе знаний, чтобы загрузить данные, то мы можем выбрать коллекцию, которая нас интересует, в нашем случае это коллекция “faq”

В поле "Prompt" запишем промпт, по которому будет формироваться поиск в векторной БД и указываем топ релевантных ответов, опционально подключаем метадату (она содержится в базе знаний).

Далее переходим к следующей ноде, формирующей итоговый ответ. Это нода OpenAI с функцией ответа LLM. В прошлом пайплайне мы уже встречались с ней, но сейчас мы будем ей отдавать контекст, поэтому запишем промпт:

Ты — помощник, который отвечает только на основе базы знаний.
Контекст:
{{ $json.document.metadata.question }} - {{ $json.document.metadata.answer }}
Вопрос пользователя: {{ $('Webhook').item.json.body.question }}
Ответь, используя только контекст. Если {{ $json.score }} ниже, чем "0.35",
то не нужно использовать контекст, так как вопрос не связан с базой знаний и 
отвечай просто на поставленный вопрос пользователя без контекста

Порог в 0.35 подбирался экспериментальным путем, в зависимости от исходных данных в базе знаний он может отличаться.

Давайте проверим, что векторная база знаний работает и наша система RAG нам отвечает.

Будем проверять на следующих тест-кейсах:

Первый тест-кейс
Первый тест-кейс
Второй тест-кейс
Второй тест-кейс
Третий тест-кейс
Третий тест-кейс
Четвертый тест-кейс
Четвертый тест-кейс

Как видно из тест-кейсов - RAG система отлично работает. Вопросы, которые не относятся к базе знаний обрабатываются через LLM.

Объединяем все одно c помощью свитча: узнаем погоду, обращаемся к LLM и  RAG

Теперь усложним задачу, добавим дополнительно функционал для получения погоды в конкретном городе, оставив при этом RAG. 

На вход пайплайна поставим LLM классификатор, а погоду будем брать по бесплатному API от OpenWeatherMap. Как это будет выглядеть:

Пайплайн с нодой Switch
Пайплайн с нодой Switch

В LLM классификаторе указываем system prompt и user prompt.

System Prompt:

Тебе дан вопрос пользователя. Определи, какие источники информации нужны для ответа:
- Qdrant (если вопрос про компанию, офис, продукты, скидки и т.п.)
- API (если вопрос о погоде, температуре, погодных условиях)
- LLM (если вопрос общий, математика, теория, не относящееся к компании и погоде) 
Ответь строго в формате JSON:
{
  "use_rag": true/false,
  "use_api": true/false,
  "use_llm": true/false
}

User Prompt:

Здесь просто укажем вопрос пользователя

Вопрос: {{ $json.body.question }}

После LLM классификатора стоит встроенная нода Switch. Она работает по принципу правил. Если конкретное поле из входного JSON “is true”, то открывается путь к следующей ноде.

Нода Switch
Нода Switch

Первый путь – RAG. Там тот же функционал, что мы рассмотрели в предыдущей главе.

Второй путь – прогноз погоды. Сначала с помощью LLM ноды мы достаем название города из запроса пользователя. Далее название города подаем в API OpenWeatherMap. Получаем большой JSON со всеми параметрами погоды: температура, облачность, влажность и прочее. В следующей ноде LLM мы на основе ответов OpenWeatherMap ноды формируем ответ для пользователя в красивом виде с помощью промпта ниже:

Ты — умный ассистент. Тебе дан ответ от OpenWeather API в формате JSON:
Погода: {{ JSON.stringify($json.weather) }}
Температура и влажность: {{ JSON.stringify($json.main) }}
Ветер: {{ JSON.stringify($json.wind) }}
Облачность: {{ JSON.stringify($json.clouds) }}
Преврати это в понятный ответ для пользователя на русском языке. 
Укажи:
- текущую температуру (округли до целого числа),
- погоду (облачность, дождь, солнце),
- скорость ветра,
- влажность.
Не используй лишние технические детали (id, код, координаты).
Если в JSON нет нужной информации — скажи, что данные недоступны.

Третий путь – LLM. То есть, если вопрос пользователя никак не связан с офисом или погодой, то мы отправляемся в ноду LLM, где обрабатываем запрос пользователя и формируем итоговый ответ.

Готово! Вы реализовали свой первый chain-пайплайн!

Его основной минус заключается в том, что при свитче мы не можем в одном запросе использовать информацию сразу из двух тулов: не можем спросить про погоду в городе, где находится офис компании.
Чтобы решить такую проблему мы можем использовать AI Агента. Давайте посмотрим насколько усложнится пайплайн в этом случае.

Объединяем все одно c помощью тулов AI Агента: узнаем погоду, обращаемся к LLM и RAG

Создадим в n8n агента, который будет выполнять те же задачи из предыдущего пайплайна, но с использованием tools.

Пайплайн с агентом и двумя тулами
Пайплайн с агентом и двумя тулами

Основная нода здесь – AI Agent. Рассмотрим основные поля этой ноды.

Параметры ноды AI Agent
Параметры ноды AI Agent

Указываем в user message (user prompt):
Входной запрос пользователя { $json.body.question }

В системном промпте важно описать инструменты, которые есть у агента и правила, по которым он будет ими пользоваться.

System message (system prompt):

Ты — умный помощник. У тебя есть три инструмента:  
1. "Knowledge Base" — база знаний (RAG) для поиска по внутренним документам.  
   Используй её, когда пользователь задаёт вопрос, связанный с нашей документацией, компанией или внутренней информацией.  
2. "Weather API" — инструмент для получения погоды через OpenWeatherMap.  
   Используй его, если пользователь спрашивает про погоду, температуру, прогноз или климат в конкретном городе.  
3. "LLM Answer" — твои собственные знания и способности.  
   Используй их для всех остальных вопросов, когда не нужно обращаться к базе или API. 
Правила:  
- Сначала пойми, какой инструмент подходит.  
- Если нужно RAG или погода — используй соответствующий инструмент.  
- Если вопрос общий (например, философский или бытовой) — отвечай напрямую сам.  
- Отвечай ясно и по-русски, даже если данные приходят на английском.  

Также к ноде агента необходимо подключить Chat Model (в нашем случае gpt-4.1), PostgresDB для контекстной памяти (ранее мы ее поднимали через docker compose) и необходимые tools(инструменты).

Tools подключаем через встроенные ноды. Ноды tools немного могут отличаться от обычных нод из пайплайнов, построенных ранее.

Например, tool OpenWeatherMap

Нода tool OpenWeatherMap
Нода tool OpenWeatherMap

Здесь также инициализируемся через авторизационные данные, описываем функционал инструмента в его описании (поле “Description”), выбираем операцию инструмента (текущая погода), выбираем метрическую систему (чтобы были градусы Цельсия, а не Фаренгейта), выбираем чтобы мы получали погоду по названию города, а не по координатам. Также здесь есть функционал того, чтобы город определился автоматически с помощью ИИ из запроса пользователя. И в последнем поле указываем язык формирования ответа API.

Для Qdrant Vector Store делаем аналогично, описываем функционал инструмента, указываем название коллекции, подключаем эмбеддер.

Предлагаю немного улучшить веб-интерфейс gradio для чат-бота с нашим агентом.

Обновленный gradio веб-интерфейс
import gradio as gr
import requests

N8N_WEBHOOK = <ВАШ АДРЕС ИЗ НОДЫ WEBHOOK>

# История чата
chat_history = []

def chat_with_n8n(user_input, history):
    response = requests.post(
        N8N_WEBHOOK,
        json={"question": user_input},
        headers={"Content-Type": "application/json"}
    )
    if response.ok:
        bot_response = response.text
    else:
        bot_response = f"Ошибка: {response.status_code}, {response.text}"
    
    # Добавляем сообщение пользователя и ответ бота
    history.append((user_input, bot_response))
    return history, history

# Функция для отображения с кастомным стилем
def format_message(history):
    formatted = []
    for user_msg, bot_msg in history:
        formatted.append((
            f"<div style='background-color:#D1E8FF;padding:8px;border-radius:5px;margin:2px;'>Вы: {user_msg}</div>",
            f"<div style='background-color:#F1F0F0;padding:8px;border-radius:5px;margin:2px;'>Бот: {bot_msg}</div>"
        ))
    return formatted

with gr.Blocks() as demo:
    gr.Markdown("## ? n8n Chat")
    
    chatbot = gr.Chatbot()
    user_input = gr.Textbox(
        placeholder="Напиши что-нибудь...",
        show_label=False
    )
    send_btn = gr.Button("Отправить")
    
    send_btn.click(
        chat_with_n8n,
        inputs=[user_input, chatbot],
        outputs=[chatbot, chatbot]
    )
    user_input.submit(
        chat_with_n8n,
        inputs=[user_input, chatbot],
        outputs=[chatbot, chatbot]
    )

demo.launch()

Агент готов, подключим его к UI и проверим его работоспособность:

Тест-кейсы 1,2
Тест-кейсы 1,2
Тест-кейсы 3,4
Тест-кейсы 3,4
Тест-кейс 5
Тест-кейс 5

Как видно, агент работает отлично. Самое интересное, что он смог при запросе пользователя “Где офис и какая там погода?” понять, что необходимо использовать два инструмента. Он отлично справился с этим и дал грамотный ответ на оба вопроса.

Может случиться такое, что tool, который вы хотите использовать, не окажется в базовых нодах n8n. В таком случае придется как-то через “костыли” придумывать http-request ноду, поднимать через FastAPI сервис и прочее. 

Но на самом деле всё можно сделать более удобно, лаконичино и наглядно, используя MCP подход. Расскажу подробнее об этом ниже.

Final Boss: AI Агент с MCP серверами 

Доработаем нашего агента так, чтобы он обращался к инструментам через MCP.

AI Агент с MCP серверами в качестве tools
AI Агент с MCP серверами в качестве tools

Теперь для ноды AI Agent – tools являются MCP серверами.

MCP сервера поднимаются через библиотеку FastMCP. Сначала мы инициализируем класс, затем расписываем необходимые инструменты для этого сервера как функции в python. Когда функция готова мы ее регистрируем через метод tool(), в нее передаем саму функцию и полное описание ее функционала, чтобы агент мог понять как и когда он может ее использовать.

Для каждого MCP мы прописываем docker файл, а также добавляем MCP серверы в docker-compose.

Обновленный docker-compose
version: '3.8'

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=db
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=n8n
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      - db
      - qdrant

  db:
    image: postgres:12
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=n8n
    volumes:
      - db_data:/var/lib/postgresql/data

  qdrant:
    image: qdrant/qdrant
    restart: unless-stopped
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant_data:/qdrant/storage
  
  weather-mcp:
    build: ./src/mcp_weather
    restart: unless-stopped
    ports:
      - "8082:8082"
    env_file:
      - .env
  qdrant-mcp:
    build: ./src/mcp_qdrant
    restart: unless-stopped
    ports:
      - "8083:8083"
    env_file:
      - .env
    depends_on:
      - qdrant

volumes:
  n8n_data:
  db_data:
  qdrant_data:
  weather-mcp_data:
  qdrant-mcp_data:
MCP сервер прогноза погоды
import os
import requests
from fastmcp import FastMCP

server = FastMCP("Weather MCP Server")

def get_weather(city: str) -> dict:
    """
    MCP-инструмент: получает погоду по городу.
    Возвращает JSON с полезной информацией.
    """
    API_KEY = os.getenv("OWM_API_KEY")
    if not API_KEY:
        return {"error": "API key is not set in OWM_API_KEY environment variable"}

    url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={API\_KEY}&units=metric&lang=ru"

    try:
        response = requests.get(url)
        response.raise_for_status()
        data = response.json()

        return {
            "city": data.get("name"),
            "country": data.get("sys", {}).get("country"),
            "temperature": data.get("main", {}).get("temp"),
            "feels_like": data.get("main", {}).get("feels_like"),
            "weather": data.get("weather", [{}])[0].get("description"),
            "wind_speed": data.get("wind", {}).get("speed"),
        }

    except requests.exceptions.RequestException as e:
        return {"error": str(e)}

# Регистрируем инструмент
server.tool(get_weather, description="""Ты можешь воспользоваться этим инструментом,
            если тебе интересно узнать текущую погоду в городе. Для этого достаточно передать в инструмент название города.""")

if __name__ == "__main__":
    server.run("http", host="0.0.0.0", port=8082)

Вот так выглядят ноды MCP серверов для прогноза погоды и поиска по векторной базе. MCP для прогноза погоды имеет всего один прописанный tool, называется 'get_weather' и имеет описание. MCP для векторной базы знаний тоже имеет всего лишь один tool, который достает топ 3 ближайших вектора из базы знаний, релевантных запросу пользователя.

Нода MCP для прогноза погоды
Нода MCP для прогноза погоды
Нода MCP для Qdrant
Нода MCP для Qdrant

Ну и конечно важно не забыть про System prompt для Агента:

Ты — умный помощник. У тебя есть два инструмента, которые работают на MCP.  
1. "MCP Qdrant" — база знаний (RAG) для поиска по внутренним документам.  
   Используй её, когда пользователь задаёт вопрос, связанный с нашей документацией, компанией или внутренней информацией.  

2. "MCP Open Weather Map" — инструмент для получения погоды через OpenWeatherMap.  
Используй его, если пользователь спрашивает про погоду, температуру, прогноз или климат в конкретном городе.
3. Если вопрос пользователя не относится ни к погоде, ни к жизни компании, то отвечай самостоятельно, используя LLM 
Правила:  
- Сначала пойми, какой инструмент подходит.  
- Если нужно RAG или погода — используй соответствующий инструмент.  
- Если вопрос общий (например, философский или бытовой) — отвечай напрямую сам.  
- Отвечай ясно и по-русски, даже если данные приходят на английском.  

Мы сделали AI Агента с MCP серверами, каждый из которых имел один tool. Каждый MCP сервер мы подняли как отдельный сервис, а сам агент в свою очередь смог разобраться как использовать каждый из tools, за счет их грамотного описания.

Заключение

Я надеюсь, что вы не потеряли желание заниматься n8n.

Когда это закончится?
Когда это закончится?

Что можно сказать про n8n? Эта платформа действительно не является панацеей - она имеет функциональные ограничения. Я показал как можно обходить эти ограничения. Кому-то это может показаться «overkill», кто‑то в этом наоборот увидит интерес. Но факт остается фактом — такая платформа может позволить очень быстро накидать базовые MVP-проекты и без проблем интегрироваться с простым веб-интерфейсом на gradio.

А если вы упираетесь в потолок базовых возможностей n8n, то смело используйте этот туториал для расширения функционала платформы и решения своих задач.

Комментарии (0)