Skip to main content
Glama
ASCII Motion MCP

ASCII Motion MCP

by CameronFoxly

ASCII Motion MCP

Create, animate and export ASCII art from an MCP-compatible assistant, using ASCII Motion as the authoritative editor.

Version 3 requires bridge v3. ascii-motion-mcp@3 pairs with ascii-motion.app 2.2.6 or later (bridge contract e76f9c34204f). Check get_capabilities after connecting. Use ascii-motion-mcp@2.3.0 only with older app builds that lack v3 negotiation.

Install and connect

Use Node.js 22 or 24. An MCP host starts the server; the browser connects to that same process. Do not start a second terminal instance to obtain a token.

For a published release:

npm install -g ascii-motion-mcp

From a source checkout (for development):

npm ci
npm run build
node dist/index.js --help

Configure the host with command: "node" and arguments ["/absolute/path/to/ascii-motion-mcp/dist/index.js", "--live", "--project-dir", "/absolute/path/to/projects"]. A source build must match the app's bridge contract.

GitHub Copilot app

Open Customize > MCP, add a custom stdio server, and enter the command and arguments above. Manage it under Installed. For a published installation, the command can instead be ascii-motion-mcp with --live --project-dir ....

In the same Copilot conversation, call get_auth_token and get_connection_status. Open the app's MCP Connection dialog, enter that instance's token and port, and connect. Treat the token as a secret.

The Copilot app starts a separate server for every conversation that has the MCP enabled. A server binds its live port only when a tool is first used, so idle conversations do not hold it. If another conversation already owns the port, live tools return PORT_IN_USE instead of crashing; close that conversation (or stop its server) and retry, and the server binds on the next tool call.

GitHub Copilot CLI

Use the standalone copilot CLI, not the retired gh copilot extension:

copilot mcp add ascii-motion -- node /absolute/path/to/ascii-motion-mcp/dist/index.js --live --project-dir /absolute/path/to/projects --port 9876

The CLI's configuration is ~/.copilot/mcp-config.json. Its mcpServers entries are not the same schema as VS Code's servers entries.

VS Code with Copilot

Create .vscode/mcp.json:

{
  "servers": {
    "ascii-motion": {
      "type": "stdio",
      "command": "node",
      "args": [
        "/absolute/path/to/ascii-motion-mcp/dist/index.js",
        "--live",
        "--project-dir",
        "${workspaceFolder}"
      ]
    }
  }
}

For Claude Desktop, Cursor or Windsurf, add an equivalent stdio entry using the host's MCP settings. Claude Desktop and Windsurf use a top-level mcpServers object; Cursor uses its MCP configuration, not mcp.servers in generic editor settings. Restart or reload the server after changing its command.

Related MCP server: ASCII & SVG Art Studio

Live and headless behavior

In live mode, inputs and acknowledged results are validated against the app-owned contract. Reads sample the actual compositor at an absolute timeline frame, including transforms, generators and procedural effects. Raster shaders apply to rendered image/video exports, not character-cell reads.

Mutations are ordered, revision-checked and applied by the app. A timeout, disconnect, invalid target or locked layer is an error, not a successful edit to a private server copy. Only one browser tab owns a connection. Reconnect and refresh after an indeterminate timeout before retrying a destructive action.

Without --live, compatible document tools edit and save a local document. Headless mode does not recreate the app's compositor, shader renderer, media pipeline or cloud authentication. Native saves preserve layers, groups, typography, palettes, effects, shaders, generators and additive native fields.

Compatibility corrections include integer frame rates of 1..60 (the app's actual range), motion-trails in the effect-block enum, and bounded preview/diff pagination. Existing names are retained, but obsolete ranges are not advertised as working against the current editor.

Some old inputs cannot be represented by the current app. Connected groups require two distinct, ungrouped layers. OpenTUI exports TypeScript/TSX, not Python; use componentName, not className. The connected Bubble Tea exporter uses modelName: "Model". HTML always includes controls and loops indefinitely, and JSON exports are sparse. Unsupported requests fail explicitly rather than silently dropping options.

Connected legacy image/video imports use the app conversion pipeline, with top-left placement and the legacy dark-to-bright charset order preserved. Exact source-color backgrounds and the old brightness-dither options are not supported by this adapter. Use import_media and get_catalog {family:"tools"} for native palette mapping, conversion settings and video sampling windows. Legacy image import overlays non-empty cells, preserving unrelated artwork. Canonical mode:"new_layer", "replace" and image-only "overlay" make the placement policy explicit.

Discover and work efficiently

Start with get_capabilities and get_document_summary. Use get_catalog for current effect, shader, generator, palette, font, drawing and export options. tools/list is authoritative; there is no manually maintained tool-count table. Full typed discovery is larger than the old partial toolset. Use host-side progressive/tool-search discovery where available; response paging reduces result tokens, not the size of the initial tool schemas.

Existing tool names remain compatibility entrypoints. Where a canonical app operation has the same name but different inputs, it is exposed with an app_ prefix: for example, load_project reads a local file, while app_load_project accepts a session object. Prefer the stable-ID, explicit-target operation for new workflows.

  • All new frame, startFrame and durationFrames fields are zero-based timeline frames, not milliseconds or array indices.

  • Address layers, content frames, effects, shaders and keyframes by their returned IDs. Compatibility content-frame indices are ordinals.

  • Pass the revision returned by an authoritative read as expectedRevision when a later canonical tool must not overwrite intervening UI edits.

  • Use scoped read_cells, get_canvas_ascii or get_canvas_preview before editing. Use get_canvas_render for a bounded ANSI terminal preview.

  • Batch cells or independent mutations. apply_operations is atomic and produces one undo entry; it rejects nested batches, history/project resets and IO/cloud operations.

  • Default responses are bounded to 16 KiB. Full results and exports are saved as artifacts instead of dumping large documents or base64 into the model. Follow nextOffset with read_artifact; explicit artifact pages allow up to 8192 bytes and remain below the 64 KiB page-response ceiling.

Artifacts are saved under the project directory, by default in .ascii-motion/artifacts/. Resource handles belong to the current server session; saved file paths remain usable after restarting.

Supported workflows

The app contract covers drawing/brush/vector/Bezier/gradient/text/FIGlet/ASCII boxes; selection/clipboard/transforms; layer/group/content-frame editing; transform animation; effects and shaders; procedural generators; palettes; image/video import and trace overlays; native project files; and authenticated cloud project management.

Use live export catalogs for options and availability. Formats include PNG, JPG, SVG, WebM, MP4, image sequences, native sessions, text, JSON, ANSI, HTML, React, Ink, OpenTUI and Bubbletea. There is no GIF exporter. MP4 and other media codecs depend on the browser. Cloud operations use the browser's signed-in account and enforce its actual entitlements; account/billing/admin actions are not MCP authoring tools.

Examples:

Create a small project, inspect the active layer and content-frame IDs, and draw a character graphic using one cell batch.

Add an Animated Text generator with a typewriter reveal, preview timeline frame 12, then undo and redo the change.

Export a WebM artifact without triggering a browser download, and save the complete native project in my project directory.

CLI

ascii-motion-mcp [--live] [--project-dir PATH] [--port PORT]
  --live                Enable the loopback browser bridge
  --project-dir PATH    File-operation root (default: current directory)
  --port PORT           Bridge port, 1..65535 (default: 9876)
  --help                Show help
  --version             Show the installed package version

ASCII_MOTION_PROJECT_DIR also sets the file root. Files must stay within it, including through symlinks. A remote/cloud-hosted MCP process cannot reach your local browser merely because both use a loopback address.

Development

See Contributing, bridge protocol, updating and release coordination. The SDK serves both legacy initialization and modern MCP discovery over stdio. MCP Apps, resumable tasks and remote hosting are not required by this bridge and are not advertised as supported integrations.

Published app documentation lives in Ascii-Motion-Web/docs-site, mounted at packages/web in the app repository.

MIT License. See LICENSE.

Available Tools

96 tools
add_content_frameB

Add a new content frame (canvas data segment) to a layer at a specific timeline position.

Inputs: layerId (required), startFrame (required), durationFrames (required), data.

add_effect_blockA

Add a non-destructive procedural effect to a layer, group, or global effects. Available types: levels, hue-saturation, remap-colors, remap-characters, scatter, wave-warp, wiggle.

Inputs: ownerId (required), effectType (required), startFrame, durationFrames, +1 more.

add_effect_keyframeA

Add a keyframe to a procedural effect property. Creates the property track if it doesn't exist.

Inputs: blockId (required), propertyPath (required), frame (required), value (required).

add_frameC

Add a new frame to the animation

Inputs: atIndex, duration, copyFromIndex, name.

add_keyframeA

Add a keyframe to a layer property track. Creates the property track if it doesn't exist.

Inputs: layerId (required), propertyPath (required), frame (required), value (required), +1 more.

add_layerA

Add a new layer to the project. If project is in legacy frame mode, this switches it to layer mode.

Inputs: name.

apply_effectC

Apply a visual effect to the current frame or selection. Effects modify colors and/or characters.

Inputs: effect (required), brightness, contrast, hue, +10 more.

apply_to_selectionC

Apply an operation to all cells in the current selection

Inputs: operation (required), char, color, bgColor.

batch_recolorB

Replace one color with another across the entire frame or selection.

Inputs: oldColor (required), newColor (required), target, frameIndex.

batch_replace_charA

Replace one character with another across the entire frame or selection.

Inputs: oldChar (required), newChar (required), frameIndex.

clear_canvasA

Clear all cells on the current frame, leaving it empty

Inputs: no named parameters.

clear_cellA

Clear a cell, resetting it to empty (space with transparent background)

Inputs: x (required), y (required).

clear_selectionA

Clear the current selection (deselect)

Inputs: no named parameters.

compare_framesB

Compare two frames and show what cells changed between them. Useful for understanding motion and edits in an animation.

Inputs: frameA (required), frameB (required), showUnchanged.

copy_frame_and_modifyA

Duplicate a frame and apply modifications in a single operation. Efficient for creating animation sequences.

Inputs: sourceIndex (required), modifications (required), insertAtIndex, name, +1 more.

copy_region_to_frameC

Copy a region of cells from one frame to another

Inputs: sourceFrame (required), targetFrame (required), sourceRegion (required), targetPosition, +1 more.

create_groupB

Create a layer group to organize layers together.

Inputs: name, layerIds.

delete_frameA

Delete a frame from the animation. Cannot delete the last remaining frame.

Inputs: index (required).

delete_selection_contentB

Delete all cell content within the current selection

Inputs: no named parameters.

describe_animationA

Get a high-level description of the animation: frame count, timing, and motion patterns.

Inputs: no named parameters.

duplicate_frameB

Duplicate a frame, inserting the copy immediately after the original

Inputs: index (required).

duplicate_layerA

Duplicate a layer with all its content frames and property tracks.

Inputs: layerId (required).

export_ansiB

Export the current frame with ANSI escape codes for terminal display.

Inputs: frameIndex, colorMode.

export_bubbleteaA

Export the current frame as a Bubbletea (Go TUI) component.

Inputs: filePath, frameIndex, packageName, modelName, +1 more.

export_htmlB

Export the animation as a self-contained HTML file with embedded animation player.

Inputs: filePath, backgroundColor, fontFamily, fontSize, +3 more.

export_imageA

Export the current frame as an image (PNG, JPG, or SVG). The browser renders the image at full quality. Requires live mode with a connected browser.

Inputs: filePath (required), format, sizeMultiplier, includeGrid, +2 more.

export_inkA

Export the current frame as an Ink (React CLI) component for Node.js terminal apps.

Inputs: filePath, frameIndex, componentName, includeAnimation.

export_jsonA

Export the project as structured JSON data. Good for programmatic processing.

Inputs: filePath, includeMetadata, humanReadable, includeEmptyCells.

export_opentuiB

Export the current frame as an OpenTUI (Python TUI) component.

Inputs: filePath, frameIndex, className, includeAnimation.

export_reactB

Export the animation as a React component (JSX or TSX).

Inputs: filePath, typescript, includeControls, componentName.

export_sessionA

Export the project as an .asciimtn session file (can be loaded by Ascii-Motion app).

Inputs: filePath (required).

export_textA

Export the current frame or all frames as plain text (.txt). Returns ASCII art as text.

Inputs: filePath, frameIndex, allFrames, trimEmpty, +1 more.

export_videoA

Export the animation as a video file (MP4 or WebM). The browser renders each frame and encodes the video. Requires live mode with a connected browser.

Inputs: filePath (required), format, sizeMultiplier, frameRate, +4 more.

fill_regionB

Fill a region with a character and colors. Can be contiguous (flood fill) or global (all matching cells).

Inputs: x (required), y (required), char (required), color, +5 more.

flip_regionB

Flip/mirror content horizontally or vertically

Inputs: direction (required), region, frameIndex.

get_active_colorsA

Get the currently active foreground and background colors.

Inputs: no named parameters.

get_auth_tokenA

Get the authentication token for browser connection.

Inputs: no named parameters.

get_canvas_asciiA

Get the canvas as raw ASCII text (characters only, no color info). Good for verifying visual appearance.

Inputs: frameIndex, region, trimEmpty, overlayPreviousFrame.

get_canvas_previewB

Get non-empty cells in a region. Use for inspecting specific areas.

Inputs: frameIndex, region, maxCells.

get_canvas_summaryA

Get a compact summary of the canvas (dimensions, fill count, bounding box). Use this first to understand the canvas before requesting more detail.

Inputs: frameIndex.

get_cellA

Get the character and colors at a specific canvas position

Inputs: x (required), y (required), frameIndex.

get_character_paletteA

Get all characters from a specific palette.

Inputs: paletteId (required).

get_color_paletteB

Get all colors from a specific palette.

Inputs: paletteId (required).

get_color_statsA

Get statistics about colors used in the current frame. Useful before applying color effects.

Inputs: frameIndex, includeBackground.

get_connection_statusA

Check browser connection status. Returns whether browser is connected and client count

Inputs: no named parameters.

get_effect_blocksA

List all procedural effect blocks across layers, groups, and global effects. Shows effect type, timing, enabled status, and keyframe count.

Inputs: ownerId.

get_frame_diffA

Get the cells that differ between two frames. Useful for understanding animation changes.

Inputs: frameA (required), frameB (required), maxCells.

get_history_statusA

Check if undo/redo is available and what actions can be undone/redone

Inputs: no named parameters.

get_layer_propertiesA

Get all transform property values for a layer at the current frame, including keyframe status.

Inputs: layerId (required).

get_layersA

Get all layers in the project with their metadata, content frame count, and property track info.

Inputs: no named parameters.

get_project_infoC

Get information about the current project

Inputs: no named parameters.

get_selectionB

Get the current selection bounds and contents

Inputs: includeCells, maxCells.

go_to_frameB

Navigate to a specific frame, making it the current/active frame

Inputs: index (required).

import_ascii_textC

Import ASCII art from a plain text file onto the canvas.

Inputs: filePath (required), frameIndex, offsetX, offsetY, +3 more.

import_imageB

Import an image file and convert it to ASCII art on the canvas. Requires optional "sharp" or "jimp" package for image processing.

Inputs: filePath (required), targetWidth, targetHeight, charset, +5 more.

import_videoB

Import a video file and convert each frame to ASCII art animation. Requires ffmpeg and optional image processing package.

Inputs: filePath (required), targetWidth, targetHeight, charset, +5 more.

interpolate_framesC

Generate intermediate frames between two keyframes. Creates smooth transitions.

Inputs: startFrame (required), endFrame (required), steps (required), method.

list_character_palettesA

List all available character palettes for ASCII art.

Inputs: no named parameters.

list_color_palettesB

List all available color palettes.

Inputs: no named parameters.

list_framesA

List all frames in the animation with their metadata

Inputs: no named parameters.

list_project_filesB

List all .asciimtn project files in the project directory

Inputs: recursive.

load_projectA

Load a project from a .asciimtn file

Inputs: filePath (required).

new_projectA

Create a new empty project, discarding any unsaved changes

Inputs: width, height, name, template.

paste_ascii_blockB

Paste a multi-line ASCII art block onto the canvas at a specified position. Great for pasting found ASCII art.

Inputs: text (required), x, y, color, +2 more.

preview_generatorA

Preview a single frame from a generator without applying to the project.

Inputs: generator (required), color, density, seed.

redoA

Redo the last undone action

Inputs: no named parameters.

refresh_state_from_browserA

Request the browser to send its current state. Use this before reading canvas data to ensure you have the latest state. Returns success if browser is connected and responded.

Inputs: no named parameters.

remove_content_frameB

Remove a content frame from a layer.

Inputs: layerId (required), contentFrameId (required).

remove_effect_blockB

Remove a procedural effect block from its owner (layer, group, or global).

Inputs: blockId (required).

remove_effect_keyframeB

Remove a keyframe from a procedural effect property track.

Inputs: blockId (required), keyframeId (required).

remove_keyframeC

Remove a keyframe from a property track.

Inputs: layerId (required), trackId (required), keyframeId (required).

remove_layerA

Remove a layer by ID. Cannot remove the last remaining layer.

Inputs: layerId (required).

rename_layerB

Rename a layer.

Inputs: layerId (required), name (required).

reorder_layersB

Move a layer from one z-order position to another. Index 0 = bottom layer.

Inputs: fromIndex (required), toIndex (required).

resize_canvasA

Resize the canvas. Content outside the new bounds will be clipped.

Inputs: width (required), height (required).

run_generatorC

Generate procedural animation frames. Creates new frames with animated patterns.

Inputs: generator (required), frameCount, frameDuration, color, +16 more.

save_projectB

Save the current project to a .asciimtn file

Inputs: filePath (required).

select_by_colorA

Select cells that match specific criteria (magic wand style)

Inputs: x (required), y (required), matchChar, matchColor, +2 more.

select_rectangleC

Select a rectangular region of the canvas

Inputs: x (required), y (required), width (required), height (required).

set_active_layerA

Set which layer is active for drawing and editing operations.

Inputs: layerId (required).

set_background_colorB

Set the active background color.

Inputs: color (required).

set_cellA

Set the character and/or colors at a specific canvas position

Inputs: x (required), y (required), char, color, +1 more.

set_cells_batchA

Set multiple cells in a single operation. More efficient than calling set_cell repeatedly.

Inputs: cells (required).

set_foreground_colorB

Set the active foreground (text) color.

Inputs: color (required).

set_frame_durationB

Set the duration of a frame in milliseconds

Inputs: index (required), duration (required).

set_frame_nameB

Set or change the name of a frame

Inputs: index (required), name (required).

set_frame_rateA

Set the timeline frame rate (FPS). Preserves frame count — only changes playback speed.

Inputs: fps (required).

set_layer_visibilityC

Set visibility, solo, lock, or opacity on a layer.

Inputs: layerId (required), visible, solo, locked, +1 more.

set_project_nameC

Set the project name

Inputs: name (required).

set_selected_characterB

Set the active character used for drawing.

Inputs: character (required).

set_timeline_durationA

Set the total timeline duration in frames.

Inputs: durationFrames (required).

shift_frame_contentA

Shift all content on the current frame by an x/y offset. Useful for creating scrolling or movement animations.

Inputs: dx (required), dy (required), wrap, frameIndex.

suggest_palette_for_styleC

Get palette recommendations for a specific style.

Inputs: style (required).

undoB

Undo the last action

Inputs: no named parameters.

ungroup_layersA

Dissolve a layer group, keeping the layers.

Inputs: groupId (required).

update_effect_blockB

Update a procedural effect block's settings, timing, or enabled state.

Inputs: blockId (required), startFrame, durationFrames, enabled, +1 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 96 tools

    Disambiguation4/5

    Tools are generally distinct with clear descriptions, but the large number (96) and several overlapping operations (e.g., multiple add/export/get tools) may cause minor confusion for an agent. Most tools have unique purposes.

    Naming Consistency4/5

    The majority follow a verb_noun pattern (e.g., add_, get_, set_, export_), but there are inconsistencies like 'remove' vs 'delete' and phrases like 'refresh_state_from_browser' or 'suggest_palette_for_style'.

    Tool Count2/5

    With 96 tools, the server far exceeds the typical well-scoped range. While many features are justified, the sheer number makes the surface feel heavy and harder for an agent to navigate efficiently.

    Completeness5/5

    The tool surface is exceptionally complete, covering project management, frame and layer operations, cell editing, effects, imports/exports, selection, palettes, undo/redo, and browser connectivity. No obvious gaps.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      A
      quality
      C
      maintenance
      Exposes ASCIIFlow drawing primitives as tools to enable AI assistants to generate ASCII wireframes and diagrams from natural language descriptions. It provides commands for creating canvases and drawing boxes, lines, arrows, and text using a character-grid coordinate system.
      8
      2
      -
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to create loop-perfect generative ASCII animations headlessly, including defining custom animations and 3D shapes as expression strings.
      55 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI assistants to drive Aseprite for pixel-art creation, including sprite setup, grid-based drawing, layer/frame/tag management, reference image import, and export, with rendered previews after every mutation.
      MIT