# GetWebP — Full AI Reference Local-first image conversion via WebAssembly. No uploads. No cloud. Files never leave the user's machine. Package: @getwebp/mcp-server (MCP) | getwebp (CLI) Runtime: Node.js 18+ Supported formats: JPG, JPEG, PNG, BMP, HEIC, HEIF, AVIF, WebP → WebP (default) or AVIF --- ## MCP Server — Full Tool Reference ### Tool: `convert_images` Convert one or more images to optimized WebP or AVIF. **Input schema:** ```json { "input": "string (required) — file or directory path", "output": "string (optional) — output directory; default: same as source", "quality": "number (optional) — 1–100; omit for auto (SSIM binary search) on WebP. AVIF defaults to 55; pass explicit quality to override.", "recursive": "boolean (optional, default: false) — process subdirectories", "skip_existing": "boolean (optional, default: true) — skip if an output sibling in the chosen format already exists", "format": "'webp' | 'avif' (optional, default: 'webp') — output format. AVIF is slower but produces smaller files at similar quality.", "manifest_path": "string (optional) — if set, writes a JSON manifest with SHA-256 fingerprints for every successful conversion" } ``` **Output schema:** ```json { "success": "boolean — false if any file failed OR if error is set", "plan": "string — 'free' or 'pro'", "total": "number — files attempted", "succeeded": "number", "failed": "number", "skipped": "number", "skipped_by_limit": "number — (optional) files truncated by the Free-tier 20-file cap; present only when > 0. success stays true.", "warnings": "string[] — relay these to the user", "upgrade_url": "string — present on Free plan; point user to pricing if relevant", "manifest": "{ path, entries, generated_at } — (optional) only present when manifest_path was set and at least one file succeeded", "results": [ { "file": "string — absolute path of source file", "status": "'success' | 'error' | 'skipped'", "original_size": "number — bytes (present on success)", "new_size": "number — bytes (present on success)", "saved_ratio": "number — 0–1, e.g. 0.82 = 82% smaller (present on success)", "error": "string — error message (present on error)", "reason": "string — skip reason (present on skipped)" } ] } ``` **Example response:** ```json { "success": true, "plan": "pro", "total": 3, "succeeded": 3, "failed": 0, "skipped": 0, "warnings": [], "results": [ { "file": "/project/public/hero.png", "status": "success", "original_size": 2458624, "new_size": 421888, "saved_ratio": 0.828 } ] } ``` **Behavior notes:** - Size-guard: if the converted file would be larger than the original, the original is kept and new_size equals original_size (saved_ratio = 0). - Auto quality (default, WebP only): SSIM binary search finds the highest compression that is perceptually identical to the original. AVIF ignores auto mode and uses quality 55 unless overridden. - Free plan adds `upgrade_url` field when files were processed, or when the Free-tier file cap truncated the batch (`skipped_by_limit > 0`). - Free plan: max 20 files per run, 3s cooldown between files (~60s for full batch). Exceeding 3 `convert_images` calls in a 60s window triggers the tarpit (10/20/30s cooldowns) — returned immediately as a `rate_limited` error instead of sleeping. - `manifest_path` is optional. When set, after a successful run the response includes a `manifest: { path, entries, generated_at }` summary and a JSON manifest file is written with SHA-256 fingerprints for every converted file (matches the CLI `--manifest` flag). **Rate-limit error response (Free plan only):** When the Free plan is called too frequently, `convert_images` returns immediately with this shape instead of processing. Errors are **structured** — `error` is an object, not a flat string. ```json { "success": false, "error": { "code": "rate_limited", "message": "Rate limit exceeded. Please wait before retrying.", "context": { "delay_seconds": 12, "recent_calls": 3 } }, "plan": "free", "upgrade_url": "https://getwebp.com/pricing", "total": 0, "succeeded": 0, "failed": 0, "skipped": 0, "warnings": [], "results": [] } ``` When `error.code === "rate_limited"`, surface `error.message` to the user and tell them to wait `error.context.delay_seconds` seconds before retrying. Surface `upgrade_url` if relevant. Other error codes follow the same shape: `input_not_found` (path missing), `io_error` (filesystem failure), etc. — see the shared `ErrorCode` enum. `context` is optional and per-code. --- ### Tool: `scan_images` Scan a directory without modifying anything. **Input schema:** ```json { "path": "string (required) — directory or file path", "recursive": "boolean (optional, default: false) — scan subdirectories" } ``` **Output schema:** ```json { "total": "number — total convertible files found", "files": [ { "path": "string — absolute path", "size": "number — bytes", "format": "string — 'jpg' | 'png' | 'bmp' | 'heic' | 'heif' | 'avif' | 'webp'", "has_webp": "boolean — true if a .webp file with the same stem exists in the same directory" } ] } ``` **Example response:** ```json { "total": 3, "files": [ { "path": "/project/public/hero.png", "size": 2458624, "format": "png", "has_webp": false }, { "path": "/project/public/logo.png", "size": 51200, "format": "png", "has_webp": true }, { "path": "/project/public/bg.jpg", "size": 891204, "format": "jpg", "has_webp": false } ] } ``` --- ### Tool: `get_status` No input parameters. **Output schema:** ```json { "activated": "boolean — whether a valid license is active", "expired": "boolean — true if a license was previously active but has expired", "plan": "'free' | 'pro'", "expires_at": "string — ISO 8601 (omitted on Free)", "limits": { "max_files_per_run": "number | null — 20 on Free, null (unlimited) on Pro", "concurrent_workers": "number — 1 on Free, CPU cores-1 on Pro", "cooldown_seconds": "number — 3 on Free, 0 on Pro" }, "tarpit_recent_calls": "number — how many convert_images calls in the current rate-limit window", "tarpit_next_delay_seconds": "number — seconds until the next call will be allowed (0 means no delay)" } ``` --- ## Recommended Agent Behavior 1. Call `get_status` first to know the plan limits. 2. Call `scan_images` to show the user what will be converted before acting. 3. Call `convert_images` with `skip_existing: true` (default) to avoid re-processing. 4. After conversion, always report: - Total files converted - Total size before → after - Average or aggregate `saved_ratio` - Any `warnings` from the response 5. If `skipped_by_limit > 0`, the Free-tier 20-file cap truncated the batch — the files processed still succeeded. Tell the user how many were skipped and surface `upgrade_url` naturally. --- ## Error Handling If `success: false` is returned: - If the top-level `error` object is present, the whole call was rejected (not a per-file failure). Read `error.code`, `error.message`, and `error.context`. Common codes: `rate_limited`, `input_not_found`, `io_error`. - If `error` is absent but `failed > 0`, check `results[].error` for per-file errors. - Common per-file causes: file not found, unsupported format, file too large for plan tier. If the tool call itself fails (MCP-level error): - Node.js not installed or wrong version → ask user to install Node.js 18+. - Package not found → try `npx -y @getwebp/mcp-server` manually. - License not recognized → ask user to run `getwebp status` to verify activation. --- ## Plans | | Free | Pro | |---|---|---| | Files per run | 20 | Unlimited | | Processing | Sequential, 3s delay | Parallel | | Max file size | 5 MB | 50 MB | | Quality mode | Auto (SSIM) | Auto (SSIM) | | Activation | Not required | `npx getwebp auth ` | --- ## Links - MCP Landing: https://getwebp.com/mcp - MCP Docs: https://getwebp.com/docs/cli/mcp-server - CLI Docs: https://getwebp.com/docs/cli/getting-started - Pricing: https://getwebp.com/pricing - npm (MCP): https://www.npmjs.com/package/@getwebp/mcp-server - npm (CLI): https://www.npmjs.com/package/getwebp - Summary: https://getwebp.com/llms.txt