Snail.MCP.AfterEffects
0.1.0
{ "inputs": [ { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_DATA_DIRECTORY", "description": "This server's own files: the token the bridge presents, the announcements the bridge reads to find running servers, captured frames. Default: ~/.s3l-mcp-aftereffects." }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_PROJECT_DIRECTORY", "description": "The project folder: captures and renders asked for without a path land in it. Default: the folder the client starts the server in." }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_BRIDGE__PORT", "description": "Port the server listens on for the bridge inside After Effects; 0 takes a free one, which the announcement under the data directory names.", "default": "0" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_BRIDGE__LISTEN", "description": "The address the bridge listener binds; empty binds the loopback for a loopback host and every interface otherwise.", "default": "" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_BRIDGE__HOST", "description": "The address the bridge inside After Effects dials to reach this server, written into the announcement; in a container the server's service name.", "default": "127.0.0.1" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_BRIDGE__REQUEST_TIMEOUT_SECONDS", "description": "Seconds to wait for one bridge reply; renders and imports use their own longer timeout.", "default": "30" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_BRIDGE__TOKEN", "description": "Shared secret the bridge presents when it connects; empty reads the token file.", "password": true }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_BRIDGE__TOKEN_FILE", "description": "Where that token lives. Default: <data>/state/token." }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_IDLE_TIMEOUT_MINUTES", "description": "Minutes without a tool call after which the process exits on its own; 0, the default, disables the watchdog, since a client that ends closes the pipe and the server exits with it.", "default": "0" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_SKILL_IDLE_MINUTES", "description": "Minutes a loaded skill may go unused before its tools leave the catalog; 0 keeps skills loaded.", "default": "0" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_FARM_PARALLEL", "description": "How many aerender renders the farm runs at once; 1 renders jobs one after another.", "default": "1" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_AGENT", "description": "Name this server signs its requests with, so the bridge's journal tells agents apart." }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_CONFIG", "description": "Path of the settings file, with the same keys under a Snail section; when set, it is the only file read, and none is read if it does not exist." }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_SCRIPTING", "description": "allow (the default) offers ae_script, which runs any ExtendScript; off hides it, and refuses run_tools lists that carry a script step.", "default": "allow" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_TRANSPORT", "description": "Stdio when the client starts this server over stdio (the default); Http to run it on its own beside After Effects and let clients connect with keys.", "default": "Stdio" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_HTTP__URL", "description": "Where the HTTP server listens; a container listens on http://0.0.0.0:8080.", "default": "http://127.0.0.1:8080" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_HTTP__TOKEN", "description": "The token clients present as a bearer; the configured token holds every scope. Prefer keys minted with the clients command.", "default": "" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_HTTP__TOKEN_FILE", "description": "A file holding the token, the way a container receives a secret.", "default": "" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_HTTP__PUBLIC_URL", "description": "The address clients reach the server at behind a reverse proxy, which links to files are built on.", "default": "" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_HTTP__LINK_MINUTES", "description": "Minutes a signed link to a file stays valid.", "default": "15" }, { "type": "promptString", "id": "SNAIL_MCP_AFTEREFFECTS_HTTP__UPLOAD_PART_MB", "description": "Megabytes an upload sends in one request, which a reverse proxy must read within its own body timeout.", "default": "16" } ], "servers": { "Snail.MCP.AfterEffects": { "type": "stdio", "command": "dnx", "args": ["Snail.MCP.AfterEffects@0.1.0", "--yes"], "env": { "SNAIL_MCP_AFTEREFFECTS_DATA_DIRECTORY": "${input:SNAIL_MCP_AFTEREFFECTS_DATA_DIRECTORY}", "SNAIL_MCP_AFTEREFFECTS_PROJECT_DIRECTORY": "${input:SNAIL_MCP_AFTEREFFECTS_PROJECT_DIRECTORY}", "SNAIL_MCP_AFTEREFFECTS_BRIDGE__PORT": "${input:SNAIL_MCP_AFTEREFFECTS_BRIDGE__PORT}", "SNAIL_MCP_AFTEREFFECTS_BRIDGE__LISTEN": "${input:SNAIL_MCP_AFTEREFFECTS_BRIDGE__LISTEN}", "SNAIL_MCP_AFTEREFFECTS_BRIDGE__HOST": "${input:SNAIL_MCP_AFTEREFFECTS_BRIDGE__HOST}", "SNAIL_MCP_AFTEREFFECTS_BRIDGE__REQUEST_TIMEOUT_SECONDS": "${input:SNAIL_MCP_AFTEREFFECTS_BRIDGE__REQUEST_TIMEOUT_SECONDS}", "SNAIL_MCP_AFTEREFFECTS_BRIDGE__TOKEN": "${input:SNAIL_MCP_AFTEREFFECTS_BRIDGE__TOKEN}", "SNAIL_MCP_AFTEREFFECTS_BRIDGE__TOKEN_FILE": "${input:SNAIL_MCP_AFTEREFFECTS_BRIDGE__TOKEN_FILE}", "SNAIL_MCP_AFTEREFFECTS_IDLE_TIMEOUT_MINUTES": "${input:SNAIL_MCP_AFTEREFFECTS_IDLE_TIMEOUT_MINUTES}", "SNAIL_MCP_AFTEREFFECTS_SKILL_IDLE_MINUTES": "${input:SNAIL_MCP_AFTEREFFECTS_SKILL_IDLE_MINUTES}", "SNAIL_MCP_AFTEREFFECTS_FARM_PARALLEL": "${input:SNAIL_MCP_AFTEREFFECTS_FARM_PARALLEL}", "SNAIL_MCP_AFTEREFFECTS_AGENT": "${input:SNAIL_MCP_AFTEREFFECTS_AGENT}", "SNAIL_MCP_AFTEREFFECTS_CONFIG": "${input:SNAIL_MCP_AFTEREFFECTS_CONFIG}", "SNAIL_MCP_AFTEREFFECTS_SCRIPTING": "${input:SNAIL_MCP_AFTEREFFECTS_SCRIPTING}", "SNAIL_MCP_AFTEREFFECTS_TRANSPORT": "${input:SNAIL_MCP_AFTEREFFECTS_TRANSPORT}", "SNAIL_MCP_AFTEREFFECTS_HTTP__URL": "${input:SNAIL_MCP_AFTEREFFECTS_HTTP__URL}", "SNAIL_MCP_AFTEREFFECTS_HTTP__TOKEN": "${input:SNAIL_MCP_AFTEREFFECTS_HTTP__TOKEN}", "SNAIL_MCP_AFTEREFFECTS_HTTP__TOKEN_FILE": "${input:SNAIL_MCP_AFTEREFFECTS_HTTP__TOKEN_FILE}", "SNAIL_MCP_AFTEREFFECTS_HTTP__PUBLIC_URL": "${input:SNAIL_MCP_AFTEREFFECTS_HTTP__PUBLIC_URL}", "SNAIL_MCP_AFTEREFFECTS_HTTP__LINK_MINUTES": "${input:SNAIL_MCP_AFTEREFFECTS_HTTP__LINK_MINUTES}", "SNAIL_MCP_AFTEREFFECTS_HTTP__UPLOAD_PART_MB": "${input:SNAIL_MCP_AFTEREFFECTS_HTTP__UPLOAD_PART_MB}" } } } }
.vscode/mcp.json settings file.
dotnet tool install --global Snail.MCP.AfterEffects --version 0.1.0
dotnet new tool-manifest
dotnet tool install --local Snail.MCP.AfterEffects --version 0.1.0
#tool dotnet:?package=Snail.MCP.AfterEffects&version=0.1.0
nuke :add-package Snail.MCP.AfterEffects --version 0.1.0
Snail.MCP.AfterEffects
An MCP server that lets your AI assistant drive a running Adobe After Effects. It runs on the machine After Effects runs on, talks to your client over stdio, and reaches After Effects through a small ExtendScript bridge that lives in its scripts folder and dials the server on its own.
What it can do
- Always on, 40 tools: the project (new, open, save, items, folders, import), compositions, layers of every kind with their switches,
timing and transforms, the whole property tree by match name (
ae_property_tree,ae_get_property,ae_set_property), a frame of a composition as a picture (ae_capture_frame), undo and redo, menu commands, andae_scriptfor the ExtendScript nothing else reaches. - Skills, loaded on demand, 103 tools:
animation(keyframes, easing presets and curves, expressions checked for errors, markers, time remapping),text(fonts, the document with every attribute down to a range of characters, animators with range, wiggly and expression selectors, text on a path),shapes(shape layer contents by plain names, masks from rectangles, ellipses or vertices),effects(the effects catalog, effects and their parameters, animation presets, layer styles),threed(cameras, lights, materials, geometry, the renderer),compositing(precomposing, nested compositions, replacing and interpreting footage, proxies, missing files, cleanup, collecting files),rendering(the render queue, templates, rendering in place, Media Encoder) andfarm(background renders throughaerender, with a queue, progress by frame, retries and cancellation, while After Effects stays free),templates(Essential Graphics controllers, filling and substituting template compositions,.mogrtin and out),transfer(the server's files by area, uploads and downloads),layout(bounds, selection, guides, splitting and placing layers, copying between compositions),settings(project and application settings, fonts, caches, memory, preferences and script settings by key, the machine, a shell command),viewer(the viewer panel's views, channels, exposure and zoom) andworkers(an After Effects of your own: the server launches an instance, binds the client to it, and it quits when idle).ae_skillslists them andae_enable_skillloads one. - The machinery every Snail server shares:
find_toolsearches the whole catalog by what you want to do and answers with each tool's command and parameters;run_toolssends a list of steps in one call;run_programruns a small JavaScript program that calls the commands itself, for builds of many steps.
Install
dotnet tool install --global Snail.MCP.AfterEffects, then give your MCP client the commands3l-mcp-aftereffects(for Claude Code:claude mcp add aftereffects -- s3l-mcp-aftereffects). To run it from a checkout instead:dotnet build -c Releaseand the commanddotnetwithsrc/bin/Release/net10.0/Snail.MCP.AfterEffects.dllas its argument.- In After Effects open Preferences → Scripting & Expressions and switch on Allow Scripts to Write Files and Access Network, once.
- Ask the agent to run
ae_install_bridge: it copies the bridge into After Effects' userScripts/Startupfolder and starts it in the running After Effects; from then on the bridge starts with After Effects and dials every server that is running. - Ask for
ae_diagnose:afterEffects.reachableis true once the bridge is connected.
How it works
The server listens on the loopback and announces its port in ~/.s3l-mcp-aftereffects/state/servers/; the bridge, an ExtendScript
started from After Effects' Startup folder, reads that folder once a second and opens a connection to every server it finds, presenting
the token the server keeps next to its state. Requests and replies are JSON lines matched by id; the bridge serves them on After Effects'
main thread between the application's own work, every 50 to 100 ms. docs/content/architecture.md explains
why it is built this way round.
Over HTTP
The same server runs on its own beside After Effects and serves several clients over Streamable HTTP, each with a key of its own:
mkdir -p ~/.config/s3l-mcp-aftereffects
echo '{ "Snail": { "Http": { "Token": "<a long random secret>" } } }' > ~/.config/s3l-mcp-aftereffects/config.json # the operator's key, every scope
chmod 600 ~/.config/s3l-mcp-aftereffects/config.json
export SNAIL_MCP_AFTEREFFECTS_TRANSPORT=Http
export SNAIL_MCP_AFTEREFFECTS_HTTP__URL=http://0.0.0.0:8080
dotnet Snail.MCP.AfterEffects.dll clients add titles --scope read,write,farm # prints a key once
dotnet Snail.MCP.AfterEffects.dll
A client connects to /mcp with Authorization: Bearer <key>; the key names the client and says what it may do: read, write, delete
(removing items, layers and files, undo, cancelling renders), script (ExtendScript and menu commands) and farm (rendering). A call the key
does not open is refused before it reaches After Effects, inside run_tools and run_program too. Each client has a tool list of its own:
a skill one client loads is in its list and nobody else's. clients list and clients revoke <name> manage the keys; a revoked key is turned
away at once. The pages at / (sign in with any key) show the status, the files by area with previews and downloads, and the farm's jobs;
/healthz answers anyone; /raw/<area>/<path> serves and takes files with a key or a signed link, which ae_upload and ae_download hand
out as shell commands.
Settings
Every setting is an environment variable with the prefix SNAIL_MCP_AFTEREFFECTS_; .mcp/server.json lists them all. The same keys go into
a settings file under a Snail section: the one SNAIL_MCP_AFTEREFFECTS_CONFIG names, the only one read when it is set, or else the
first that exists of .s3l-mcp-aftereffects.json and s3l-mcp-aftereffects.json in the working directory,
~/.config/s3l-mcp-aftereffects/config.json, ~/.s3l-mcp-aftereffects.json; the variables win over it. A token belongs in
~/.config/s3l-mcp-aftereffects/config.json
(chmod 600), never in a launchd job or a client's registration —
docs/content/configuration.md. The ones that matter first:
| Variable | Default | Meaning |
|---|---|---|
SNAIL_MCP_AFTEREFFECTS_DATA_DIRECTORY |
~/.s3l-mcp-aftereffects |
Where the server keeps its state, token, announcements and captures |
SNAIL_MCP_AFTEREFFECTS_SCRIPTING |
Allow |
Off refuses ae_script and the script command in programs |
SNAIL_MCP_AFTEREFFECTS_SKILL_IDLE_MINUTES |
0 |
Unload a skill unused for this many minutes; 0 keeps skills loaded, which suits clients that cache the tool list |
SNAIL_MCP_AFTEREFFECTS_BRIDGE__REQUEST_TIMEOUT_SECONDS |
30 |
How long a tool waits for After Effects before answering with a timeout |
SNAIL_MCP_AFTEREFFECTS_FARM_PARALLEL |
1 |
How many aerender renders the farm runs at once |
SNAIL_MCP_AFTEREFFECTS_WORKERS__MAX |
2 |
Most After Effects workers the server launches for clients that lease one; 0 switches it off |
SNAIL_MCP_AFTEREFFECTS_WORKERS__IDLE_MINUTES |
15 |
Minutes an idle worker waits before quitting on its own |
SNAIL_MCP_AFTEREFFECTS_TRANSPORT |
Stdio |
Http runs the server on its own beside After Effects |
SNAIL_MCP_AFTEREFFECTS_HTTP__URL |
http://127.0.0.1:8080 |
Where the HTTP server listens |
SNAIL_MCP_AFTEREFFECTS_HTTP__TOKEN |
The operator's key; HTTP__TOKEN_FILE reads it from a file |
|
SNAIL_MCP_AFTEREFFECTS_HTTP__PUBLIC_URL |
The address behind a reverse proxy, which signed links are built on |
Requirements
| .NET 10 SDK | dotnet.microsoft.com/download |
| An MCP client | Claude Code, Claude Desktop, Cursor, VS Code, Codex — anything that speaks MCP over stdio |
| Adobe After Effects 2026 or newer | with Allow Scripts to Write Files and Access Network switched on in Preferences → Scripting & Expressions |
Developing
| Folder | Holds |
|---|---|
src/ |
the server: Configuration, Domain, Application, Adapters, Hosting, Extensions, and Tools — Base for the layer that is always on, one folder per skill, and Prompts for the descriptions, messages and guidance the model reads |
extension/ |
the ExtendScript bridge After Effects runs |
tests/ |
a folder per layer of src, Contracts for the guards, Support for the fakes |
dotnet build
dotnet test
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 68 | 10/25/2026 |
| 0.1.0-preview.8 | 57 | 10/25/2026 |
| 0.1.0-preview.5 | 66 | 10/24/2026 |
| 0.1.0-preview.4 | 50 | 10/24/2026 |