Skip to main content
Glama

PWA Sticker MCP · 共享表情包

让人和 AI 共用同一个 PWA 表情包库:人在抽屉里点一下发送,模型通过 MCP 调同一张图发送。

The human-facing PWA drawer and the AI-facing MCP server share one sticker library and one attachment contract.

这个公开版从真实家庭 PWA 的现役功能中独立抽出,保留了最有用的部分:

  • PWA 表情包抽屉:上传、懒加载、最近使用排序、长按或键盘进入管理、删除

  • iOS 友好的正方形网格:不依赖滚动 grid 中容易塌陷的 aspect-ratio

  • 静态 WebP 抽屉预览:有 ffmpeg 时自动生成 192px 首帧,实际发送仍是原图或原 GIF

  • MCP 三工具:list_stickerssend_stickeradd_sticker

  • 图片-only 消息:发送 { 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: sticker-mcp

接入 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?):把模型所在机器上的本地图片登记进共享库,但不发送

关键词命中多张时工具会请模型收窄,不会擅自挑一张。

把抽屉装进现有 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 到 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 server,只要实现下面五个请求:

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。

Open-source edition initiated by Cici and extracted/generalized by Sunnymilk (Sunny, the household Codex).

License

MIT

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Your memory, everywhere AI goes. Build knowledge once, access it via MCP anywhere.

  • Shared, governed long-term memory for AI agents across tools and sessions via MCP and REST.

  • Cross-vendor AI memory over MCP. One semantic store, readable and writeable from every MCP client.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/gobly2333/pwa-sticker-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server