Read in:
Русский

MCP Federation

MCP Federation соединяет вашу базу знаний trip2g с другими MCP-совместимыми базами. AI-агент обращается к одному эндпоинту (вашему хабу) и ищет по всем подключённым базам: публичным справочникам, базам партнёров и внешним адаптерам (GitHub, Telegram).

flowchart LR
    Agent["AI-агент\n.mcp.json: только хаб"]
    Hub["Ваш trip2g хаб\n/_system/mcp\n(ваши заметки + KB-заметки)"]
    Pub["Публичная база\nбез аутентификации"]
    Peer["Приватный пир\nHMAC-секрет"]
    Ext["Внешний адаптер\nHMAC-секрет"]

    Agent -->|"search / federated_search"| Hub
    Hub -->|"веерный federated_search"| Pub
    Hub -->|"веер + исходящий секрет → JWT"| Peer
    Hub -->|"веер + исходящий секрет → JWT"| Ext
    Peer -->|"входящий секрет фильтрует результаты"| Hub
    Ext -->|"входящий секрет фильтрует результаты"| Hub

Топология федерации: агент видит один MCP-эндпоинт; хаб рассылает запрос по всем подключённым пирам и объединяет результаты.

Как это работает

┌─────────────────────────┐
│  Ваш AI-агент           │
│  .mcp.json: ваш хаб     │
└────────────┬────────────┘
             │
┌────────────▼────────────┐
│  Ваш trip2g хаб         │
│  /_system/mcp           │
│  • ваши заметки         │
│  • KB-заметки на пиров  │
│    и адаптеры           │
└─┬──────────┬───────────┬┘
  │          │           │
  ▼          ▼           ▼
Публичная  Партнёр    Внешний
база       (HMAC)     адаптер
(без auth)            (HMAC)

Хаб не хранит удалённый контент: только ваши заметки, KB-заметки для роутинга и federation secrets в базе данных.

Основные понятия

KB-заметка: обычная заметка Obsidian с полем mcp_federation_kb_url в frontmatter. Это поле регистрирует пира. Тело заметки содержит произвольный текст с описанием, когда использовать эту базу; агент читает его во время поиска.

Federation secret: общий HMAC-ключ для аутентификации вашего хаба у приватного пира (и наоборот). Для публичных баз секрет не нужен.

kb_id: короткий slug для идентификации пира. По умолчанию совпадает с hostname URL; переопределяется полем mcp_federation_kb_id.

Добавить публичного пира

Создайте заметку в хранилище с таким frontmatter:

---
mcp_federation_kb_url: https://philosophers.example.com/_system/mcp
mcp_federation_kb_id: philosophy
---
Использовать для: поиска философских отсылок к инженерным решениям.
Не использовать для: срочных задач и узкоспециализированных тем.

Нажмите Sync. Готово. Агент обращается к этой базе через federated_search с kb_id="philosophy" или автоматически при веерном поиске по всем базам.

Поле mcp_federation_kb_id необязательно. Если его нет, kb_id будет равен hostname URL (philosophers.example.com).

Добавить приватного пира (двусторонний обмен)

Приватные пиры аутентифицируются через общий HMAC-секрет. Это однократный обмен ключами.

Шаг 1: Боб генерирует секрет для вас.

Боб открывает Администрирование → Federation → «Добавить входящий секрет». Задаёт короткий идентификатор (alice-2026), при необходимости выбирает, какие подграфы вы можете видеть, и нажимает «Сгенерировать». Секрет в формате hex показывается один раз. Боб отправляет вам kid и secretHex по доверенному каналу (например, личным сообщением в Telegram).

Шаг 2: Вставьте данные как исходящий секрет.

В вашем Администрирование → Federation → «Добавить исходящий секрет» укажите:

  • kid: идентификатор от Боба (например, alice-2026)
  • secretHex: hex-строка от Боба
  • kb_url: MCP-эндпоинт Боба (https://bob.team.io/_system/mcp)

Шаг 3: Создайте KB-заметку.

---
mcp_federation_kb_url: https://bob.team.io/_system/mcp
mcp_federation_kb_id: bob
---
Использовать для: статусов задач Боба, общих заметок по дизайну.

Шаг 4: Настройте обратное направление (опционально).

Если Боб тоже хочет запрашивать вашу базу, повторите процесс в обратную сторону: вы генерируете входящий секрет, отправляете Бобу kid и secretHex, Боб вставляет их как исходящий секрет со ссылкой на ваш /_system/mcp.

Каждое направление независимо. Можно дать Бобу доступ к подграфу team-status, не открывая остальное.

Инструменты федерации

Хаб всегда предоставляет шесть MCP-методов, независимо от количества подключённых пиров:

Метод Описание
search(query) Локальный поиск по вашим заметкам
similar(note_id) Похожие заметки локально
note_html(note_id) Содержимое локальной заметки
expand(pid, toc_path?) Обход оглавления локальной заметки по уровням, см. ru/user/expand
federated_search(query, kb_id?) Поиск по пирам (веерный или точечный)
federated_similar(note_id, kb_id) Похожие заметки у конкретного пира
federated_note_html(note_id, kb_id) Содержимое заметки у конкретного пира
federated_expand(kb_id, pid, toc_path?) Обход оглавления удалённой заметки у конкретного пира, тот же интерфейс, что expand, применённый к удалённой базе

federated_search без kb_id веерно обращается ко всем доступным пирам параллельно и объединяет результаты. С kb_id="bob" обращается только к базе Боба. С kb_ids=["bob","philosophy"] обращается ровно к этим двум.

Когда локальный search находит KB-заметку, он возвращает её с маркером kind: "federation_kb" и инструкцией агенту вызвать federated_search с соответствующим kb_id. Агент собирает контекст по мере запросов, без выгрузки всего заранее.

Права доступа

Федерация использует существующую систему подграфов trip2g.

Исходящий доступ (что видят пиры у вас). Когда хаб Боба обращается к вашему с валидным JWT, ваш экземпляр проверяет, какие подграфы привязаны к его kid, и фильтрует результаты. Заметки вне этого scope невидимы для Боба, так же как для любого другого читателя без доступа.

Входящий доступ (что видите вы у пиров). KB-заметки являются обычными заметками, им можно назначить подграф. Если позднее вы откроете хаб коллегам, они увидят только те KB-заметки, подграф которых им доступен локально.

Уровни видимости KB-заметок. KB-заметка подчиняется тем же правилам видимости, что и обычная заметка:

Frontmatter KB-заметки Анонимный MCP-агент Аутентифицированный подписчик Администратор
free: true ✓ маршрутизация работает ✓ маршрутизация работает
(нет флагов) ✗ "not configured" ✓ маршрутизация работает
subgraphs: team ✗ "not configured" только при подписке на team

KB-заметка без free: и без subgraphs: не является «только для администратора»: её видит любой аутентифицированный подписчик. Чтобы KB-заметка была доступна только администраторам, поместите её в подграф, к которому у обычных пользователей нет доступа (например, subgraphs: admin-only). Ответ federated_search на недоступный kb_id всегда «not configured», неотличим от несуществующего kb_id, поэтому существование пира не раскрывается.

Граф федерации (панель self-hosted)

Если trip2g запущен за simplepanel, в разделе Администрирование → Federation есть страница с графом, отображающим текущее состояние всех инстансов пула в виде направленного графа. Каждый узел соответствует инстансу, каждое ребро соответствует обнаруженной federation-связи.

Цвет ребра отражает статус соединения:

Статус Значение
ok KB-заметка, исходящий секрет и совпадающий неотозванный входящий секрет с хотя бы одним подграфом. Связь работает.
no_auth KB-заметка есть, исходящего секрета нет. Агент попытается позвонить пиру, пир ответит 401. Добавьте исходящий секрет.
orphan_secret Исходящий секрет записан, но KB-заметка не указывает на пира. Агент никогда не обнаружит этот маршрут. Добавьте KB-заметку.
one_way Исходящий секрет и KB-заметка есть, но у пира нет входящего секрета для этого kid. Пир ответит 401. Попросите пира добавить входящий секрет для вашего kid.
no_access Связь установлена, но входящий секрет не даёт доступа ни к одному подграфу, пир получает пустые результаты. Расширьте scope.
revoked Исходящий секрет отозван. Маршрут нерабочий, запись следует удалить.
external URL назначения не является инстансом пула (публичная или внешняя база). Только информативно.

На странице также выводится список Issues: ошибки конфигурации, обнаруженные при сканировании, с уровнем важности (error / warning / info) и описанием по каждому ребру. Это позволяет диагностировать проблемы, не читая логи.

Отозвать доступ

Администрирование → Federation → найдите строку → «Отозвать». Строка становится серой. Все последующие запросы с этим kid получают ответ 401. Координация с пиром не нужна: его вызовы просто начнут завершаться ошибкой.

Чтобы сузить scope без полного отзыва, удалите отдельные подграфы из kid в панели «Управление scope».

Ограничения

  • Аутентификация: только HMAC-SHA256. mTLS и OAuth не поддерживаются в текущей версии.
  • Таймаут веерного поиска: 2 секунды на каждый вызов пира. Медленные или недоступные пиры пропускаются; результаты от остальных возвращаются.
  • Глубина рекурсии: по умолчанию 3 уровня (настраивается через MCP_FEDERATION_MAX_DEPTH на self-hosted). Защищает от петель, когда пиры сами имеют пиров.
  • TLS: хаб не форсирует HTTPS. Используйте HTTPS-URL пиров в продакшене.

Диагностика

federation_not_configured в ответе агента. В хранилище нет KB-заметок или поле mcp_federation_kb_url отсутствует либо написано с ошибкой.

Ошибки 401 в логах хаба. Исходящий секрет не совпадает с тем, что ожидает пир, или пир отозвал ваш kid. Повторите обмен секретами с партнёром.

Пир не возвращает результатов, ошибки нет. Scope вашего kid у пира пуст. Бобу нужно добавить хотя бы один подграф к вашему kid в его Администрирование → Federation → «Управление scope».

Веерный поиск всегда занимает 2 секунды. Один или несколько пиров недоступны. Проверьте логи хаба с префиксом mcp:federation: там будут предупреждения с указанием конкретного пира и временем ожидания.

Дополнительно