pixelate-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +46 -0
  3. package/index.js +95 -0
  4. package/package.json +35 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PixelAOI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # pixelate-mcp
2
+
3
+ An [MCP](https://modelcontextprotocol.io) server that turns any image into
4
+ **grid-perfect, true pixel art** — it auto-detects the native pixel grid and a
5
+ sensible palette among other things like reauthoring of the image. Works in **Codex, Claude Desktop, and Cursor**.
6
+
7
+ The heavy lifting runs in the cloud (Pixelate Cloud); this package is the small
8
+ local connector that decodes your image and streams it to the service. You need
9
+ a subscription key from **https://pixelaoi.pro**.
10
+
11
+ ## Use it
12
+
13
+ Add to your MCP client config (Codex `~/.codex/config.toml`, Claude Desktop, or
14
+ Cursor) — no install step needed, `npx` fetches it on demand:
15
+
16
+ ```toml
17
+ [mcp_servers.pixelate]
18
+ command = "npx"
19
+ args = ["-y", "pixelate-mcp"]
20
+ env = { PIXELATE_API_URL = "https://pixelate.pixelaoi.cloud", PIXELATE_API_KEY = "YOUR_KEY" }
21
+ ```
22
+
23
+ Then ask your agent something like *"pixelate ./hero.png and save it next to the
24
+ original."*
25
+
26
+ ## Tool: `pixelate_image`
27
+
28
+ | arg | description |
29
+ |-----|-------------|
30
+ | `image_path` / `image_base64` / `image_url` | the source image (provide one) |
31
+ | `auto` | auto-detect grid + palette (default `true`) |
32
+ | `target_width` / `target_height` | output size when `auto` is off or no grid is found |
33
+ | `colors` | palette size (omit to auto-pick) |
34
+ | `seed` | determinism seed |
35
+ | `output_path` | if set, saves the PNG there |
36
+
37
+ Returns the pixel art as an image, plus a short summary.
38
+
39
+ ## Requirements
40
+
41
+ - Node.js ≥ 18
42
+ - A `PIXELATE_API_KEY` (subscribe at https://pixelaoi.pro)
43
+
44
+ ## License
45
+
46
+ MIT
package/index.js ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import sharp from "sharp";
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { z } from "zod";
8
+
9
+ const API_URL = (process.env.PIXELATE_API_URL || "").replace(/\/+$/, "");
10
+ const API_KEY = process.env.PIXELATE_API_KEY || "";
11
+ if (!API_URL || !API_KEY) {
12
+ console.error("pixelate-mcp: set PIXELATE_API_URL and PIXELATE_API_KEY environment variables.");
13
+ process.exit(1);
14
+ }
15
+
16
+ const stripDataUrl = (s) => {
17
+ const i = s.indexOf(",");
18
+ return s.startsWith("data:") && i !== -1 ? s.slice(i + 1) : s;
19
+ };
20
+ const errText = (text) => ({ content: [{ type: "text", text }], isError: true });
21
+
22
+ async function jobReq(query, body) {
23
+ const res = await fetch(`${API_URL}/job?${query}`, {
24
+ method: "POST",
25
+ headers: body
26
+ ? { "content-type": "application/octet-stream", "x-api-key": API_KEY }
27
+ : { "x-api-key": API_KEY },
28
+ body: body ?? undefined,
29
+ });
30
+ const j = await res.json().catch(() => ({}));
31
+ if (!res.ok) throw new Error(`HTTP ${res.status}: ${j.error || "request failed"}`);
32
+ if (!j.success) throw new Error(j.error || "job error");
33
+ return j;
34
+ }
35
+
36
+ const server = new McpServer({ name: "pixelate-mcp", version: "0.1.0" });
37
+
38
+ server.tool(
39
+ "pixelate_image",
40
+ "Convert an image into grid-perfect, true pixel art. Auto-detects the native pixel grid and a sensible palette. Provide exactly one of image_path, image_base64, or image_url.",
41
+ {
42
+ image_path: z.string().optional().describe("Local path to the source image (png/jpg/webp)."),
43
+ image_base64: z.string().optional().describe("Base64-encoded image (alternative to image_path)."),
44
+ image_url: z.string().optional().describe("URL to fetch the image from (alternative to image_path)."),
45
+ auto: z.boolean().optional().describe("Auto-detect native grid + palette (default true)."),
46
+ target_width: z.number().int().positive().optional().describe("Output width; used when auto is off or no grid is detected."),
47
+ target_height: z.number().int().positive().optional().describe("Output height; used when auto is off or no grid is detected."),
48
+ colors: z.number().int().positive().optional().describe("Palette size; omit to auto-pick."),
49
+ seed: z.number().int().optional().describe("Determinism seed (default 42)."),
50
+ output_path: z.string().optional().describe("If set, save the resulting PNG to this path."),
51
+ },
52
+ async (a) => {
53
+ try {
54
+ let buf;
55
+ if (a.image_base64) buf = Buffer.from(stripDataUrl(a.image_base64), "base64");
56
+ else if (a.image_path) buf = await readFile(a.image_path);
57
+ else if (a.image_url) buf = Buffer.from(await (await fetch(a.image_url)).arrayBuffer());
58
+ else return errText("Provide one of image_path, image_base64, or image_url.");
59
+
60
+ // Decode locally to raw RGBA (no Worker decode -> no decode CPU on the edge).
61
+ const { data, info } = await sharp(buf).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
62
+
63
+ // Start: raw bytes go in the binary body; params in the query string.
64
+ const q = new URLSearchParams({ action: "start", w: String(info.width), h: String(info.height), auto: (a.auto ?? true) ? "1" : "0" });
65
+ if (a.colors) q.set("colors", String(a.colors));
66
+ if (a.seed != null) q.set("seed", String(a.seed));
67
+ if (a.target_width) q.set("tw", String(a.target_width));
68
+ if (a.target_height) q.set("th", String(a.target_height));
69
+
70
+ let res = await jobReq(q.toString(), data);
71
+ const jobId = res.job_id;
72
+ let guard = 0;
73
+ while (!res.done) {
74
+ if (++guard > 1000) return errText("pixelate-mcp: job did not converge");
75
+ res = await jobReq(`action=step&id=${encodeURIComponent(jobId)}`);
76
+ }
77
+
78
+ let summary = `Pixel art ${res.width}x${res.height}.`;
79
+ if (a.output_path) {
80
+ await writeFile(a.output_path, Buffer.from(res.image_base64, "base64"));
81
+ summary += ` Saved to ${a.output_path}.`;
82
+ }
83
+ return {
84
+ content: [
85
+ { type: "text", text: summary },
86
+ { type: "image", data: res.image_base64, mimeType: "image/png" },
87
+ ],
88
+ };
89
+ } catch (e) {
90
+ return errText(`pixelate-mcp error: ${e?.message || e}`);
91
+ }
92
+ },
93
+ );
94
+
95
+ await server.connect(new StdioServerTransport());
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "pixelate-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server: turn any image into grid-perfect pixel art via the Pixelate Cloud API. Works in Codex, Claude Desktop, Cursor.",
5
+ "type": "module",
6
+ "bin": {
7
+ "pixelate-mcp": "index.js"
8
+ },
9
+ "files": [
10
+ "index.js",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "keywords": [
15
+ "mcp",
16
+ "model-context-protocol",
17
+ "pixel-art",
18
+ "pixelate",
19
+ "codex",
20
+ "claude",
21
+ "cursor",
22
+ "aseprite"
23
+ ],
24
+ "homepage": "https://pixelaoi.pro",
25
+ "license": "MIT",
26
+ "author": "PixelAOI",
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.12.0",
32
+ "sharp": "^0.33.5",
33
+ "zod": "^3.23.8"
34
+ }
35
+ }