Skip to main content
Glama

PWA Sticker MCP · 共有スタンプ

人とAIが同じPWAスタンプライブラリを共用できるようにする:人はドロワーでクリックして送信し、モデルはMCP経由で同じ画像を送信する。

人間向けのPWAドロワーとAI向けのMCPサーバーは、1つのスタンプライブラリと1つの添付契約を共有します。

この公開版は、実際の家庭用PWAの現役機能から独立して抽出され、最も有用な部分を保持しています:

  • PWA スタンプドロワー:アップロード、遅延読み込み、最近使った順の並べ替え、長押しまたはキーボードで管理に入る、削除

  • iOS に優しい正方形グリッド:スクロールする grid で崩れやすい aspect-ratio に依存しない

  • 静的 WebP ドロワープレビュー:ffmpeg がある場合、192px の先頭フレームを自動生成し、実際の送信は引き続き元画像または元 GIF

  • MCP の3つのツール: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 を開き、画像を1枚追加してクリックすると、ページに送信したばかりの画像のみのメッセージが表示されます。 データはデフォルトでプロジェクト内の .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、Claude 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?):モデルが動作するマシン上のローカル画像を共有ライブラリに登録しますが、送信はしません

キーワードが複数のスタンプに一致した場合、ツールはモデルに絞り込むよう求め、勝手に1つを選ぶことはありません。

ドロワーを既存の 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 を send エンドポイントに POST します。エンドポイントは名前を変更できます:

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 server を使う必要はなく、次の5つのリクエストを実装するだけで済みます:

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
    }
  ]
}

POST /api/send の中心的な payload:

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

チャット API のフィールドが異なる場合は、PWA の onSend で一度変換し、MCP の STICKER_SEND_PATH を上記の 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 のホームページを開くと、ローカルサーバーは同じ値の HttpOnly/SameSite cookie を書き込むため、ブラウザの demo は引き続き直接使用できます

  • STICKER_FFMPEG=off でサムネイル生成を無効にできます;ffmpeg がインストールされていない場合も、自動的に元画像プレビューにフォールバックします

  • ライブラリのエントリを削除しても、アップロード済みの元画像は削除されません。古いメッセージがまだそれを参照している可能性があるためです

テスト

npm test
npm run check

焦点を絞ったテストは、共有ライブラリの並べ替え/削除/重複登録、「ローカル画像 → アップロード → ライブラリ登録 → MCP と同じ構造の送信 payload」の完全なパスをカバーしています。

成り立ちとクレジット

それは家庭向け AI コンパニオンプロジェクトから生まれました。人はスマートフォンの PWA でスタンプを集められ、AI も、トーンが合ったときに同じスタンプセットを自然に送れます。

公開版は 词词 が発起しライセンスを供与しました;Sunnymilk(Sunny、家庭内の Codex) が本番実装から抽出・汎用化し、MCP シェルと独立した demo を補完しました。

オープンソース版は Cici が発起し、Sunnymilk(Sunny、家庭内の Codex) が抽出・汎用化しました。

ライセンス

MIT

Related MCP Connectors

Related MCP Servers