npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

adobe-mcp-core

v0.2.0

Published

Shared foundation for MCP servers that drive Adobe InDesign, Illustrator and other desktop Adobe applications through ExtendScript

Readme

adobe-mcp-core

The shared foundation for MCP servers that drive desktop Adobe applications through ExtendScript: adobe-mcp-illustrator, and adobe-mcp-indesign, whose infrastructure it was extracted from.

Each server keeps what is specific to its application: tool definitions, handlers, enum lists, server instructions, and how the application is told to run a script file. Everything else lives here, so a fix to escaping, path checks, result handling or the script runner reaches every server at once.

What it provides

| Module | Purpose | |---|---| | str, num, index, bool, enumOf, json, numList, measure | Turn caller input into safe ExtendScript literals. ExtendScript is not sandboxed, so no caller value is ever interpolated raw. | | createPathPolicy({ envVar }) | Confine file paths to the home folder plus the directories in envVar, and never a system directory. | | wrapScriptForStructuredResult, parseStructuredResult | Make any script evaluate to {"ok":…,"result"|"error":…} using only ES3, and parse it back. | | looksLikeFailure, createFailureDetector, formatResponse | One result shape; failure strings ("No document open", "Error …") become success: false. | | createArgNormalizer | Canonical parameter names, deprecated aliases with warnings, and "did you mean" for unknown arguments. | | createAnnotations | MCP tool annotations from explicit read-only, destructive, idempotent and open-world lists. | | createExecutor(app) | Run a script in the application: AppleScript on macOS, COM through PowerShell on Windows, optional extra backends. | | createMcpServer | The stdio server: tools/list, tools/call, alias mapping, warnings, error results. | | adobe-mcp-core/testing | The static script audit: run every tool with sample arguments against a stubbed executor, then check each generated script parses as ES5 and uses only names in the application's type definitions. |

The executor

import { createExecutor, appleScriptString, powerShellString } from 'adobe-mcp-core';

export const executor = createExecutor({
    label: 'Illustrator',
    envPrefix: 'ILLUSTRATOR',              // ILLUSTRATOR_APP_NAME, ILLUSTRATOR_SCRIPT_TIMEOUT_MS, ILLUSTRATOR_BACKEND
    appNamePrefix: 'Adobe Illustrator',
    defaultAppName: 'Adobe Illustrator',
    macScript: ({ scriptPath }) => `do javascript (POSIX file ${appleScriptString(scriptPath)})`,
    winProgIds: ['Illustrator.Application'],
    winInvoke: ({ scriptPath }) => `$app.DoJavaScriptFile(${powerShellString(scriptPath)})`,
    winProcessName: 'Illustrator.exe',
});

const name = await executor.runScript('app.activeDocument.name;');
const { ok, result, error } = await executor.runStructured('app.documents.length;');
  • Scripts go to the application as a temporary .jsx file, removed afterwards.
  • An application with no COM scripting object on Windows passes winRun, which runs the .jsx some other way and resolves with its result (After Effects runs scripts with AfterFX.exe -r).
  • Processes start with execFile, never a shell, and never block the event loop.
  • Every run has a timeout (<PREFIX>_SCRIPT_TIMEOUT_MS, default 120 s). On timeout the error says a dialog may be open in the application, which is the usual cause.
  • backends adds alternatives to ExtendScript, such as InDesign's UXP bridge. <PREFIX>_BACKEND=auto uses the first available one and falls back to ExtendScript only when the backend could not have run the script.

The server

import { createMcpServer } from 'adobe-mcp-core';

const mcp = createMcpServer({
    info: { name: pkg.name, version: pkg.version },
    instructions: SERVER_INSTRUCTIONS,
    tools,                                  // definitions with title and annotations
    handlers: { get_document_info: getDocumentInfo, /* one per tool */ },
    aliases: [{ old: 'strokeWidth', canonical: 'strokeWeight' }],
});
await mcp.run();

Construction fails if an advertised tool has no handler.

Tests

npm test        # node --test
npm run check   # syntax check of src/

Licence

MIT. See LICENSE.