Skip to main content
Glama

relic

Чип, через який чужа свідомість бачить твоє життя, — і лише ту його частину, яку ти відкрив. Назва — з Cyberpunk 2077.

Шлюз від продуктів до соцмереж і месенджерів: ключ продукту, область дії, облік, бюджет відповіді. REST для продуктів і MCP для моделей — на одному порту, з одними ключами.

продукт ──(ключ продукту)──▶ relic ──▶ адаптер ──▶ інструмент ──▶ платформа
модель (MCP) ────────────┘              telegram-archive → Telegram-Archive → Telegram
                                        youtube          → Data API v3, yt-dlp → YouTube

Двійник exo-ai (шлюз до моделей) за механікою і незалежний від нього: шлюзи один про одного не знають. Самарі, аналіз і відповіді робить продукт: текст звідси → промпт → exo-ai.

Навіщо сервіс, а не бібліотека

  • Сесія особистого акаунта — одна. Два процеси на одній сесії ламають її, кожен новий вхід — «новий пристрій», часті входи — шлях до бану. Сесія живе в одному місці, продукти просять дані.

  • Політику не можна доручити тому, кого вона обмежує. «Продукт A бачить лише ці три чати» тримається тільки на боці сервера.

  • Стелі частоти — спільні: FloodWait і ліміти API рахуються на акаунт.

Адаптер — на інструмент, не на платформу. Важка робота лишається в готовому інструменті (архіватор, міст, офіційний API), адаптер лише перекладає.

Related MCP server: Telegram MCP Server

Контракт

Authorization: Bearer <ключ продукту> (або X-Api-Key). Ключ називає продукт — це ім'я шукається в області й пишеться в облік.

MCP-інструмент

REST-двійник

list_chats

GET /v1/conversations?limit&offset

get_messages

GET /v1/conversations/:ref/messages?limit&cursor

search_messages

GET /v1/conversations/:ref/search?q&limit

get_messages_by_date

GET /v1/conversations/:ref/by-date?date&timezone&limit

get_transcript

GET /v1/conversations/:ref/transcript?language&cursor

Ще: GET /v1/adapters (стан входу кожного адаптера з причиною і limited), GET /v1/scope (своя область), GET /v1/usage (виклики за добу), /health/live, /health/ready (обидва без ключа). MCP — POST /mcp, Streamable HTTP, stateless, відповідь JSON.

Спільна форма даних — одна на всі адаптери:

сутність

поля

розмова

ref (<адаптер>:<акаунт>:<id>, стабільний), name, type, platform, last_message?, participants?

повідомлення

id, date (ISO, UTC, Z), from?, out?, text?, reply_to?, topic?, media?, fwd?, edited?, deleted?, pinned?, cut?

сегмент транскрипту

start, end (секунди від початку, до десятих), text — рядки субтитрів, злиті до ~30 с

код

що це

що робити продуктові

200

відповідь є

читати; truncated: true → звузити питання або cursor=next

404 not_found

розмови немає або вона поза областю ключа — невідрізненно

брати ref з list_chats

429 budget_exhausted

денна стеля продукту

деградувати, сьогодні не повторювати

429 rate_limited

стеля частоти платформи (у YouTube — і вичерпана квота Data API)

повторити пізніше

502 platform_blocked

платформа відмовляє саме серверу (бот-перевірка YouTube для IP датацентру)

не повторювати; вхід цілий

503 adapter_expired

вхід адаптера відхилено

людина: перелогінити інструмент

503 adapter_down / scope_unavailable

інструмент або БД недосяжні

fail-safe продукту

Область дії

Рядки social_scope: (продукт, адаптер, акаунт, розмови, read|write). Розмови — список ref або {*} = «усе, що бачить акаунт адаптера». Новий продукт — порожня область, а не «усе». Запис — окремий рядок write; поки його немає, інструментів запису немає в tools/list (у цій версії їх немає взагалі). Недоступна БД — відмова (fail-closed); облік і стелі — fail-open.

Два рівні білого списку свідомо: акаунт інструмента (наприклад, акаунт переглядача архіву з білим списком чатів) — що шлюзу взагалі видно; область ключа — що з цього видно конкретному продукту.

Бюджет відповіді

Кожна відповідь — не більше MAX_ITEMS (100) елементів і MAX_RESPONSE_BYTES (32 КБ ≈ 8–10 тис. токенів) компактного JSON. Обрізана каже truncated, пояснює note і, де є куди гортати, дає непрозорий курсор next. Перше повідомлення не випадає, а вкорочується (cut) — порожня сторінка не дала б курсора. Перенесення internal/budget з форку telegram-archive-mcp, тести — ті самі межі. Заміряно на чаті в 10 тис. повідомлень: 3,3 тис. токенів замість 75 тис.

Здоров'я бачить вхід адаптера

/health/ready несе checks.<адаптер>: ok / expired / down (і skip — вхід вимкнений конфігом свідомо, як youtube без ключа). expired чи down увімкненого адаптера — 503 проби: протухлий вхід — це «шлюз непридатний», і монітор мусить це бачити, а не дізнатись з обліку. Стеля частоти платформи (FloodWait, 429, вичерпана квота) і відмова платформи серверу (бот-перевірка) — не вирок, лише limited з причиною у /v1/adapters. Проба ходить за розкладом (ADAPTER_PROBE_INTERVAL_MS), а не на кожен запит монітора: відхилений вхід — теж спроба, а стелі входів у інструментів тісні.

Адаптери

адаптер

інструмент

вхід

telegram-archive

HTTP API переглядача Telegram-Archive

окремий акаунт переглядача з allowed_chat_refs: []; кука viewer_auth шлеться руками (вона Secure, а шлюз ходить по HTTP у приватній мережі), перелогін на 401

youtube

YouTube Data API v3 (коментарі, назви) і yt-dlp (транскрипти)

входу в акаунт немає, акаунт один — public; «вхід» = ключ API (YOUTUBE_API_KEY), без нього skip

youtube

  • Розмова = відео: youtube:public:<id>, type: video, name — назва. Ref будує викликач: на місці id можна дати й посилання (watch?v=, youtu.be/, shorts/, live/, embed/) — шлюз зводить його до id до області й обліку. list_chats відео не показує: відео — не список розмов акаунта. Окремого resolve немає: розбір рядка не вартий ще одного інструмента.

  • Повідомлення = коментарі (commentThreads): гілка, за нею відповіді, які Data API віддає разом із нею (reply_to — батьківський коментар); новіші гілки першими. Курсор несе pageToken і останній відданий коментар — сторінку, обрізану бюджетом посередині, продовжує без повторів. get_messages_by_date — коментарі дня (обхід до 20 сторінок); search_messages — searchTerms.

  • Транскрипт — окремий інструмент get_transcript, бо мовлення не «повідомлення»: ні автора, ні id. Субтитри автора мовою відео, інакше розпізнане YouTube (source: manual | auto); language — інша мова. Сторінки гортаються з кешу (година), yt-dlp — один запуск на відео.

  • Квота Data API — 10 000 одиниць на добу на проєкт Google; сторінка коментарів = 1. Витрата кожного виклику — у detail обліку (units=…), проба ключа — 1 одиниця раз на YOUTUBE_PROBE_INTERVAL_MS (10 хв).

  • Запобіжник (adapters/youtube/guard.ts, стан у Redis): на весь шлюз ≤ 20 запусків yt-dlp на годину і ≤ 100 на добу, проміжок ≥ 10 с, один процес за раз; 429 від YouTube — пауза на годину, 5 бот-перевірок поспіль — на 30 хв; відео з бот-перевіркою не питається вдруге добу; кеш транскрипту — доба; автоперекладу субтитрів немає; власна стеля Data API — 5000 одиниць на добу з 10 000. На паузі чи стелі шлюз відповідає сам (429 rate_limited з причиною), YouTube не питає. Без Redis стан тримається в пам'яті — стелі не знімаються.

  • Бот-перевірка. З IP датацентру YouTube часто просить «Sign in to confirm you're not a bot» — тоді get_transcript → platform_blocked, а стан адаптера лишається ok з limited і причиною. Ні інший player_client, ні PO-токен цього не знімають (перевірено 2026-09-24); коментарі (Data API) перевірка не зачіпає.

Інтерфейс — src/adapters/types.ts (як Publisher в exopost: probe ≈ verify, AdapterError.retryable, реєстр за іменем).

stdio-вхід MCP

dist/mcp-stdio.js — міст stdin/stdout ↔ http://127.0.0.1:$PORT/mcp того самого контейнера з ключем продукту STDIO_PRODUCT з оточення. Для клієнта, що бачить контейнер лише через docker exec:

claude mcp add relic -s user -- docker exec -i relic-web node dist/mcp-stdio.js

Політика лишається на сервері: область, стеля, бюджет і облік — ті самі.

Розробка

pnpm install && pnpm test && pnpm typecheck

Ворота (typecheck + test) — у стадії build образу. Міграції — dbmate (apps/api/db/migrations), бінарник у образі. yt-dlp — запінений реліз з перевіркою sha256 (ADD --checksum у Dockerfile); тести підміняють його справжнім процесом-скриптом.

Ліцензія

MIT — LICENSE. Бюджет відповіді — перенесення нашого ж доповнення до форку telegram-archive-mcp (сам форк лишається під GPL-3.0 апстріму, і його код сюди не переноситься: обхід дня в адаптері — власна реалізація). Інструмент під адаптером — Telegram-Archive, з ним relic говорить лише по HTTP. yt-dlp (Unlicense) — окремий бінарник в образі, relic запускає його процесом.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Enables full access to your personal Telegram account via MCP, allowing reading, sending, and searching messages, managing chats, and retrieving user information through natural language commands.
    18
    29 npm
    4
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to control a personal Telegram account for sending/reading messages, media, group management, and more via the MTProto API.
    MIT