Microsoft Paint Server
БесплатноНе проверенMCP server that automates Microsoft Paint on Windows, offering tools to draw freehand strokes, polylines, and logarithmic spirals through Win32 API calls.
Описание
MCP server that automates Microsoft Paint on Windows, offering tools to draw freehand strokes, polylines, and logarithmic spirals through Win32 API calls.
README
This project exposes MCP (Model Context Protocol) tools that open Microsoft Paint and draw automatically from Node.js and TypeScript.
Included tools:
paint_draw_freehandpaint_draw_polylinepaint_draw_logarithmic_spiral
These tools automate Microsoft Paint through the Win32 API (user32.dll, shell32.dll) via Koffi.
Important: Paint automation only works on Windows. This is an educational proof of concept. Window interaction is performed with Win32 calls from Node.js through Koffi. It does not use RobotJS, Playwright, Puppeteer, AutoHotkey, or screen capture / visual analysis.
Requirements
- Windows 10 or 11 (64-bit)
- Node.js 18 or later (tested with Node 24)
- Microsoft Paint installed
Installation
npm install
Koffi installs a native binary. If your npm setup restricts scripts, approve Koffi explicitly:
npm approve-scripts koffi
Project Structure
Light hexagonal architecture: the domain is pure and does not know about MCP or Win32. The adapters live under src/infrastructure/. Composition happens in src/server.ts.
src/
server.ts # Composition root
domain/
drawing.ts # Drawing types, PaintPort, PaintWindow
figures.ts # Pure math helpers for figures
infrastructure/
win32/
user32.ts # user32.dll bindings and constants
shell.ts # shell32.dll binding (ShellExecuteW)
process.ts # Generic Windows helpers
paint.ts # Win32 Paint driver implementing PaintPort
mcp/
schemas.ts # Shared zod schemas
errors.ts # MCP tool error formatting
registry.ts # Registers all MCP operations
operations/
freehand.operation.ts
polyline.operation.ts
logarithmic-spiral.operation.ts
test/
helpers.mjs # MCP client helpers + spiral generators
logarithmic-spiral.test.mjs
polyline.test.mjs
freehand.test.mjs
Dependency flow:
src/server.ts -> infrastructure/mcp/*
|
v
domain/drawing.ts <- infrastructure/win32/paint.ts
^
|
domain/figures.ts
Running
Development:
npm run dev
Build and run:
npm run build
npm start
Sequence Diagram
End-to-end pipeline from an MCP call to actual drawing in Paint:
sequenceDiagram
autonumber
participant C as MCP Client / Inspector
participant S as src/server.ts
participant O as MCP Operation
participant P as PaintPort / Win32 Driver
participant W as Win32 / Shell / user32
participant M as Paint Window
C->>S: callTool(name, arguments)
S->>O: Registered tool handler
O->>P: paint.createWindow()
alt No Paint window is open
P->>W: spawnApplication("mspaint")
W-->>P: PID
P->>W: waitForWindowByPid(pid)
else Paint is already open
P->>W: enumerateWindows()
P->>W: spawnApplication("mspaint")
P->>W: waitForNewPaintWindow(before, 5s)
alt mspaint.exe does not create a new window
P->>W: ShellExecuteW(Paint AUMID)
P->>W: waitForNewPaintWindow(before, 5s)
end
end
W-->>P: WindowInfo (HWND, PID, title, class)
P->>M: maximizeWindow + bringWindowToFront
P->>M: wait PAINT_READY_DELAY_MS
P-->>O: PaintWindow
alt drawPolyline(points)
O->>P: window.drawPolyline(points, options)
P->>M: validate and convert canvas -> client -> screen
opt skipToolSelection === false
P->>M: click Pencil tool
end
P->>W: SetCursorPos + SendInput(single drag)
else drawFreehand(strokes)
O->>P: window.drawFreehand(strokes, options)
P->>M: validate and convert canvas -> client -> screen
opt skipToolSelection === false
P->>M: click Pencil tool
end
loop one drag per stroke
P->>W: SetCursorPos + SendInput(drag)
end
end
P-->>O: structured result
O-->>S: content + structuredContent
S-->>C: MCP response
Quick reading:
- MCP clients never talk to Win32 directly
- each operation creates its own
PaintWindow - the Win32 driver decides how to open or create the new Paint window
- actual automation happens through Win32 APIs such as
ShellExecuteW, window enumeration,SetCursorPos, andSendInput - tools return normal MCP responses with
structuredContent
Adding a New Operation
Each MCP operation lives in its own *.operation.ts file under src/infrastructure/mcp/operations/.
Typical flow:
- Add a pure figure helper to
src/domain/figures.tsif needed. - Create
src/infrastructure/mcp/operations/<name>.operation.ts. - Define input with zod schemas.
- In the handler, call
paint.createWindow()and thenwindow.drawPolyline(...)orwindow.drawFreehand(...). - Register the operation in
src/infrastructure/mcp/registry.ts.
Minimal example:
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import type { PaintPort } from "../../domain/drawing.js";
import { logarithmicSpiral } from "../../domain/figures.js";
import { toolErrorResult } from "../errors.js";
export function registerLogarithmicSpiral(
server: McpServer,
paint: PaintPort,
): void {
server.registerTool(
"paint_draw_logarithmic_spiral",
{ title: "Logarithmic Spiral", description: "...", inputSchema: {} },
async () => {
try {
const points = logarithmicSpiral(SPIRAL_PARAMS);
const window = await paint.createWindow();
const result = await window.drawPolyline(points, { stepDelayMs: 8 });
return {
content: [{ type: "text", text: "Done." }],
structuredContent: result,
};
} catch (error: unknown) {
return toolErrorResult("paint_draw_logarithmic_spiral", error);
}
},
);
}
MCP Inspector
npm run inspect
Start with paint_draw_logarithmic_spiral, then try paint_draw_freehand and paint_draw_polyline.
Tests
Integration tests use Node's built-in test runner and draw on real Paint windows, so they move the real mouse and depend on the active Windows desktop session.
Even though each operation creates its own Paint window, tests must run sequentially because they share the real mouse, Paint process, and Windows focus. That is why npm test uses --test-concurrency=1.
npm run build
npm test
Run a single test:
node --test --test-concurrency=1 test/polyline.test.mjs
Tool Behavior
paint_draw_logarithmic_spiral
Zero-argument example operation. It draws a logarithmic spiral r = 1.1^theta for 6 turns. It is the fastest way to verify the server from MCP Inspector.
paint_draw_freehand
Freehand drawing: one or more strokes, each stroke drawn with a single mouse drag.
Parameters:
strokes: 1-100 strokes, each as{ points: [{x, y}, ...] }, 2-1000 points per strokestepDelayMs: integer, 0-200, default10skipToolSelection: optional boolean;falseselects the Pencil tool before drawing
Default Inspector payload:
{
"strokes": [
{ "points": [{"x": 100, "y": 100}, {"x": 200, "y": 300}, {"x": 300, "y": 100}, {"x": 400, "y": 300}, {"x": 500, "y": 100}] },
{ "points": [{"x": 550, "y": 300}, {"x": 650, "y": 100}] }
],
"stepDelayMs": 10
}
paint_draw_polyline
Draws a connected polyline with a single drag. Useful for curves, spirals, and generated figures.
Parameters:
points: 2-1000{x, y}pointsstepDelayMs: integer, 0-200, default10skipToolSelection: optional boolean;falseselects the Pencil tool before drawing
Default Inspector payload:
{
"points": [{"x": 200, "y": 100}, {"x": 600, "y": 100}, {"x": 600, "y": 500}, {"x": 200, "y": 500}],
"stepDelayMs": 10
}
Paint Window Lifecycle
Each tool call creates its own Paint window and returns metadata including:
windowHandlewindowTitleprocessIdcreatedBy
createdBy can be:
opened: Paint was not open, so a fresh window was openedlaunched: Paint was already open andmspaint.execreated a new windowshell:mspaint.exedid not create a new window, soShellExecuteWwas used with the Paint AUMID
Internal drawing pipeline:
paint.createWindow()- Maximize the window
- Bring it to the foreground
- Wait
PAINT_READY_DELAY_MSso the canvas is actually ready - Convert canvas coordinates to client coordinates using
CANVAS_ORIGIN - Validate bounds
- Convert to screen coordinates
- Draw with
SetCursorPosandSendInput
Win32 APIs Used
EnumWindowsGetWindowTextWGetClassNameWGetWindowThreadProcessIdGetForegroundWindowIsWindowIsWindowVisibleIsIconicSetForegroundWindowShowWindowAttachThreadInputGetClientRectClientToScreenSetCursorPosGetSystemMetricsSetProcessDpiAwarenessContextSendInputShellExecuteW
Safety and Validation
- validates that the
HWNDstill exists before using it - rejects negative coordinates
- rejects points outside the Paint client area
- limits
stepDelayMsto0-200 - limits points and strokes to controlled ranges
- returns a warning if Windows does not allow the window to reach the foreground
Limitations
- Windows only
- moves the real mouse during drawing
- depends on Windows foreground restrictions and an interactive desktop session
- uses hardcoded layout offsets measured on a specific modern Paint build
- optional Pencil selection is coordinate-based and less reliable than drawing with the already active tool
mspaint.execan behave like a UWP stub on Windows 11, so the driver may need theShellExecuteWfallback- Paint windows accumulate and must be closed manually
Koffi Notes
HWNDandHANDLEare treated as 64-bit pointers and represented asBigIntINPUT/MOUSEINPUTmust match the exact x64 layoutEnumWindowsuses a transient Koffi callback that is only valid during the call
from github.com/miguelcespedes/mcp-server-microsoft-paint-nodejs
Установка Microsoft Paint Server
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/miguelcespedes/mcp-server-microsoft-paint-nodejsFAQ
Microsoft Paint Server MCP бесплатный?
Да, Microsoft Paint Server MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Microsoft Paint Server?
Нет, Microsoft Paint Server работает без API-ключей и переменных окружения.
Microsoft Paint Server — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Microsoft Paint Server в Claude Desktop, Claude Code или Cursor?
Открой Microsoft Paint Server на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Microsoft Paint Server with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
