stickers-mcp
by crsel
README.md
# sticker-mcp
MCP server that publishes sticker packs: PNG → visually-lossless HEIC + small HEIC
thumbnail, upload to Firebase Storage, and merge into the `sticker_categories`
Remote Config parameter.
## Requirements
- Node 18+ (uses global `fetch`)
- `brew install libheif imagemagick` (provides `heif-enc`, `magick`)
- `gcloud` authenticated with an account that has access to the target Firebase
project (`crsel-dev`) for both Storage and Remote Config:
```
gcloud auth login
```
The bearer token comes from `gcloud auth print-access-token`. The active
account must have Storage write + `firebaseremoteconfig.*` permissions on the
project. The Remote Config REST API always requires a quota project — the
tools send `x-goog-user-project` (defaults to `project`; override with
`quotaProject` if your billing/quota project differs).
## Install
```bash
git clone git@github.com:crsel/stickers-mcp.git ~/stickers-mcp && bash ~/stickers-mcp/install.sh
```
`install.sh` (safe to re-run) will:
- verify Node 18+,
- install `libheif` + `imagemagick` via Homebrew if missing,
- `npm install`,
- register the server with Claude Code at **user scope** (available in all your projects).
Afterwards: run `gcloud auth login` if prompted, then restart Claude Code.
Manual registration (if you skip the script):
```bash
claude mcp add stickers-mcp -s user -- node /absolute/path/to/stickers-mcp/src/index.js
```
## Tools
| Tool | What it does |
|------|--------------|
| `convert_stickers` | A single `.png` file **or** every `.png` in a folder → `<out>/full/*.heic` (q90, alpha preserved) + `<out>/thumb/*.heic` sized into 10–25 KB. One file = one sticker, converted as-is (no content judgement). |
| `inspect_bucket` | `gcloud storage ls gs://<bucket>/<path>` — confirm existing layout before uploading. |
| `upload_stickers` | Upload full → `<folder>/` (bucket root), thumb → `thumbnails/<folder>/`. Returns config urls. `dryRun` to preview paths. |
| `get_sticker_categories` | Fetch live Remote Config: category_order, category sizes, ETag. |
| `update_sticker_categories` | `new`/`merge` a category into `sticker_categories` and publish (If-Match/ETag). `dryRun=true` by default — returns the diff without publishing. |
| `migrate_png_to_heic` | Scan `sticker_categories` for `.png` urls (optionally scoped via `categoryKey`, capped via `limit`), fetch each PNG, convert to HEIC + thumbnail, upload to root + `thumbnails/`, rewrite the url to `.heic`. Publishes incrementally (every 10, fresh ETag), emits per-item progress, skips a failed sticker instead of aborting, and is safe to re-run. `dryRun=true` by default. |
| `reorder` | Reorder the category list (`scope=categories`) or stickers within a category (`scope=stickers`). Use `moves` for "move X before/after B" / to start/end/index, or `order` for a full desired list. `dryRun=true` by default; publishes with If-Match/ETag. |
## Conventions
- Verified bucket layout: full sticker = `gs://<bucket>/<folder>/<file>.heic`
(bucket root, **no** `stickers/` prefix); thumbnail =
`gs://<bucket>/thumbnails/<folder>/<file>.heic`. Config `url` = `<folder>/<file>.heic`.
- `folder` (storage subfolder) can differ from the category key — e.g. category
key `Cut Out`, folder `Cut Outs`.
- Referencing a **folder** of PNGs mirrors that folder's name into the bucket
root: `convert_stickers` returns `suggestedFolder`, which you pass to
`upload_stickers` as `folder` → `gs://<bucket>/<folder>/` + `thumbnails/<folder>/`.
## Typical flow (driven by Claude)
1. `convert_stickers` on the PNG file or folder.
2. `inspect_bucket stickers/<existing folder>/` to confirm the layout.
3. `upload_stickers` (try `dryRun` first) → collect returned `urls`.
4. Decide category placement with the user (new vs merge, order).
5. `update_sticker_categories dryRun=true` → review the diff.
6. `update_sticker_categories dryRun=false` to publish.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing