Repository navigation
For developers
How Surehand MCP is built, tested and released. For using it, start at Home.
AI app ──MCP (stdio or HTTP)──> server (Node.js, server/dist/surehand-ae.mjs)
│ HTTP on 127.0.0.1, token
▼
bridge (CEP extension inside After Effects, com.aemcp.bridge)
│ CEP evalScript
▼
ExtendScript (aemcp.jsxinc helpers)
- The server is TypeScript bundled into one file. It defines the tools, transpiles modern JavaScript to ES3 with Babel, computes change reports, logs activity, runs Preflight's ffmpeg checks and aerender, and has the command-line commands (install, selftest, update…).
-
The bridge is an invisible CEP extension that starts with After Effects (
StartOn: ApplicationInitialized). It runs a small HTTP server on127.0.0.1(port 8765, or the next free one of 10), runs one script at a time, holds approvals and the pause, and registers itself in~/.surehand/ae/instances/. -
The panel (
com.aemcp.panel) and the approval pop-up (com.aemcp.approval) are CEP extensions in the same bundle. They talk to the bridge over the same HTTP API, and get the panel secret through CEP events (com.surehand.ae.hello→com.surehand.ae.welcome). - The extension is embedded in the server bundle at build time; the server installs or updates it when it starts.
server/ MCP server (TypeScript) -> bundled into server/dist/surehand-ae.mjs (committed)
src/aemcp.jsxinc ExtendScript helper library, loaded into After Effects on demand
src/tools/ tool definitions (each is a zod input schema + an ExtendScript function body)
src/preflight/ Preflight: spec schema, project checks, ffmpeg checks, report
src/cli/ install, uninstall, selftest, chatgpt, setup, update, clients, checkpoints…
src/paths.ts every name and folder (surehand-ae, ~/.surehand/ae…)
src/migrate.ts the move from 1.3's ~/.aemcp
src/permissions.ts modes, shell check, approval texts
test/ unit tests (vitest)
scripts/smoke.mjs end-to-end test against a running After Effects
scripts/package.mjs builds the release folder, zip and .mcpb
scripts/release.mjs cuts a release (see below)
scripts/test-mac.mjs installs this build on this Mac and runs the full self-test on each open After Effects
scripts/test-windows.mjs the same on a Windows PC over SSH
scripts/sign-extension.mjs signs the After Effects extension
scripts/package-mac-pkg.mjs the signed, notarized Mac installer (.pkg)
scripts/package-win-installer.mjs the Windows installer (.exe, NSIS, built on the Mac)
scripts/sign-win.mjs signs Windows files (Certum certificate via SimplySign)
scripts/ci-check.mjs assertions for the CI install / uninstall runs
extension/ After Effects extension (signed): bridge, panel, approval pop-up
js/bridge-core.js the bridge: HTTP API, queue, approvals, pause
js/panel.js, panel-model.js the panel (panel-model.js is pure and unit-tested)
js/approval.js the pop-up
js/control.js the panel secret handshake
js/paths.js the same folder rules as server/src/paths.ts
installer/ run.sh / run.ps1 (find or download Node.js, run a command), START HERE.txt
mac/, windows/ double-click launchers for a source checkout
mac/pkg/ .pkg resources and postinstall
windows/nsis/ the NSIS script
brand/ the logo: SVG masters, PNGs, Surehand.icns, Surehand.ico (see brand/README.md)
.github/workflows/ci.yml CI
cd server
npm install
npm run check # what CI runs: type-check, all unit tests, build. Run before every push.
npm test # unit tests only
npm run build # -> dist/surehand-ae.mjsserver/dist/surehand-ae.mjs is committed. CI rebuilds it and fails if the committed file differs, so commit the
rebuilt bundle with your change.
After changing the server or the panel: rebuild, re-run the installer (or node dist/surehand-ae.mjs install),
restart After Effects. After Effects only loads extension changes when it starts.
node scripts/smoke.mjs # calls all major tools; needs After Effects running with the bridge
npm run test:mac # installs this build here (AI app settings untouched) and runs the full self-test
# on each open After Effects; one run per Mac at a time (~/.surehand/test-mac.lock)
npm run test:windows # the same on a Windows PC over SSH (host in the script, or AEMCP_WIN_HOST)--allow-no-ae lets either test pass when no After Effects is open. An After Effects that was open before the
install keeps running the previous extension; the test says so.
surehand-ae selftest checks the installation and the connection. selftest --full runs every major tool (over
60 steps) against temporary comps, which are removed afterwards. If the open project has no unsaved changes, the Save
As and checkpoint-restore checks briefly switch to a scratch project and reopen yours. It lists which scripting
features your After Effects version has and saves a report to ~/.surehand/ae/compat/.
All steps pass on After Effects 2025 (25.6) and 2026 (26.5) on macOS, and on 2026 on Windows 11, also with 2025 and 2026 running side by side. Reports from other versions are welcome.
Add an entry to one of the arrays in server/src/tools/*.ts: a zod input schema and an ExtendScript function body
that receives args and can use the aemcp helpers. Mark tools that only read as readOnly (they skip approvals,
the undo group and the change report, and work in Read-only mode). Add it to a category in
server/src/tools/profile.ts so ae_tools lists it.
npm run sign # after changing anything in extension/ or the versionThe version is stamped into the extension's files, so the signature must be redone after a version bump; npm test
fails while it is out of date. Signing needs Adobe's ZXPSignCmd and the certificate outside the repo (see the header
of scripts/sign-extension.mjs; override with AEMCP_SIGN_DIR / AEMCP_ZXPSIGNCMD). CI only verifies the digests.
npm run package # -> ../dist-zip/Surehand-MCP/ (launchers, server, Surehand-MCP.mcpb) + zip
npm run package:mac-pkg # -> ../dist-zip/Surehand-MCP-<version>.pkg, signed and notarized (--no-notarize: faster)
npm run package:win-installer # -> ../dist-zip/Surehand-MCP-Setup-<version>.exe (--sign: Authenticode, needs SimplySign)- The
.pkgbundles Node.js 24 LTS (universal arm64 + x86_64, re-signed with the Developer ID) and needs the Developer ID Application and Installer identities plus the notarization keychain profileaemcp-notary. - The Setup
.exebundles the official win-x64node.exe, checked against a pinned SHA-256 and nodejs.org'sSHASUMS256.txt, and is built with NSIS on the Mac.
npm run release -- 1.4.0 --notes notes.mdscripts/release.mjs does everything in order and stops at the first failure:
- version bump;
- sign the After Effects extension;
- check (types, tests, build);
- Mac and Windows live tests (
--skip-mac,--skip-windowsto skip); - package, then the signed installers (
--skip-installersto skip); - a
release/X.Y.Zbranch and its pull request; - wait for the PR's CI;
- squash-merge, and check the merged tree equals the tested commit;
- the GitHub release on the merged commit, with the zip, the
.mcpb, the installers and the server file (surehand-ae.mjs, also asae-mcp.mjsfor 1.3's updater, each with a.sha256).
main only accepts changes through a pull request with green CI, which is why the release goes through its own PR.
Nothing is pushed until everything local has passed. If the PR's CI fails, main is untouched and nothing is
published. Run it from a clean main that matches origin/main.
A pre-release version (1.4.0-beta.1) becomes a GitHub pre-release, which surehand-ae update offers only on the
beta channel (--channel beta, or Beta updates in the panel). --draft
creates a draft release.
.github/workflows/ci.yml, on every push to main and every pull request:
| Job | What it does |
|---|---|
test (Ubuntu) |
npm ci, type-check, unit tests, rebuild and fail if server/dist is stale, shellcheck run.sh, parse run.ps1
|
install (macOS and Windows) |
Builds the release folder, then on a fake, empty user profile runs the real launchers: 1. Install (with a forced Node.js download), 2. Test Installation, 4. Uninstall, and checks the result with ci-check.mjs
|
There is no After Effects on CI; the live tests are test:mac and test:windows.
The installed server is also the command-line tool. Run it with the Node.js the installer used:
node ~/.surehand/ae/server/surehand-ae.mjs <command>| Command | What it does |
|---|---|
| (none) | The MCP server over stdio. --tools core|full picks the tool profile. |
--http [--port 8766] [--host 127.0.0.1] [--no-auth] |
The MCP server over Streamable HTTP at /mcp (token required). |
install [--skip-clients] [--no-<app>] |
Install the server and extension; connect AI apps (--no-claude-desktop, --no-vscode…). |
uninstall [--keep-config] [--all] |
Uninstall; keeps checkpoints and files that aren't Surehand's unless --all. |
selftest [--full] |
Check the installation (and with --full, every major tool). |
test --json |
The quick self-test as JSON (the panel's Connection test). |
diagnostics |
A report for a bug report, with no secrets. |
activity [n] |
The last n tool calls (default 30). |
chatgpt [--local] |
HTTP server and public tunnel for ChatGPT on the web, in the terminal; Ctrl+C stops it. |
chatgpt --background|--status|--stop [--json] |
The same in the background (the panel's ChatGPT screen). |
update [--json], update --check [--json]
|
Install the latest release; or only report. --channel beta|stable also sets the update channel. |
clients [--json] |
The AI apps on this computer and whether they are connected. |
connect <app> [--json], disconnect <app> [--json]
|
claude-desktop, claude-code, codex, cursor, vscode, windsurf, lm-studio. |
skills [--json], skills install|uninstall [--json]
|
Where the Surehand skills are installed; write or remove them. |
farm check <manifest.json> [--map <from>=<to>] [--ae <folder>] [--json] |
On a render node, without After Effects: does it have what the render needs? Exit code 0 ready, 1 missing or different, 3 not everything checked. |
chat --agents --json, chat --agent <id>
|
The panel's Chat in After Effects (see docs/chat-in-ae.md). |
checkpoints [--json] [--project <path>] |
A project's checkpoints (default: the open one). |
checkpoint-diff <id> [--json] [--project <path>] |
What changed since a checkpoint (needs After Effects). |
checkpoint-save [--label <text>] [--project <path>] [--json] |
Save the open project and checkpoint it. |
setup [--force] |
Only install or update the After Effects extension and config. |
--version, --help
|
ae-mcp is an alias of surehand-ae. With --json, the panel's commands print one JSON object and never ask
anything; an unknown command exits with an error instead of starting the server.
Environment variables are listed in Settings and files. For testing:
SUREHAND_AE_FORCE_NODE_DOWNLOAD=1 makes the launchers ignore a system Node.js.
The family is Surehand, so this app's names are surehand-ae: the command, the server file, the MCP server name and
the key in AI app settings, and the folders ~/.surehand/ae (this app) and ~/.surehand (shared). All are in
server/src/paths.ts. Unchanged so that scripts and the extension keep working: the tool names (ae_*), the
extension id com.aemcp (and its bundle ids), the aemcp helper object and the aemcp:// resource addresses. The
npm package name is surehand-mcp. Environment variables are SUREHAND_AE_*; the older AEMCP_* names
still work (for example AEMCP_TOOLS), and the command ae-mcp stays as an alias.
1.3 kept everything in ~/.aemcp, ran as after-effects in AI app settings, and its panel was named differently.
The first time 1.4 runs (installer, update, or simply starting the server), server/src/migrate.ts moves it:
| 1.3 | 1.4 | |
|---|---|---|
| Folder | ~/.aemcp |
~/.surehand/ae (this app), ~/.surehand (shared) |
| Server file | ~/.aemcp/server/ae-mcp.mjs |
~/.surehand/ae/server/surehand-ae.mjs |
| Private Node.js / ffmpeg |
~/.aemcp/node, ~/.aemcp/ffmpeg
|
~/.surehand/node, ~/.surehand/ffmpeg
|
| Name in AI app settings | after-effects |
surehand-ae |
| Command | ae-mcp |
surehand-ae (ae-mcp still works) |
| Environment variables | AEMCP_* |
SUREHAND_AE_* (AEMCP_* still work) |
| Claude Desktop extension | after-effects |
surehand-ae |
- Settings, checkpoints, project history and other files go to
~/.surehand/ae; Node.js and ffmpeg to~/.surehand. Files are renamed, not copied. Where a file of the same name already exists, the old one arrives as<name>.from-aemcp. - AI apps that ran the old server are pointed at the new one:
after-effectsbecomessurehand-ae. Anafter-effectsentry that runs some other server is left alone. A 1.3 backup<file>.aemcp.bakcounts as the first original. - If anything can't be moved, the move is undone and retried later (
~/.surehand/migration.log); Copy diagnostics shows "(1.3 location, not migrated yet)" meanwhile. - Until After Effects restarts, the 1.3 extension still reads
~/.aemcp, which keeps a copy ofconfig.json, an emptyinstancesfolder, a smallserver/ae-mcp.mjsthat starts the new server, anodelink to the moved Node.js andMOVED.txt. The 1.4 server accepts the old extension's token meanwhile, and settings the 1.3 panel saves there are picked up later. Uninstalling 1.4 removes these compatibility files; files of yours that stayed in~/.aemcpare kept. - The 1.4 release also carries the server as
ae-mcp.mjs, the file 1.3's updater downloads.
- Open an issue first for anything larger than a fix.
- Run
npm run checkbefore pushing, and commit the rebuiltserver/dist. - If you change
extension/, it must be re-signed (npm run sign); a maintainer does this if you can't. - Keep the user-facing language plain and precise; error messages say what happened and what to do.
- Changes reach
mainthrough a pull request with green CI.
Licence: MIT. Created and maintained by Ron Yitzhaki.
Start here
Using Surehand
- The Surehand panel
- Approvals
- What the AI can do
- Precision tools
- Checkpoints
- Proven edits
- Project history
- Project X-ray
- Precomp surgery
- Preflight
- Stress test
- Versions, localization and reformat
- Rendering
- Render speed, handoff and farms
- Chat in After Effects
- In-chat views
Reference
Developers