JCAppleScript

io.github.johnnyclemPublished by GitHub account johnnyclemv2.0.0Updated Oct 24, 2026

Control macOS apps via AppleScript/JXA: sanitized commands for Messages, Mail, Finder, and more.

Overview

AI-generated overview

A local macOS MCP server that lets an assistant control Apple apps such as Messages, Mail, Finder, Notes and Safari through AppleScript and JXA.

What you can do
Run arbitrary AppleScript or JXA code, or send a tell command to a named app, and check script syntax without executing it (these code-execution tools can be disabled in safe mode). Browse, search and inspect the built-in command sheets for 12 macOS apps, and dry-run a command to see the exact script it would run. Execute pre-built commands for Messages, Mail, Reminders, Calendar, Notes, Finder, Safari, Music, Terminal, System Settings, Xcode and Speech Recognition. List running applications and load extra community app definitions from JSON manifests.
When to use it
Useful when you want an assistant on a Mac to send messages or mail, manage reminders, calendar events, notes or files, control Music or Safari, or drive Xcode and Terminal through vetted shortcuts rather than free-form scripting.
Requirements
Runs as a local process on macOS 13.0 or later; the release ships a prebuilt universal binary bundle for Claude Desktop, or it can be built with Swift 5.9+. No authentication is declared. Optional environment variables: JCAS_SAFE_MODE and JCAS_APP_MANIFESTS. macOS automation permissions for the target apps are likely needed.
Before you install
The execute_applescript, execute_jxa and tell_application tools run arbitrary code by design; only connect trusted clients or set JCAS_SAFE_MODE=1. Registry commands flagged dangerous, such as terminal.run_command and safari.run_javascript, run shell commands or page JavaScript. Commands can send messages and email, delete reminders and move files to the trash. Community manifests loaded via JCAS_APP_MANIFESTS add third-party command definitions; preview commands before running them.

Installation

In SourceWeft

  1. Open JCAppleScript in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

JCAppleScript

A Swift package for executing AppleScript from macOS applications, featuring a built-in MCP server that lets AI assistants control macOS apps through pre-built command shortcuts.

Overview

JCAppleScript provides three components:

  1. JCAppleScript (library) - Core AppleScript execution engine
  2. AppShortcuts (library) - Registry of pre-built AppleScript commands for popular macOS apps
  3. jcas-mcp (executable) - MCP (Model Context Protocol) server for AI-driven app automation

Installation

Swift Package Manager

Add JCAppleScript to your Package.swift:

swift
dependencies: [    .package(url: "https://github.com/johnnyclem/JCAppleScript.git", from: "2.0.0")]

Then add the targets you need:

swift
.target(    name: "YourTarget",    dependencies: [        "JCAppleScript",     // Core engine only        "AppShortcuts",      // App command registry    ])

Quick Start

Using the Core Engine

swift
import JCAppleScript
let engine = AppleScriptEngine.shared
// Execute raw AppleScriptlet result = try engine.execute("""    tell application "Finder"        display dialog "Hello from Swift!"    end tell""")
// Send a command to an applicationlet output = try engine.tell(application: "Music", command: "play")
// Execute a script file with variable substitutionlet fileResult = try engine.executeFile(at: "/path/to/script.scpt", variables: ["Alice", "Hello!"])
// Execute JavaScript for Automation (JXA)let jxa = try engine.execute("Application('Music').play()", language: .javaScript)
// Check syntax without executingtry engine.checkSyntax("tell application \"Finder\" to activate")
// All execution APIs also have async variantslet asyncResult = try await engine.execute("return 40 + 2")

When embedding untrusted values in script source, escape them first:

swift
let userInput = "…"let script = "display dialog \(AppleScriptString.quoted(userInput))"

Using App Shortcuts

swift
import AppShortcuts
let registry = AppRegistry.shared
// Execute a pre-built commandlet result = try registry.executeCommand("messages.send_message", arguments: [    "recipient": "+15551234567",    "message": "Hello from JCAppleScript!"])
// Discover available commandslet commands = registry.commands(forApp: "Reminders")for cmd in commands {    print("\(cmd.id): \(cmd.name) - \(cmd.description)")}
// Search across all appslet results = registry.searchCommands("send")

Using the MCP Server

The jcas-mcp executable is a Model Context Protocol server that AI assistants (Claude, GPT, etc.) can use to control macOS applications.

It is published to the official MCP registry as io.github.johnnyclem/jcas-mcp, and each GitHub release ships a prebuilt jcas-mcp.mcpb bundle (universal macOS binary) that can be installed directly in Claude Desktop via Settings → Extensions.

Setup with Claude Desktop

Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json):

json
{  "mcpServers": {    "applescript": {      "command": "/path/to/jcas-mcp"    }  }}

Build the server:

bash
swift build -c release# Binary at: .build/release/jcas-mcp
Available MCP Tools
ToolDescription
execute_applescriptExecute arbitrary AppleScript code †
execute_jxaExecute JavaScript for Automation (JXA) code †
tell_applicationSend a command to a specific app via tell block †
check_script_syntaxCompile a script (AppleScript or JXA) without executing it
list_running_applicationsGet currently running applications
list_registered_appsBrowse all registered app command sheets
search_commandsSearch for commands by keyword
run_app_commandExecute a pre-built command by ID
preview_app_commandDry-run: show the exact script a command would execute
get_app_commandsGet detailed command info for a specific app

† Hidden and disabled when the server runs in safe mode (see below).

Server Configuration
Environment variableEffect
JCAS_SAFE_MODE=1Disables the arbitrary-code tools (execute_applescript, execute_jxa, tell_application) and registry commands flagged dangerous (e.g. terminal.run_command, safari.run_javascript). Only pre-built, sanitized registry commands remain available.
JCAS_APP_MANIFESTS=a.json:b.jsonColon-separated JSON manifest files with additional community app definitions to load at startup.

CLI flags: jcas-mcp --manifest prints the full registry as JSON, --version prints the server version, --help shows usage.

Example AI Interaction
User: "Send a message to John saying I'll be late"AI uses tool: run_app_command  command_id: "messages.send_message"  arguments: { "recipient": "John", "message": "I'll be late" }

Supported Applications

JCAppleScript ships with command sheets for 12 built-in macOS apps:

AppCategoryCommandsExamples
MessagesCommunication6Send message, list chats, get participants
MailCommunication7Compose email, search, check mail, list accounts
RemindersProductivity7Create/complete/delete reminders, search, list
CalendarProductivity6Create events, list today's events, upcoming
NotesProductivity8Create/search/append notes, manage folders
FinderSystem12File operations, folder contents, labels, trash
SafariInternet10Open URLs, manage tabs, run JavaScript, get page content
MusicMedia13Playback control, playlists, library search, ratings
TerminalDevelopment8Run commands, manage windows/tabs, profiles
System SettingsSystem13Dark mode, volume, notifications, dialogs, system info
XcodeDevelopment20+Open/build/run/test projects, schemes, build logs, debugging
Speech RecognitionSystem3Listen for spoken phrases via the system speech engine

Adding Custom App Support

Implement the ScriptableApp protocol to add support for any scriptable macOS app:

swift
import AppShortcuts
struct MyApp: ScriptableApp {    static let bundleIdentifier = "com.example.myapp"    static let appName = "MyApp"    static let description = "My custom application"    static let category = AppCategory.productivity
    static let commands: [AppCommand] = [        AppCommand(            id: "myapp.do_thing",            name: "Do Thing",            description: "Performs the thing",            parameters: [                CommandParameter(name: "input", description: "The input value"),            ]        ) { args in            let input = args["input", default: ""]            return """            tell application "MyApp"                do thing with "\(input)"            end tell            """        },    ]}
// Register at runtimeAppRegistry.shared.register(MyApp.self)

Community App Registry

JCAppleScript is designed to grow through community contributions. The app shortcut system uses a standard protocol (ScriptableApp) that makes it easy to:

  • Add new applications - Implement ScriptableApp for any scriptable macOS app
  • Extend existing apps - Submit new commands for already-registered apps
  • Share command sheets - Export/import app definitions via JSON manifests

We're building a browsable registry (similar to npmjs.org) where you can:

  • Browse applications and their supported AppleScript commands
  • Submit new commands for existing apps
  • Add entirely new applications to the registry
  • Generate JSON manifests for integration with other tools

Exporting and Importing the Registry

swift
// Export all registered apps as manifest JSONlet json = try AppRegistry.shared.exportManifestJSON()
// Import community app definitions from a JSON manifest.// Manifest commands are declarative script templates with ${param}// placeholders; argument values are sanitized before substitution.try AppRegistry.shared.loadManifest(contentsOf: URL(fileURLWithPath: "community.json"))

Example manifest:

json
[  {    "name": "CoolApp",    "bundleIdentifier": "com.example.coolapp",    "description": "A community-contributed app",    "category": "Productivity",    "commands": [      {        "id": "coolapp.greet",        "name": "Greet",        "description": "Show a greeting",        "script": "tell application \"CoolApp\"\n    greet \"${who}\"\nend tell",        "parameters": [          {"name": "who", "description": "Who to greet", "required": true, "type": "string"}        ]      }    ]  }]

The MCP server loads extra manifests from the JCAS_APP_MANIFESTS environment variable at startup.

Security Model

Registry command arguments are sanitized before script generation:

  • String, file-path, and date arguments are escaped (\, ", and control characters) so they cannot break out of AppleScript string literals.
  • Integer and boolean arguments are strictly validated/normalized — malformed values are rejected at validation and fall back to declared defaults during generation.
  • Values outside a parameter's allowedValues list are dropped.
  • Arguments that don't correspond to a declared parameter are discarded.

Commands that execute caller-supplied code (Terminal shell commands, Safari JavaScript) are flagged dangerous and can be disabled wholesale with JCAS_SAFE_MODE=1. Use the preview_app_command tool to inspect the exact script a command will run before executing it.

Note that execute_applescript, execute_jxa, and tell_application execute arbitrary code by design — only expose them to clients you trust, or run the server in safe mode.

Architecture

JCAppleScript/├── Sources/│   ├── JCAppleScript/           # Core engine│   │   ├── AppleScriptEngine.swift│   │   ├── AppleScriptSanitizer.swift│   │   ├── ScriptResult.swift│   │   └── ScriptError.swift│   ├── AppShortcuts/            # App command registry│   │   ├── AppProtocol.swift    # ScriptableApp protocol│   │   ├── AppCommand.swift     # Command & parameter types + sanitization│   │   ├── AppDefinition.swift  # Instance-based app description│   │   ├── AppManifest.swift    # JSON import/export│   │   ├── AppRegistry.swift    # Central registry│   │   └── Apps/                # Built-in app sheets│   │       ├── MessagesApp.swift│   │       ├── RemindersApp.swift│   │       ├── FinderApp.swift│   │       ├── SafariApp.swift│   │       ├── MailApp.swift│   │       ├── CalendarApp.swift│   │       ├── NotesApp.swift│   │       ├── MusicApp.swift│   │       ├── TerminalApp.swift│   │       └── SystemSettingsApp.swift│   └── JCAppleScriptMCP/       # MCP server│       ├── main.swift│       ├── MCPServer.swift│       ├── MCPTransport.swift│       └── MCPTypes.swift├── Tests/├── Legacy/                      # Original Obj-C implementation├── Package.swift└── LICENSE

Requirements

  • macOS 13.0+
  • Swift 5.9+

Legacy

The original Objective-C implementation (2013) is preserved in the Legacy/ directory for reference. It provided basic NSAppleScript wrapping with variable substitution. The new Swift implementation builds on those concepts while adding the MCP server, app registry, and modern Swift patterns.

License

MIT License - Copyright (c) 2013 John Clem. See LICENSE for details.

Source: README.md at commit 57e718e

Tools

0
SourceWeft has not started this package in its sandbox yet, so its tools are not known.

Version history

1
  1. v2.0.0LatestSep 16, 2026

Score

50% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts

    Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.

  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listed15 pts

    Answer tools/list without a credential, or ship a package that starts in a sandbox without one.

  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts