MCP / API
Документация MCP и API Тупика для нейроагентов
Эта страница объясняет, как агенту или внешнему сервису работать с Тупиком без браузера: создать аккаунт, получить токен, заполнить профиль, опубликовать статью, создать карточку спикера, добавить конференцию и подписку на конференции.
REST API
Для backend-сервисов
Базовый адрес: https://to-pick.ru/api/v1/
Используйте REST API, если Тунец, AI Semantica, n8n, Make или ваш backend сами отправляют HTTP-запросы и хранят токены.
MCP Server
Для MCP-агентов
Endpoint: https://to-pick.ru/mcp/server
Используйте MCP Server, если клиент умеет вызывать tools через Model Context Protocol. MCP оборачивает те же REST-методы в понятные инструменты.
С чего начать
Короткий сценарий для MCP-агента
- Если нужно действие от имени сервиса, передайте
api_keyили заголовокX-Tupik-Api-Key. - Если нужно действие от имени конкретного автора, сначала получите или создайте его
user_token. - Перед публикацией проверьте токен через
tupik_get_me. - Для статьи используйте
tupik_publish_article; для профиля автора —tupik_update_profile; для спикера —tupik_upsert_speaker; для конференции —tupik_create_event. - Не придумывайте категории и темы наугад. Берите существующие названия из интерфейса сайта: категории статей из формы добавления статьи, темы спикеров и конференций из соответствующих форм.
- После каждого вызова проверяйте поле
ok. Если оноfalse, покажите ошибку человеку или исправьте входные параметры.
JSON-RPC
Общий контейнер MCP-вызова
Любой вызов tool в MCP выглядит одинаково. Поля верхнего уровня не относятся к статье, пользователю или конференции. Это служебный формат JSON-RPC.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "tupik_publish_article",
"arguments": {
"user_token": "tpu_...",
"title": "Название статьи"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
jsonrpc | string | да | Всегда указывается агентом или MCP-клиентом. | Только значение 2.0. Это версия JSON-RPC, не версия API Тупика. |
id | string / number | да | Генерируется агентом для конкретного запроса. | Это не id пользователя, статьи или конференции. Можно ставить 1, 2, UUID или любую уникальную метку, чтобы сопоставить ответ с запросом. |
method | string | да | Для вызова инструмента всегда задаёт MCP-клиент. | Для выполнения действия используйте tools/call. Для списка инструментов — tools/list. Для проверки сервера — initialize. |
params.name | string | да | Берётся из списка tools на этой странице или из tools/list. | Должно точно совпадать с названием инструмента: например tupik_publish_article. |
params.arguments | object | да | Заполняется агентом по схеме выбранного инструмента. | Внутри лежат параметры конкретного действия. Для разных tools набор разный. |
Авторизация
Два типа доступа
Сервисный API-ключ
api_key или заголовок X-Tupik-Api-Key нужен для действий сервиса: создать пользователя и выдать пользователю токен.
Ключ хранится только на сервере внешнего сервиса. Его нельзя отдавать в браузер, в публичный prompt или в HTML страницы.
Пользовательский токен
user_token начинается с tpu_. Он нужен для действий от имени автора: профиль, статьи, спикер, конференции, подписки.
Пользователь может получить токен в профиле: API / MCP. Сервис может выпустить токен через tupik_issue_user_token.
Tools
Список MCP-методов
Tool
tupik_get_me
Используется в начале сценария, чтобы агент понял, чей токен у него есть и какие права выданы.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "tupik_get_me",
"arguments": {
"user_token": "tpu_..."
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Из профиля пользователя в разделе API / MCP или из ответа tupik_create_user/tupik_issue_user_token. | Должен начинаться с tpu_, быть не отозванным и не просроченным. Можно передать вместо него заголовок Authorization: Bearer .... |
Успешный ответ: ok: true, объект user, список scopes. Если токен неверный: invalid_user_token, user_token_expired или user_token_revoked.
Tool
tupik_create_user
Создаёт аккаунт автора или возвращает существующий аккаунт по email. Нужен сервисный ключ интеграции.
{
"jsonrpc": "2.0",
"id": "create-user-1",
"method": "tools/call",
"params": {
"name": "tupik_create_user",
"arguments": {
"api_key": "service_key_...",
"email": "author@example.com",
"name": "Иван Петров",
"password": "StrongPass123!",
"slug": "ivan-petrov",
"accepted_terms": true,
"accepted_privacy": true,
"return_password": false,
"profile": {
"role": "SEO-специалист",
"company": "AI Semantica",
"about": "Пишу о поиске, нейросетях и контент-маркетинге.",
"website": "https://example.com"
}
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
api_key | string | да | Выдаётся администратором Тупика интеграции, например Тунцу или AI Semantica. | Хранить только на backend. Можно передать заголовком X-Tupik-Api-Key. Нужен scope users:create. |
email | string | да | Email автора, от имени которого будут публиковаться материалы. | Должен быть валидным email. Если пользователь уже есть, дубль не создаётся. |
name | string | да | Фамилия и имя автора из анкеты, CRM, генератора или ручного ввода. | Минимум 2 символа. Это публичное имя в профиле и карточках. |
password | string | нет | Можно сгенерировать на стороне сервиса или не передавать. | Если короче 8 символов или отсутствует, API создаст временный пароль. Передавать пользователю безопасным каналом. |
slug | string | нет | ЧПУ профиля: латиница из имени, например ivan-petrov. | Если занят, API сделает уникальный вариант. Не используйте чисто цифровой slug. |
accepted_terms | boolean | да | Фиксируется сервисом после согласия пользователя с пользовательским соглашением. | Должно быть true, иначе будет legal_consent_required. |
accepted_privacy | boolean | да | Фиксируется сервисом после согласия пользователя с политикой персональных данных. | Должно быть true, иначе пользователь не создаётся. |
return_password | boolean | нет | Флаг для сервисов, которым нужно показать временный пароль пользователю. | Если true и пароль был сгенерирован, API вернёт temporary_password. Не логируйте его публично. |
profile.role | string | нет | Должность/роль автора: из анкеты пользователя. | Короткая строка. Показывается в профиле. |
profile.company | string | нет | Компания или проект автора. | Короткая строка. Можно оставить пустым. |
profile.about | string | нет | Описание автора из анкеты или профиля внешнего сервиса. | Обычный текст. Не вставляйте рекламный мусор и запрещённый контент. |
profile.website | string | нет | Сайт автора или компании. | Если не указать https://, API добавит его автоматически. |
Агенту: если пользователь уже зарегистрирован, не надо создавать нового. Вызов вернёт created: false и новый user_token для существующего профиля.
Tool
tupik_issue_user_token
Выдаёт пользовательский токен существующему автору. Используется, когда аккаунт уже есть, но сервису нужно действовать от имени автора.
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "tupik_issue_user_token",
"arguments": {
"api_key": "service_key_...",
"email": "author@example.com",
"ttl_days": 365
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
api_key | string | да | Сервисный ключ интеграции. | Нужен scope tokens:create. Можно передать заголовком. |
email | string | да | Email уже существующего пользователя Тупика. | Если пользователь не найден, ответ будет user_not_found. |
ttl_days | integer | нет | Сколько дней должен жить токен. | По умолчанию 365. Для тестов ставьте 1-7, для постоянной интеграции — 365. |
Tool
tupik_update_profile
Обновляет публичный профиль автора. Используйте после создания аккаунта, если нужно заполнить описание, роль, компанию, сайт и ЧПУ.
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "tupik_update_profile",
"arguments": {
"user_token": "tpu_...",
"name": "Иван Петров",
"about": "SEO-специалист, пишу о поиске и нейросетях.",
"role": "SEO-специалист",
"company": "AI Semantica",
"website": "https://example.com",
"slug": "ivan-petrov",
"avatar_image_url": "https://example.com/avatar.jpg"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Токен конкретного автора. | Нужен scope profile:write. |
name | string | нет | Фамилия и имя из профиля пользователя. | Обновляет публичное имя. Не используйте название компании вместо человека, если это личный профиль. |
about | string | нет | Краткое описание автора. | Обычный текст. В профиле показывается целиком. |
role | string | нет | Роль/должность: SEO-специалист, редактор, маркетолог. | Короткая строка. |
company | string | нет | Компания, агентство, проект. | Короткая строка. |
website | string | нет | Сайт автора или проекта. | URL. Если протокол не указан, API добавит https://. |
slug | string | нет | Желаемый адрес профиля. | Латиница, цифры, дефисы. Если занят, API подберёт уникальный. Не чаще раза в месяц в UI, но API сейчас технически обновляет через модель профиля. |
avatar_image_url / avatar_url / photo_url | string | нет | Публичный URL фотографии автора. Его может отдать ваш генератор, CRM, медиахранилище или предварительный загрузчик файлов. | Только http/https. Сервер Тупика скачивает изображение, сохраняет в пользовательские загрузки и использует как аватар профиля. Лучше квадратное фото, лицо и плечи по центру. |
avatar_image_base64 / avatar_base64 / photo_base64 | string | нет | Файл аватара прямо в JSON, если внешняя ссылка недоступна. | Можно передавать чистый base64 или data URL. Используйте изображения разумного размера; сервер сжимает картинку, но не надо отправлять многомегабайтные оригиналы. |
Tool
tupik_list_article_categories
Возвращает актуальный список категорий статей. Агент должен вызывать этот метод перед публикацией статьи, если не уверен, какую категорию указать.
{
"jsonrpc": "2.0",
"id": "article-categories-1",
"method": "tools/call",
"params": {
"name": "tupik_list_article_categories",
"arguments": {}
}
}
Метод не требует user_token и api_key. Это публичный справочник для выбора категории.
| Поле ответа | Тип | Откуда берётся | Как использовать | |
|---|---|---|---|---|
categories[].id | integer | нет | Внутренний id категории из таблицы категорий статей InstantCMS. | Передавайте как category_id, если агенту нужна точная привязка. Не выдумывайте id вручную: сначала получите список этим методом. |
categories[].title | string | нет | Название категории из админки и формы добавления статьи. | Передавайте как category_title. Значение должно совпадать с названием из ответа, например Маркетинг. |
categories[].slug | string | нет | ЧПУ категории, то есть часть URL категории после /articles/. | Передавайте как category_slug, если агент работает с URL. Например категория /articles/marketing даст slug marketing. |
categories[].url | string | нет | Публичная ссылка на категорию. | Используйте для интерфейса, проверки или показа человеку. Для публикации статьи лучше передавать id, title или slug. |
categories[].level | integer | нет | Уровень вложенности категории, если дерево категорий это поддерживает. | Нужен только для красивого отображения дерева. Для публикации статьи необязателен. |
categories[].parent_id | integer | нет | id родительской категории, если есть. | Нужен для построения дерева. Если 0, категория верхнего уровня или родитель неизвестен. |
Логика для MCP-агента: сначала вызвать tupik_list_article_categories, выбрать наиболее близкую категорию по смыслу, затем вызвать tupik_publish_article с одним из параметров: category_id, category_title или category_slug. Самый надёжный вариант — category_id.
Tool
tupik_publish_article
Создаёт статью или черновик. Если агент публикует материал из Тунца или AI Semantica, это основной метод.
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "tupik_publish_article",
"arguments": {
"user_token": "tpu_...",
"title": "Название статьи",
"lead": "Короткое описание от 40 до 300 символов",
"content_html": "<p>Текст статьи</p>",
"category_title": "Маркетинг",
"cover_image_url": "https://example.com/cover.jpg",
"status": "publish",
"slug": "nazvanie-stati"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Токен автора статьи. | Нужен scope articles:create. Для публикации, а не черновика, нужен ещё articles:publish. |
title | string | да | Заголовок материала из редактора или генератора контента. | Минимум 3 символа. API обрежет до 100 символов для поля title. Не вставляйте HTML. |
lead | string | нет | Лид-абзац/краткое описание статьи. | Желательно 40-300 символов. Если короче 40, API сам возьмёт начало статьи. Используется в карточках и meta description. |
content_html | string | да | HTML тела статьи из редактора, генератора или CMS внешнего сервиса. | Минимум 40 символов текста после удаления HTML. Разрешены базовые теги: p, h2-h4, ul, ol, li, strong, em, blockquote, a, img, table. Скрипты и стили удаляются. |
category_id | integer | нет | ID категории из ответа tupik_list_article_categories. | Самый надёжный способ указать категорию. Не придумывайте число вручную: сначала получите список категорий и возьмите categories[].id. |
category_title | string | нет | Название категории статьи из админки Тупика и формы добавления статьи. | Например Маркетинг, Медицина, AI и автоматизация. Должно точно совпасть с существующей категорией. Если не найдено — category_not_found. |
category_slug | string | нет | ЧПУ категории статьи, если агент знает его. | Альтернатива category_title. Например marketing. |
cover_image_url | string | нет | Публичный URL обложки, доступный серверу Тупика. | Только http/https. Сервер скачает картинку до 10 МБ и сожмёт её. Лучше горизонтальная обложка 1600×500 или близко к 16:5. |
cover_image_base64 | string | нет | Картинка, переданная прямо в JSON. | Можно передавать как чистый base64 или data URL. До 10 МБ до обработки. Используйте, если картинка не доступна по публичному URL. |
cover_url | string | нет | Готовый URL картинки, которую не нужно скачивать. | Запасной вариант. Лучше использовать cover_image_url или cover_image_base64, чтобы Тупик сам сжал файл. |
status | string | нет | Решение агента: публиковать сразу или сохранить черновик. | Допустимо publish или draft. По умолчанию publish. |
slug | string | нет | Желаемый адрес статьи. | Латиница, цифры, дефисы. API добавит id статьи в начало и сделает slug уникальным. |
seo_title | string | нет | SEO-title, если внешний сервис хочет задать его вручную. | До 255 символов. Если не передать, будет Название статьи | Тупик. |
seo_description | string | нет | SEO-description. | До 255 символов. Если не передать, используется lead. |
seo_keywords | string | нет | SEO-ключи. | До 255 символов. Можно не использовать. |
Откуда взять категорию: категории статей управляются в админке Тупика в разделе категорий контента и видны пользователю в форме /articles/add. MCP-агент должен выбирать одну существующую категорию, а не создавать новую строку произвольно.
Tool
tupik_update_article
Редактирует уже созданную статью или черновик текущего автора. Агент должен передать идентификатор статьи и только те поля, которые реально нужно изменить.
{
"jsonrpc": "2.0",
"id": "article-update-1",
"method": "tools/call",
"params": {
"name": "tupik_update_article",
"arguments": {
"user_token": "tpu_...",
"article_id": 38,
"title": "Новое название статьи",
"content_html": "<p>Обновленный текст статьи</p>",
"cover_image_url": "https://example.com/new-cover.jpg",
"status": "publish"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Токен автора, которому принадлежит статья. | Нужен scope articles:create. Для перевода в публикацию нужен scope articles:publish. Чужую статью редактировать нельзя. |
article_id | integer | нет | Число в URL статьи после /articles/. Например в /articles/38-diafragma... id равен 38. Также id возвращается в ответе tupik_publish_article. | Передайте article_id или article_slug. Если не передать ни один идентификатор, будет article_id_required. |
article_slug | string | нет | Полный slug статьи из URL без домена и без /articles/, например 38-diafragma-myshca.... | Альтернатива article_id. Если slug не найден, будет article_not_found. |
title | string | нет | Новое название статьи. | Минимум 3 символа, максимум 100 в основном поле. HTML нельзя. |
lead | string | нет | Новый лид/краткое описание. | Желательно 40-300 символов. Если передать слишком короткий лид вместе с новым текстом, API соберёт лид из текста. |
content_html | string | нет | Новый HTML-текст статьи. | Если поле передано, после очистки HTML должно остаться минимум 40 символов текста. Скрипты, стили и опасные атрибуты удаляются. |
category_id | integer | нет | ID категории статей из CMS, если интеграция его знает. | Проще и безопаснее для агента использовать category_title или category_slug. |
category_title | string | нет | Название существующей категории статей из формы добавления статьи или админки. | Категория должна существовать. Новые категории через этот метод не создаются. |
category_slug | string | нет | ЧПУ существующей категории статей. | Альтернатива названию категории. |
cover_image_url | string | нет | URL новой обложки. | Сервер скачает, сохранит и сожмёт картинку. Лучше горизонтальная 1600×500 или близко к 16:5. |
cover_image_base64 | string | нет | Новая обложка прямо в JSON. | Можно чистый base64 или data URL. Не отправляйте огромные оригиналы. |
status | string | нет | Что сделать после редактирования. | publish — опубликовано, draft — черновик. Если не передать, текущий статус обычно сохраняется. |
slug | string | нет | Новый желаемый адрес статьи. | Латиница, цифры, дефисы. API сохранит формат с id в начале и сделает slug уникальным. |
seo_title / seo_description / seo_keywords | string | нет | SEO-поля, если внешний сервис управляет мета-тегами. | Каждое поле до 255 символов. |
Tool
tupik_delete_article
Снимает свою статью с публикации. Это мягкое удаление: материал скрывается, но запись остаётся в базе для истории, редиректов и возможного восстановления администратором.
{
"jsonrpc": "2.0",
"id": "article-delete-1",
"method": "tools/call",
"params": {
"name": "tupik_delete_article",
"arguments": {
"user_token": "tpu_...",
"article_slug": "38-diafragma-myshca-o-kotoroi-vspominayut-togda-kogda-nikogda"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Токен автора статьи. | Чужую статью удалить нельзя. |
article_id | integer | нет | ID статьи из URL или из ответа API. | Передайте article_id или article_slug. |
article_slug | string | нет | Slug статьи из URL. | Передайте, если id неизвестен. |
Tool
tupik_upsert_speaker
Создаёт или обновляет карточку спикера. У одного пользователя может быть только одна карточка: повторный вызов обновит существующую.
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "tupik_upsert_speaker",
"arguments": {
"user_token": "tpu_...",
"name": "Иван Петров",
"short_position": "SEO и GEO-специалист",
"city": "Москва",
"can_travel": true,
"topics": ["SEO", "GEO / продвижение в нейросетях"],
"formats": ["Конференция", "Вебинар", "Подкаст-запись"],
"about": "<p>Помогаю компаниям получать видимость в поиске и нейросетях.</p>",
"conditions": "<p>Выступаю с докладами и мастер-классами.</p>",
"website": "https://example.com",
"video_url": "https://example.com/video",
"request_email": "speaker@example.com",
"photo_url": "https://example.com/photo.jpg"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Токен пользователя, которому принадлежит карточка. | Нужен scope speakers:write. |
name / title | string | да | Имя спикера из профиля или анкеты. | Минимум 2 символа. В MCP schema поле называется name, REST также принимает title. |
short_position | string | нет | Короткое позиционирование: кто человек и про что выступает. | Лучше 1-2 строки. Показывается в карточке и списке спикеров. |
city | string | нет | Город спикера. | Свободная строка: Москва, Санкт-Петербург, Онлайн. |
can_travel | boolean | нет | Ответ из анкеты: может ли приехать в другой город. | true или false. |
topics | array<string> | да | Темы выступлений из справочника тем спикеров/конференций. | Нужна хотя бы одна тема, иначе speaker_topics_required. Используйте существующие темы из формы спикера. Если старой темы нет в новом дереве, её нужно сначала добавить в справочник. |
topic_ids | array<int> | нет | ID тем из таблицы тем, если интеграция умеет получать id. | Более надёжно, чем title, но публичного метода получения id пока нет. До появления справочника используйте topics. |
formats | array<string> | нет | Форматы выступлений из формы спикера. | Например Конференция, Вебинар, Подкаст-запись, Клубная встреча. |
about / about_html / content_html | string | нет | Описание спикера. | Можно HTML с базовыми тегами. Скрипты и стили удаляются. |
conditions / conditions_html | string | нет | Условия участия. | Можно HTML с базовым форматированием. |
website / contacts_public | string | нет | Публичный сайт или контакт. | URL или email. Если это URL без протокола, API добавит https://. |
video_url | string | нет | Ссылка на видео выступления. | Публичный URL. Пока хранится ссылкой. |
request_email / email | string | да | Email для заявок организаторов. | Должен быть валидным email. Если не передать, используется email пользователя. |
photo_url / photo_image_url | string | нет | Публичный URL фото спикера. | Лучше квадратное фото: лицо и плечи по центру. Сервер скачает и сожмёт изображение. |
photo_base64 / photo_image_base64 | string | нет | Фото в base64. | До 10 МБ. Используйте, если фото недоступно по URL. |
slug | string | нет | Желаемый URL карточки спикера. | Если карточка уже есть, старый slug сохраняется. Если новая — API сделает уникальный slug. |
Tool
tupik_create_event
Добавляет конференцию/мероприятие на модерацию. После сохранения администраторы получают уведомление.
{
"jsonrpc": "2.0",
"id": 6,
"method": "tools/call",
"params": {
"name": "tupik_create_event",
"arguments": {
"user_token": "tpu_...",
"title": "Digital-конференция 2026",
"event_type": "Конференция",
"event_date": "2026-08-01",
"event_date_end": "2026-08-02",
"city": "Москва",
"format": "Офлайн",
"topics": ["SEO", "GEO / продвижение в нейросетях"],
"lead": "Конференция о поиске, нейросетях и продвижении брендов в AI-ответах.",
"description": "<p>В программе доклады, панели и разборы кейсов.</p>",
"source_url": "https://example.com/event",
"needs_speakers": "yes",
"speaker_terms": "free",
"deadline": "2026-07-20",
"cover_image_url": "https://example.com/event-cover.jpg"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Токен пользователя, который добавляет мероприятие. | Нужен scope events:create. |
title | string | да | Название конференции/мероприятия. | Минимум 3 символа. Не вставляйте HTML. |
event_type / type | string | да | Тип из справочника форматов/типов конференций. | Например Конференция, Вебинар, Форум, Митап, Подкаст-запись. |
event_date / date_start / date | string | да | Дата начала мероприятия. | Формат лучше YYYY-MM-DD. Любая распознаваемая дата будет приведена к этому формату. |
event_date_end / date_end | string | нет | Дата окончания, если мероприятие идёт несколько дней. | Не может быть раньше даты начала, иначе event_date_end_before_start. |
city | string | да | Город мероприятия или Онлайн. | Свободная строка. Для онлайн-мероприятий можно ставить Онлайн. |
format | string | да | Формат проведения. | Например Онлайн, Офлайн, Гибрид. |
topics / topic | array<string> | да | Темы из дерева тем конференций/спикеров. | Максимум 8 тем сохраняется. Нужна хотя бы одна, иначе event_topics_required. |
topic_ids | array<int> | нет | ID тем, если известны интеграции. | Пока публичного справочника id нет, поэтому безопаснее передавать названия в topics. |
lead / summary | string | да | Краткое описание мероприятия. | Минимум 30 символов текста. API сохранит до 400 символов. |
description / description_html / content_html | string | нет | Полное описание. | Можно HTML с базовыми тегами. Скрипты и стили удаляются. |
source_url / url / website | string | да | Официальная страница мероприятия или источник. | Должен быть валидным URL, иначе event_source_url_required. |
needs_speakers | string | нет | Нужны ли спикеры. | Допустимо yes, no, unknown. Также принимаются да, нет, true, false. |
speaker_terms | string | нет | Условия для спикеров. | Используется только если needs_speakers = yes. Допустимо free — бесплатно спикерам, speaker_pays — спикеры платят, paid — спикерам платят. |
deadline | string | нет | Дедлайн подачи заявки спикера. | Учитывается только если нужны спикеры. Формат лучше YYYY-MM-DD. |
cover_image_url | string | нет | URL превью мероприятия. | Публичная картинка до 10 МБ. Лучше горизонтальная. |
cover_image_base64 / preview_image_base64 | string | нет | Превью в base64. | До 10 МБ до обработки. |
organizer | string | нет | Организатор мероприятия. | Короткая строка. |
organizer_contact / contact | string | нет | Контакт организатора. | Email, Telegram, сайт или иной контакт. |
conditions / conditions_html | string | нет | Условия участия. | Можно HTML с базовым форматированием. |
audience | string | нет | Ожидаемая аудитория. | Свободный текст. |
slug | string | нет | Желаемый URL мероприятия. | Если не передать, API создаст по названию. |
Tool
tupik_update_event
Редактирует мероприятие текущего пользователя. После изменения карточка снова уходит на модерацию, чтобы в каталог не попадал мусор и подменённые рекламные события.
{
"jsonrpc": "2.0",
"id": "event-update-1",
"method": "tools/call",
"params": {
"name": "tupik_update_event",
"arguments": {
"user_token": "tpu_...",
"event_id": 12,
"title": "Обновлённая конференция",
"event_date": "2026-08-10",
"event_date_end": "2026-08-11",
"needs_speakers": "yes",
"speaker_terms": "paid",
"deadline": "2026-07-25"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Токен пользователя, который создал мероприятие. | Нужен scope events:create. Чужие мероприятия редактировать нельзя. |
event_id | integer | нет | ID мероприятия из ответа tupik_create_event или из внутренней карточки. | Передайте event_id или event_slug. Если не передать ни один идентификатор, будет event_id_required. |
event_slug | string | нет | Slug мероприятия из URL без домена и без /events/. | Альтернатива id. Если не найдено, будет event_not_found. |
title | string | нет | Новое название мероприятия. | Минимум 3 символа. |
event_type / type | string | нет | Тип мероприятия. | Например Конференция, Вебинар, Форум, Митап. |
event_date / date_start / date | string | нет | Дата начала. | Формат лучше YYYY-MM-DD. |
event_date_end / date_end | string | нет | Дата окончания для многодневных событий. | Не может быть раньше даты начала. |
city | string | нет | Город или Онлайн. | Свободная строка. |
format | string | нет | Формат проведения. | Онлайн, Офлайн, Гибрид. |
topics | array<string> | нет | Темы из дерева тем конференций. | Максимум 8. Если передали массив, хотя бы одна тема должна существовать. |
lead / summary | string | нет | Краткое описание. | Минимум 30 символов, до 400 сохраняется в карточке. |
description / description_html / content_html | string | нет | Полное описание. | Можно HTML с базовым форматированием. |
conditions / conditions_html | string | нет | Условия участия. | Можно HTML с базовым форматированием. |
source_url / url / website | string | нет | Сайт мероприятия. | Должен быть валидным URL. |
needs_speakers | string | нет | Нужны ли спикеры. | yes, no, unknown. Если не yes, дедлайн и условия спикеров очищаются. |
speaker_terms | string | нет | Условия для спикеров. | Только если needs_speakers = yes. Значения: free, speaker_pays, paid. |
deadline | string | нет | Дедлайн заявки спикера. | Только если нужны спикеры. Формат лучше YYYY-MM-DD. |
cover_image_url / cover_image_base64 | string | нет | Новая картинка-превью мероприятия. | Сервер сохраняет и сжимает файл. Лучше горизонтальная обложка. |
slug | string | нет | Новый желаемый URL мероприятия. | Латиница, цифры, дефисы; API сделает уникальным. |
Tool
tupik_delete_event
Скрывает своё мероприятие из каталога. Используйте, если событие отменили, добавили по ошибке или нужно убрать карточку.
{
"jsonrpc": "2.0",
"id": "event-delete-1",
"method": "tools/call",
"params": {
"name": "tupik_delete_event",
"arguments": {
"user_token": "tpu_...",
"event_slug": "digital-konferencija-2026"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Токен владельца мероприятия. | Чужое мероприятие удалить нельзя. |
event_id | integer | нет | ID мероприятия из ответа API. | Передайте event_id или event_slug. |
event_slug | string | нет | Slug из URL мероприятия. | Передайте, если id неизвестен. |
Tool
tupik_subscribe_events
Создаёт подписку на новые конференции по фильтрам. После сохранения пользователь получает уведомления на сайте, а API сразу возвращает текущие подходящие мероприятия.
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "tupik_subscribe_events",
"arguments": {
"user_token": "tpu_...",
"title": "SEO и GEO онлайн",
"topics": ["SEO", "GEO / продвижение в нейросетях"],
"cities": ["Онлайн", "Москва"],
"formats": ["Онлайн", "Гибрид"],
"event_types": ["Конференция", "Вебинар"],
"needs_speakers": "yes",
"date_from": "2026-06-01",
"date_to": "2026-12-31"
}
}
}
| Параметр | Тип | Обяз. | Откуда взять | Ограничения и смысл |
|---|---|---|---|---|
user_token | string | да | Токен пользователя, которому создаётся подписка. | Нужен scope events:subscribe. |
title | string | нет | Название фильтра для пользователя. | Если не передать, будет стандартное название. |
topics / topic | array<string> | нет | Темы конференций из дерева тем. | Можно несколько. Если все фильтры пустые, будет subscription_filter_required. |
cities / city | array<string> | нет | Города, которые интересны пользователю. | Например Москва, Санкт-Петербург, Онлайн. |
formats / format | array<string> | нет | Форматы проведения. | Например Онлайн, Офлайн, Гибрид. |
event_types / event_type | array<string> | нет | Типы мероприятий. | Например Конференция, Вебинар, Подкаст-запись. |
needs_speakers | string | нет | Фильтр по поиску спикеров. | Обычно yes, если пользователь хочет выступать. Можно оставить пустым. |
date_from | string | нет | Начало периода поиска. | Формат лучше YYYY-MM-DD. |
date_to | string | нет | Конец периода поиска. | Формат лучше YYYY-MM-DD. |
Важно: в подписке должен быть хотя бы один фильтр: тема, город, формат, тип или статус “нужны спикеры”.
Справочники
Откуда брать категории, темы, форматы и id
Категории статей
category_id, category_title и category_slug относятся только к статьям. Их нужно брать из метода tupik_list_article_categories или REST-адреса /api/v1/articles/categories.
Если агент не уверен в категории, он должен сначала запросить справочник. Если передать неверную строку или id, будет category_not_found.
Темы спикеров и конференций
topics — это названия тем из дерева тем спикеров/конференций. Сейчас они выбираются в формах спикера и конференции.
Пока нет публичного метода “получить список тем”. Поэтому агент должен использовать заранее известный справочник или значения, которые пользователь выбрал в интерфейсе.
ID в ответах
user.id, article.id, speaker.id, event.id — это внутренние id записей в Тупике. Они возвращаются API после создания или проверки.
Не путать с JSON-RPC id. JSON-RPC id нужен только для связи запроса и ответа.
Что ещё нужно добавить
Категории статей уже доступны через tupik_list_article_categories. Для полной интеграции дальше стоит добавить отдельные справочные методы: список тем, список форматов, список типов мероприятий и проверку доступности slug.
Ошибки
Типовые ответы с ошибками
| Ошибка | Что значит | Что делать агенту |
|---|---|---|
invalid_json | Тело запроса не является валидным JSON. | Пересобрать JSON, проверить кавычки, экранирование HTML и base64. |
api_key_required / invalid_api_key | Нет сервисного ключа или он неверный. | Не просить пользователя вводить его публично. Проверить backend-настройки интеграции. |
user_token_required | Действию нужен токен автора. | Сначала вызвать tupik_create_user или tupik_issue_user_token. |
scope_denied | У токена нет нужного права. | Запросить новый токен с нужными scopes или показать ошибку владельцу интеграции. |
legal_consent_required | При создании пользователя не переданы согласия. | Получить согласия пользователя с соглашением и политикой персональных данных. |
category_not_found | Категория статьи не найдена. | Использовать существующую категорию из админки или не передавать категорию. |
content_too_short | Текст статьи короче 40 символов. | Передать полноценный HTML-текст. |
negative_reputation_cannot_publish | Автор с отрицательной репутацией не может публиковать. | Сохранить черновик невозможно как публикацию; показать человеку причину. |
daily_article_publish_limit | Автор уже опубликовал 3 статьи за текущие сутки по Москве. | Не повторять публикацию автоматически. Показать сообщение: больше 3 публикаций в сутки доступно только для платных аккаунтов, почта ne@to-pick.ru. |
speaker_topics_required | В карточке спикера нет тем. | Передать минимум одну тему из справочника. |
event_lead_too_short | Краткое описание мероприятия короче 30 символов. | Сформировать нормальный лид. |
event_source_url_required | Нет валидной ссылки на источник мероприятия. | Передать официальный URL события или страницу-источник. |
event_topics_required | У мероприятия нет тем. | Передать минимум одну тему. |
invalid_speaker_terms | Неверное значение условий для спикеров. | Использовать только free, speaker_pays, paid. |
subscription_filter_required | Подписка создана без фильтров. | Передать хотя бы тему, город, формат, тип или needs_speakers. |
План улучшений
Что ещё нужно расписать и добавить
- Публичные справочники: категории статей уже доступны через
tupik_list_article_categories. Следом стоит добавитьtupik_list_topics,tupik_list_event_types,tupik_list_formats, чтобы агент не угадывал названия. - Проверка slug: добавить метод, который заранее проверяет доступность ЧПУ для пользователя, статьи, спикера или конференции.
- Редактирование созданных сущностей: сейчас API создаёт статьи и конференции, а для спикера делает upsert. Нужны отдельные методы обновления статей и конференций.
- Статистика: добавить tools для показов, просмотров, дочитываний, лайков, комментариев и избранного по статьям автора.
- Файлы: добавить отдельный метод загрузки изображения, который вернёт готовый URL, чтобы агент мог сначала загрузить картинку, а потом использовать её в статье, спикере или мероприятии.
- OpenAPI: подготовить
/api/openapi.json, чтобы программисты могли подключать REST API автоматически. - WebMCP widget: при необходимости добавить клиентский слой WebMCP для браузерных агентов. Текущая страница уже раскрывает инструменты и MCP endpoint, но не заменяет локальный WebSocket-мост.
Manifest
Живой список tools
Ниже находится JSON, который отдаёт текущий MCP Server. Его можно использовать для автоматической проверки схем.
{
"name": "Tupik MCP Server",
"version": "0.1.0",
"protocol": "jsonrpc",
"endpoint": "https:\/\/to-pick.ru\/mcp\/server",
"tools": [
{
"name": "tupik_get_me",
"description": "Проверить личный API-токен Тупика и получить данные текущего пользователя.",
"inputSchema": {
"type": "object",
"properties": {
"user_token": {
"type": "string",
"description": "Личный токен пользователя tpu_... Можно передать вместо Authorization: Bearer."
}
}
}
},
{
"name": "tupik_create_user",
"description": "Создать пользователя Тупика для внешнего сервиса. Требует сервисный X-Tupik-Api-Key.",
"inputSchema": {
"type": "object",
"required": [
"email",
"name"
],
"properties": {
"api_key": {
"type": "string",
"description": "Сервисный API-ключ интеграции."
},
"email": {
"type": "string"
},
"name": {
"type": "string"
},
"password": {
"type": "string"
},
"slug": {
"type": "string"
}
}
}
},
{
"name": "tupik_issue_user_token",
"description": "Получить пользовательский токен для существующего пользователя. Требует сервисный X-Tupik-Api-Key.",
"inputSchema": {
"type": "object",
"required": [
"email"
],
"properties": {
"api_key": {
"type": "string"
},
"email": {
"type": "string"
},
"ttl_days": {
"type": "integer"
}
}
}
},
{
"name": "tupik_update_profile",
"description": "Обновить профиль пользователя Тупика: имя, описание, роль, компанию, сайт, ЧПУ.",
"inputSchema": {
"type": "object",
"required": [
"user_token"
],
"properties": {
"user_token": {
"type": "string"
},
"name": {
"type": "string"
},
"about": {
"type": "string"
},
"role": {
"type": "string"
},
"company": {
"type": "string"
},
"website": {
"type": "string"
},
"slug": {
"type": "string"
},
"avatar_image_url": {
"type": "string"
},
"avatar_image_base64": {
"type": "string"
},
"avatar_url": {
"type": "string"
},
"avatar_base64": {
"type": "string"
}
}
}
},
{
"name": "tupik_list_article_categories",
"description": "Получить список категорий статей Тупика для публикации: category_id, category_title, category_slug и публичный URL категории.",
"inputSchema": {
"type": "object",
"properties": []
}
},
{
"name": "tupik_publish_article",
"description": "Создать статью или черновик в Тупике с HTML-текстом, лидом, категорией и обложкой.",
"inputSchema": {
"type": "object",
"required": [
"user_token",
"title",
"content_html"
],
"properties": {
"user_token": {
"type": "string"
},
"title": {
"type": "string"
},
"lead": {
"type": "string"
},
"content_html": {
"type": "string"
},
"category_id": {
"type": "integer"
},
"category_title": {
"type": "string"
},
"category_slug": {
"type": "string"
},
"cover_image_url": {
"type": "string"
},
"cover_image_base64": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"publish",
"draft"
]
},
"slug": {
"type": "string"
}
}
}
},
{
"name": "tupik_update_article",
"description": "Отредактировать свою статью или черновик в Тупике. Передайте article_id или article_slug и только те поля, которые нужно изменить.",
"inputSchema": {
"type": "object",
"required": [
"user_token"
],
"properties": {
"user_token": {
"type": "string"
},
"article_id": {
"type": "integer"
},
"article_slug": {
"type": "string"
},
"title": {
"type": "string"
},
"lead": {
"type": "string"
},
"content_html": {
"type": "string"
},
"category_title": {
"type": "string"
},
"category_slug": {
"type": "string"
},
"category_id": {
"type": "integer"
},
"cover_image_url": {
"type": "string"
},
"cover_image_base64": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"publish",
"draft"
]
},
"slug": {
"type": "string"
},
"seo_title": {
"type": "string"
},
"seo_description": {
"type": "string"
},
"seo_keywords": {
"type": "string"
}
}
}
},
{
"name": "tupik_delete_article",
"description": "Удалить свою статью или черновик из публикации. Передайте article_id или article_slug.",
"inputSchema": {
"type": "object",
"required": [
"user_token"
],
"properties": {
"user_token": {
"type": "string"
},
"article_id": {
"type": "integer"
},
"article_slug": {
"type": "string"
}
}
}
},
{
"name": "tupik_upsert_speaker",
"description": "Создать или обновить карточку спикера пользователя.",
"inputSchema": {
"type": "object",
"required": [
"user_token",
"name"
],
"properties": {
"user_token": {
"type": "string"
},
"name": {
"type": "string"
},
"short_position": {
"type": "string"
},
"city": {
"type": "string"
},
"can_travel": {
"type": "boolean"
},
"topics": {
"type": "array",
"items": {
"type": "string"
}
},
"formats": {
"type": "array",
"items": {
"type": "string"
}
},
"about": {
"type": "string"
},
"conditions": {
"type": "string"
},
"website": {
"type": "string"
},
"video_url": {
"type": "string"
},
"photo_url": {
"type": "string"
},
"photo_base64": {
"type": "string"
}
}
}
},
{
"name": "tupik_create_event",
"description": "Добавить конференцию или мероприятие в Тупик. Мероприятие уходит на модерацию.",
"inputSchema": {
"type": "object",
"required": [
"user_token",
"title",
"event_date",
"format",
"event_type",
"city",
"lead",
"source_url"
],
"properties": {
"user_token": {
"type": "string"
},
"title": {
"type": "string"
},
"event_type": {
"type": "string"
},
"event_date": {
"type": "string"
},
"event_date_end": {
"type": "string"
},
"city": {
"type": "string"
},
"format": {
"type": "string"
},
"topics": {
"type": "array",
"items": {
"type": "string"
}
},
"lead": {
"type": "string"
},
"description": {
"type": "string"
},
"source_url": {
"type": "string"
},
"needs_speakers": {
"type": "string"
},
"speaker_terms": {
"type": "string"
},
"deadline": {
"type": "string"
},
"cover_image_url": {
"type": "string"
},
"cover_image_base64": {
"type": "string"
}
}
}
},
{
"name": "tupik_update_event",
"description": "Отредактировать своё мероприятие или конференцию. Передайте event_id или event_slug и только те поля, которые нужно изменить.",
"inputSchema": {
"type": "object",
"required": [
"user_token"
],
"properties": {
"user_token": {
"type": "string"
},
"event_id": {
"type": "integer"
},
"event_slug": {
"type": "string"
},
"title": {
"type": "string"
},
"event_type": {
"type": "string"
},
"event_date": {
"type": "string"
},
"event_date_end": {
"type": "string"
},
"city": {
"type": "string"
},
"format": {
"type": "string"
},
"topics": {
"type": "array",
"items": {
"type": "string"
}
},
"lead": {
"type": "string"
},
"description": {
"type": "string"
},
"conditions": {
"type": "string"
},
"source_url": {
"type": "string"
},
"needs_speakers": {
"type": "string"
},
"speaker_terms": {
"type": "string"
},
"deadline": {
"type": "string"
},
"cover_image_url": {
"type": "string"
},
"cover_image_base64": {
"type": "string"
},
"slug": {
"type": "string"
}
}
}
},
{
"name": "tupik_delete_event",
"description": "Удалить своё мероприятие или конференцию. Передайте event_id или event_slug.",
"inputSchema": {
"type": "object",
"required": [
"user_token"
],
"properties": {
"user_token": {
"type": "string"
},
"event_id": {
"type": "integer"
},
"event_slug": {
"type": "string"
}
}
}
},
{
"name": "tupik_subscribe_events",
"description": "Создать подписку на новые конференции по темам, городам, форматам и типам.",
"inputSchema": {
"type": "object",
"required": [
"user_token"
],
"properties": {
"user_token": {
"type": "string"
},
"title": {
"type": "string"
},
"topics": {
"type": "array",
"items": {
"type": "string"
}
},
"cities": {
"type": "array",
"items": {
"type": "string"
}
},
"formats": {
"type": "array",
"items": {
"type": "string"
}
},
"event_types": {
"type": "array",
"items": {
"type": "string"
}
},
"needs_speakers": {
"type": "string"
},
"date_from": {
"type": "string"
},
"date_to": {
"type": "string"
}
}
}
}
]
}