armorpaint-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| ARMORPAINT_DIR | No | Path to the ArmorPaint install directory. Only needed when the install is not auto-detected (e.g. unusual locations like the itch.io app). The server only accepts a directory that contains data/plugins. | |
| ARMORPAINT_SPOOL | No | Directory used for the file mailbox/spool. Overrides the default per-user spool location when ArmorPaint is installed somewhere read-only or when a writable spool is needed. | %LOCALAPPDATA%\armorpaint-mcp\spool |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| ap_bridge_statusA | Diagnose the connection to ArmorPaint. Answered entirely by this server, with no round trip, so it works when everything else is failing: it reports the resolved spool directory and how it was resolved, whether the bridge heartbeat exists, whether the heartbeat's clock is advancing (the only valid liveness test), the bridge/app versions, the open project, queue depth, and a plain-language diagnosis plus next step. Call this FIRST whenever any other tool reports a transport error. |
| ap_pingA | Round-trip health check: sends a real request through the file mailbox and returns the bridge's app time, window title and current project path. Confirms the whole path works end to end, unlike ap_bridge_status which only reads the heartbeat. |
| ap_get_app_infoA | Application-level facts: window title, window size and position, ArmorPaint's data directory, and the project format version. |
| ap_bridge_set_enabledA | Turn the bridge's per-frame polling on or off. This has a real cost: while enabled the plugin calls iron_delay_idle_sleep() every frame, which keeps ArmorPaint rendering at full rate even when unfocused (that is also what makes remote control of a background window possible). Disable it when no agent is working. WARNING: disabling it stops the bridge from reading requests, so this is the last tool that will work until someone re-enables it from the Plugins tab. |
| ap_console_writeA | Write a line to ArmorPaint's own console. Write-only: no binding can read the console back, so this is for leaving a trail for the human, not for logging you intend to read. |
| ap_show_messageA | Show a message to the user in ArmorPaint: a transient toast by default, or a modal box. Prefer the toast — a modal blocks ArmorPaint's UI thread, which also stalls the bridge until the user dismisses it. |
| ap_project_newA | Start a new, empty project. Discards the current project WITHOUT prompting and without saving — call ap_project_save first if the work matters. |
| ap_project_openA | Open an existing .arm project file. Discards the current project without prompting. |
| ap_project_saveA | Save the current project to its existing path. Fails with code 'no_project' if the project has never been saved — use ap_project_save_as to give it a path first. THE SAVE IS DEFERRED: ArmorPaint queues the write for the next frame, so a successful reply means 'queued', not 'written'. Call ap_fs_stat on the path if you need proof it landed. |
| ap_project_save_asA | Set the project file path and save to it (project_filepath_set + project_save). Like ap_project_save, the write is DEFERRED to the next frame, so the reply confirms the path was set and the save queued — verify with ap_fs_stat. |
| ap_project_get_infoA | Project-level state: file path, base path, format version, BGRA flag, environment map name/strength/angle, and camera FOV. |
| ap_project_list_texture_assetsA | List the names of texture assets imported into the project. This one is LIVE (it reads project_t.assets), unlike the material/mesh lists which are save-time snapshots. |
| ap_project_list_scriptsA | List script assets attached to the project. DEGRADED: project_t.script_datas is a snapshot written at save/load, so it is empty in a fresh project and stale after changes made this session. |
| ap_quitA | Quit ArmorPaint. Unsaved work is LOST — save first. Requires confirm=true. The app usually exits before it can commit a reply, so a 'no reply' result here is normal and the response says whether the request was picked up. |
| ap_import_assetA | Import a file into the project, dispatched by extension: an image becomes a texture asset, a mesh replaces/adds paint geometry, a .arm becomes a material. |
| ap_import_envmapA | Import an HDR image as the environment map (script_import_asset with hdr_as_envmap=1) and report the resulting envmap name. |
| ap_set_envmap_paramsA | Set environment map strength and/or rotation angle (direct writes to project_t). |
| ap_export_texturesA | Export the project's texture channels to real image files on disk — the only binding in ArmorPaint's plugin API that writes images to disk. Returns the files found in the target directory afterwards; feed one to ap_read_image_file to look at it. IMPORTANT LIMITS, none of which are settable from a plugin: 'directory' is a DIRECTORY, not a filename; the base filename comes from the last name used in ArmorPaint's own export dialog, falling back to 'untitled'; the channel suffixes come from the active export preset ('generic' is auto-selected on first use); and the format/bit depth is whatever the UI is set to (8-bit PNG by default). |
| ap_export_material_bakeA | Bake the ACTIVE MATERIAL onto a plane and export the result as images (export_texture_run with bake_material=1). This is not mesh map baking — there is no bake-run binding for normal/AO/curvature maps. |
| ap_export_meshA | Export the paint geometry as Wavefront OBJ. The binding appends '.obj' to the path you give, so pass a path WITHOUT the extension. |
| ap_export_materialB | Export the active material as a reusable .arm material file. |
| ap_fs_listA | List a directory as seen by the ArmorPaint process (which may be a different machine/container than this server). Useful for finding what an export actually wrote. |
| ap_fs_statA | Report whether a path exists, whether it is a directory, and whether ArmorPaint considers it absolute. |
| ap_fs_mkdirA | Create a directory (as the ArmorPaint process), e.g. before an export. |
| ap_get_contextA | The workhorse read: the live painting context — active tool, brush radius/opacity/hardness/scale/angle/blending, viewport display mode, x-ray flag, whether a layer and a material are selected, and the active material's name. Note that only whether a layer is selected can be reported: the layer object itself is an opaque pointer with no readable fields. |
| ap_get_configA | Application preferences that are readable from a plugin: window size/scale, supersampling, keymap, theme, undo steps, camera FOV, default layer resolution, live-brush/live-material/node-preview toggles, workspace and workflow, plus the recent-project and plugin lists. Post-processing settings (SSAO, bloom, LUT, gamma...) are not exposed by the API. |
| ap_set_configA | Change application preferences. Only the listed fields are writable; anything else in ArmorPaint's preferences is not exposed to plugins. layer_res is the DEFAULT resolution for new layers — changing it does not resize existing ones. |
| ap_get_main_objectA | Describe the main paint object: name, visibility and transform (location, rotation quaternion, scale). |
| ap_get_objectA | Describe a scene object by name: visibility and transform. Names are matched against the paint objects. NOTE: there is no binding that ENUMERATES objects — you can only look one up by name, or use ap_get_main_object. |
| ap_shape_listA | List the built-in primitive shapes that ap_shape_add accepts, from the running build. Typically: cone cube cube_bevel cube_bevel_shared_uvs cube_shared_uvs cylinder empty torus plane plane_2048 sphere sphere_2048. |
| ap_shape_addA | Add a built-in primitive to the scene (cube, sphere, plane, cylinder, cone, torus, the bevelled/shared-UV cube variants, the 2048-poly plane/sphere, or 'empty'). Use ap_shape_list for this build's exact names. |
| ap_object_duplicateA | Duplicate a scene object by name and return the new object's name. |
| ap_object_set_transformA | Set an object's location, rotation and/or scale, then rebuild its matrix. Rotation is given as XYZ Euler angles in DEGREES and converted to the quaternion the engine wants. Omitted components are left alone. ArmorPaint's world is Z-up. |
| ap_object_set_visibleA | Show or hide a scene object. This is the object's visible flag: a hidden object stays in the project with its materials intact, it just stops rendering. |
| ap_append_meshA | Append geometry to the current project, either from a mesh file on disk or from inline Wavefront OBJ text. Give exactly one of 'path' or 'obj_data'. Pass inline OBJ with ordinary newlines — they are re-encoded for the wire and restored inside ArmorPaint — but it must contain no double quotes, backslashes or '|' (the bridge's JSON parser does not decode escapes and '|' is the line separator), and the whole request is capped at 8 KB. Prefer 'path' for anything non-trivial. |
| ap_material_get_activeA | Report the active material: its name (a material's name is its node-canvas name) and its nine per-channel paint flags. |
| ap_material_createA | Create a new material slot and make it active. |
| ap_material_selectA | Make an existing material active, by name. |
| ap_material_deleteA | Delete a material slot by name. Irreversible from here — ArmorPaint's plugin API has no undo/redo binding, so this cannot be taken back except by the user pressing Ctrl+Z in the app. |
| ap_material_assignA | Assign an existing material to a scene object. Both are looked up by name, and a material's name is its node-canvas name (what ap_material_get_active reports). |
| ap_material_set_channelsA | Enable or disable which channels the active material paints into. These are the material's own paint_* flags, not texture-set channels (ArmorPaint's plugin API has no channel add/remove). Omitted channels are left alone. |
| ap_material_listA | List material names. DEGRADED — read the caveat before trusting it: this reads project_t.material_nodes, which is a SNAPSHOT written only at save and load. It is null in a project that has never been saved, and it misses materials created during this session. There is no live material enumeration binding. For the material you are actually working on, use ap_material_get_active. |
| ap_material_updateA | Recompile the active material after node edits (script_material_update). THIS DOES NOT CHANGE THE VIEWPORT. ArmorPaint renders the layer stack, and the node graph is only the paint SOURCE — measured: viewport captures before and after a colour change plus ap_material_update are byte-identical. To make a graph edit visible you must apply it: ap_fill_layer (whole layer) or ap_paint_stroke / ap_paint_stroke_world (where you paint). Call this once after a batch of ap_node_* edits, then apply. |
| ap_node_listA | Read the active material's node graph: every node's id, name, type and canvas position, its input/output socket names, and every link (from_id/from_socket -> to_id/to_socket). This is the richest and best-tested part of the API — node work is where an agent has the most real leverage in ArmorPaint. |
| ap_node_addA | Add a node to the active material's graph at a canvas position, and return its new id. Valid types: ATTRIBUTE BAKE_CURVATURE BLUR BOOL BRIGHTCONTRAST BUMP CLAMP COLMASK COMBINE_COLOR COMBXYZ CURVE_RGB CURVE_VEC CUSTOM DIRECT_WARP ENUM FLOAT_CURVE GAMMA GROUP GROUP_INPUT GROUP_OUTPUT HUE_SAT INVERT_COLOR LAYER LAYER_MASK MAPPING MAPRANGE MATERIAL MATH MIX_NORMAL_MAP MIX_RGB NEURAL_EDIT_IMAGE NEURAL_IMAGE_TO_3D_MESH NEURAL_IMAGE_TO_PBR NEURAL_REPEAT NEURAL_SAVE_IMAGE NEURAL_TEXT_TO_IMAGE NEURAL_UPSCALE_IMAGE NEW_GEOMETRY NORMAL NORMAL_MAP OBJECT_INFO OUTPUT_MATERIAL_PBR PICKER QUANTIZE REPLACECOL RGB RGBA RGBTOBW SCRIPT_CPU SEPARATE_COLOR SEPXYZ SHADER_GPU STRING TEX_BAKE TEX_BRICK TEX_CAMERA TEX_CHECKER TEX_COORD TEX_GABOR TEX_GRADIENT TEX_IMAGE TEX_MAGIC TEX_NOISE TEX_TEXT TEX_VORONOI TEX_WAVE TILESHEET TILESHEET_ANIM UVMAP VALTORGB VALUE VECTOR VECT_MATH VECT_ROTATE VECT_TRANSFORM WIREFRAME. |
| ap_node_removeA | Remove a node from the active material's graph by id (from ap_node_list). |
| ap_node_connectA | Link one node's output socket to another node's input socket. Socket numbers are 0-based positions, as reported by ap_node_list; the output node's material socket order is Base Color, Opacity, Occlusion, Roughness, Metallic, Normal Map, Emission, Height, Subsurface. |
| ap_node_disconnectA | Remove whatever is linked into one input socket of a node. |
| ap_node_set_valueA | Set a value on a node. Four kinds: 'float' (one number on a socket), 'color' (r,g,b,a on a socket), 'vector' (x,y,z on a socket), and 'button' (a node's own widget — dropdown index, checkbox 0/1, or a slider value; see the node reference for each type's button list). Socket-based kinds default to the node's INPUT sockets. Follow a batch of edits with ap_material_update. |
| ap_select_toolA | Select the active tool: bake, blur, brush, clone, colorid, cursor, decal, eraser, fill, material, particle, picker, select, text. The selection is read back from the context so the result confirms it took effect. |
| ap_set_brushA | Set brush parameters on the painting context. Omitted values are left alone. These are direct context writes, so they take effect immediately for the next stroke. |
| ap_paint_strokeA | Paint a stroke in SCREEN space and close it. Coordinates are normalised (0..1) across the viewport, so 0.5,0.5 is the centre and what gets painted depends on the current camera. Paints into the selected layer with the active tool/brush; silently does nothing if no project is open, no layer is selected, or the selected layer is a group. At most 48 points — the whole stroke runs inside one frame. |
| ap_paint_stroke_worldA | Paint a stroke in WORLD space and close it — camera-independent, which makes it the reliable choice for scripted painting. ArmorPaint's world is Z-up; use ap_get_main_object for the object's bounds. |
| ap_fill_layerA | Fill the selected layer with the active material and push an undo step. THIS IS THE STEP THAT MAKES A NODE-GRAPH EDIT VISIBLE — ap_material_update only recompiles the material; nothing appears in the viewport until you fill or paint. The working loop is: ap_node_* edits -> ap_material_update -> ap_fill_layer -> ap_capture_viewport. Fails with 'no_project'/'bad_args' if no layer is selected. This is also the ONLY layer operation in ArmorPaint's plugin API — there is no create/delete/rename/mask/opacity/blend binding, so layer management has to be done by hand in the UI. |
| ap_set_display_channelA | Set what the 3D viewport displays: base_color, emission, height, lit, mask, material_id, metallic, none, normal_map, object_id, object_normal, occlusion, opacity, path_trace, roughness, subsurface, texcoord. 'lit' is the normal shaded view; the others isolate a channel or a debug output. |
| ap_capture_to_projectA | Capture the 3D viewport into the project as a packed texture asset. Works on a stock ArmorPaint, but the pixels land INSIDE the project (persisted only when the .arm is saved) — nothing outside ArmorPaint can read them, so you cannot look at the result. To actually see the viewport, use ap_capture_viewport (needs the optional viewport patch). NOTE: the bridge handler runs inline in one frame and cannot wait for a re-render, so the capture is of the frame ALREADY drawn and may include the UI overlay; ArmorPaint's own two-frame settle is not reproducible from a plugin. |
| ap_capture_viewportA | Capture the shaded 3D viewport to a PNG file and return the image so you can look at your own work. REQUIRES the optional viewport patch (docs/UPSTREAM_CHANGES.md) which adds the viewport_save_texture_to_file binding — on a stock build this returns code 'unsupported', and the fallbacks are ap_capture_to_project (in-project only) or ap_export_textures (writes real files, but flat textures rather than the shaded view). |
| ap_read_image_fileA | Read an image file from THIS server's filesystem and return it as an image, so you can look at what ArmorPaint exported. Answered locally — no round trip, and it works while ArmorPaint is closed. Pair it with ap_export_textures: export, then read one of the reported files. PNG/JPEG/GIF/WEBP/BMP only (EXR cannot be displayed), up to 6 MB. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/baktubak/armorpaint-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server