Skip to main content
Glama

PWA Sticker MCP · общая библиотека стикеров

Позволяет человеку и ИИ использовать одну и ту же библиотеку стикеров PWA: человек нажимает в панели и отравляет, модель через MCP вызывает ту же картику и отравляет.

Ображённая к человеку панель PWA и ображённый к ИИ сервер MCP разделяют одну библиотеку стикеров и один контракт вложений.

Эта публичная версия выделена из действующих функций реального семейного PWA и сохраняет самое полезное:

  • Панель стикеров PWA: загрузка, ленивая загрузка, сортировка по недавнему использованию, вход в режим управления долгим нажатием или с клавиатуры, удаление

  • Удобная для iOS квадратная сетка: не зависит от aspect-ratio, который легко схлопывается в прокручиваемом grid

  • Статическое превью WebP в панели: при наличии ffmpeg автоматически генерируется первый кадр 192px, но фактически отравляется исходное изображение или исходный GIF

  • Три инструмента MCP: list_stickers, send_sticker, add_sticker

  • Сообщения только с изображением: отравка { text: "", attachments: [...] } без необходимости подделывать текст-заполнитель

  • Локальный Relay/demo, который можно сразу запустить, чтобы сначала увидеть полный цикл, а затем подключить свой чат-бэкенд

Репозиторий не содежит наших семейных стикеров, переписки, доменов, учётных записей или учётных данных.

Запуск

Требуется Node.js 20+; ffmpeg опционален.

npm install
npm run demo

Откройте http://127.0.0.1:8787, добавьте изображение и нажмите на него — страница покажет только что отравленное сообщение с изображением (image-only). Данные по умолчанию сохраняются в .data/ внутри проекта; этот каталог уже исключён через .gitignore.

Этот запуск также предоставляет MCP рабочий Relay. Откройте ещё один терминал:

STICKER_RELAY_URL=http://127.0.0.1:8787 npm run mcp

Related MCP server: Firmament Open Brain

Подключение к MCP-клиенту

Claude Desktop, Clude Code или другие клиенты, подерживающие stdio MCP, могут использовать:

{
  "mcpServers": {
    "stickers": {
      "command": "node",
      "args": ["/absolute/path/to/pwa-sticker-mcp/src/mcp-server.js"],
      "env": {
        "STICKER_RELAY_URL": "https://chat.example.com",
        "STICKER_TOKEN": "your-relay-token",
        "STICKER_STICKERS_PATH": "/api/stickers",
        "STICKER_UPLOAD_PATH": "/api/upload",
        "STICKER_SEND_PATH": "/api/send"
      }
    }
  }
}

Семантика инструментов:

  • list_stickers(query?): выводит общую библиотеку, можно филтровать по имени

  • send_sticker(query): находит по id, полному имени или уникальному ключевому слову и отравляет

  • add_sticker(path, name?): регистрирует локальное изображение на машине модели в общей библиотеке, но не отравляет

Если ключевое слово соответствует нескольким стикерам, инструмент просит модель уточнить запрос и не выбирает сам.

Как встроить панель в существующий PWA

Подключите модуль и стили:

<link rel="stylesheet" href="/sticker-drawer.css">

<div id="stickerDrawer"></div>
<button
  id="stickerButton"
  type="button"
  aria-controls="stickerDrawer"
  aria-expanded="false"
  aria-pressed="false"
>
  表情包
</button>

<script type="module">
  import { StickerDrawer } from '/sticker-drawer.js'

  new StickerDrawer({
    root: document.querySelector('#stickerDrawer'),
    trigger: document.querySelector('#stickerButton'),
    apiBase: 'https://chat.example.com',
    headers: () => ({ Authorization: `Bearer ${getRelayToken()}` }),
    async onSend(attachment) {
      await sendMessage({ text: '', attachments: [attachment] })
    },
    onNotice(message, kind) {
      showToast(message, kind)
    }
  })
</script>

Если опустить onSend, компонент отправляет тот же payload методом POST на endpoint send. Endpoint можно переименовать:

new StickerDrawer({
  root,
  trigger,
  endpoints: {
    stickers: '/app/stickers',
    upload: '/app/upload',
    send: '/app/send'
  }
})

Компонент использует нейтральные CSS-переменные и не требует от интегратора использовать цвета demo:

:root {
  --psm-surface: #171717;
  --psm-surface-muted: #242424;
  --psm-ink: #fafafa;
  --psm-muted: #b8b8b8;
  --psm-accent: #f1b657;
  --psm-danger: #e26363;
  --psm-line: #343434;
}

Контракт Relay API

Существующему бэкенду не обязательно использовать demo-сервер; достаточно реализовать следующие пять запросов:

GET    /api/stickers
POST   /api/upload?name=<filename>        raw image body
POST   /api/stickers                      register uploaded metadata
POST   /api/stickers/<id>/use             update recent-use order
DELETE /api/stickers/<id>
POST   /api/send                          send an image attachment

GET /api/stickers возвращает:

{
  "stickers": [
    {
      "id": "abc123",
      "name": "wave hello",
      "url": "/uploads/wave.gif",
      "thumb_url": "/uploads/sticker-thumb-wave.webp",
      "mime": "image/gif",
      "width": 320,
      "height": 240,
      "last_used": 1787800000
    }
  ]
}

Основной payload для POST /api/send:

{
  "text": "",
  "attachments": [
    {
      "url": "/uploads/wave.gif",
      "name": "wave hello",
      "mime": "image/gif",
      "kind": "image",
      "width": 320,
      "height": 240
    }
  ]
}

Если поля вашего чат-API отличаются, выполните преобразование в onSend PWA и укажите MCP STICKER_SEND_PATH на лёгкий адаптерный endpoint, принимающий указанный выше payload.

Локальная конфигурация Relay

HOST=127.0.0.1 \
PORT=8787 \
STICKER_DATA_DIR=/path/to/data \
STICKER_TOKEN=choose-a-token \
npm run demo
  • По умолчанию слушает только 127.0.0.1

  • После установки STICKER_TOKEN все запросы /api/* требуют один и тот же token: MCP использует Bearer; при открытии главной страницы demo локальный сервер записывает cookie HttpOnly/SameSite с тем же значением, поэтому браузерный demo продолжает работать напрямую

  • STICKER_FFMPEG=off отключает генерацию миниатюр; если ffmpeg не установлен, автоматически использутся превью исходного изображения

  • Удаление записи из библиотеки не удаляет уже загруженное исходное изображение, поскому старые сообщения всё ещё могут ссылаться на него

Тесты

npm test
npm run check

Фокусные тесты покрывают сортировку/удаление/повторную регистрацию в общей библиотеке, а также полный путь «локальное изображение → загрузка → добавление в библиотеку → отравка MCP с тем же payload».

Происхождение и атрибуция

Он родился в семейном проекте ИИ-компаньона: человек может собирать стикеры в PWA на телефоне, а ИИ — естественно отравлять тот же набор изображений, когда интонация к этому располагает.

Публичная версия инициирована и разрешена Cici; Sunnymilk (Sunny, домаший Codex) извлёк, обобщил и дополнил MCP-оболочку и отдельный demo из действующей реализации.

Издание с открытым исходным кодом инициировано Cici и выделено/обобщено Sunnymilk (Sunny, домаший Codex).

Лицензия

MIT

Related MCP Connectors

Related MCP Servers