PluginBench
MCP Server
Maintained
MIT

JCAppleScript MCP Server

io.github.johnnyclem/jcas-mcp

Control macOS apps via AppleScript/JXA with pre-built sanitized commands for Messages, Mail, Finder, and more.

What is the JCAppleScript MCP server?

JCAppleScript is an MCP server that lets AI assistants control macOS applications through AppleScript and JavaScript for Automation (JXA). It provides a registry of pre-built, sanitized commands for 12 built-in macOS apps including Messages, Mail, Reminders, Calendar, Notes, Finder, Safari, Music, Terminal, System Settings, Xcode, and Speech Recognition.

JCAppleScript enables AI agents to automate macOS applications safely through a curated command registry. Instead of executing arbitrary code, the server exposes pre-built shortcuts for common tasks like sending messages, composing emails, managing reminders, controlling music playback, and manipulating files. All arguments are sanitized before script generation, and dangerous commands can be disabled via safe mode.

How to install JCAppleScript

Copy-paste configuration for popular MCP clients.

transport: stdio
Config generated by PluginBench — verify against the source before use.
Environment / auth
  • JCAS_SAFE_MODE

    Set to 1 to disable tools that execute arbitrary code (execute_applescript, execute_jxa, tell_application) and registry commands flagged dangerous.

  • JCAS_APP_MANIFESTS

    Colon-separated list of JSON manifest files with additional community app definitions to load at startup.

~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "jcas-mcp": {
      "command": "https://github.com/johnnyclem/JCAppleScript/releases/download/v2.0.0/jcas-mcp.mcpb",
      "args": [],
      "env": {
        "JCAS_SAFE_MODE": "<YOUR_JCAS_SAFE_MODE>",
        "JCAS_APP_MANIFESTS": "<YOUR_JCAS_APP_MANIFESTS>"
      }
    }
  }
}

Tools & capabilities

Tools this server exposes to the agent.

  • execute_applescript — Execute arbitrary AppleScript code (disabled in safe mode)
  • execute_jxa — Execute JavaScript for Automation (JXA) code (disabled in safe mode)
  • tell_application — Send a command to a specific app via tell block (disabled in safe mode)
  • check_script_syntax — Compile a script without executing it to validate syntax
  • list_running_applications — Get currently running applications
  • list_registered_apps — Browse all registered app command sheets
  • search_commands — Search for commands by keyword
  • run_app_command — Execute a pre-built command by ID with sanitized arguments
  • preview_app_command — Dry-run to show the exact script a command would execute
  • get_app_commands — Get detailed command info for a specific app

Use cases

  • Send messages or emails through Messages and Mail apps with recipient and content specified by the AI
  • Create, complete, and search reminders and calendar events for task management
  • Control music playback, manage playlists, and search the music library
  • Perform file operations in Finder like moving, copying, and organizing files
  • Execute terminal commands and manage Xcode projects for development workflows

JCAppleScript MCP server FAQ

What is JCAppleScript?

JCAppleScript is an MCP server that gives AI assistants safe, controlled access to macOS applications through pre-built AppleScript and JXA commands. It sanitizes all arguments before execution and supports 12 built-in macOS apps.

Is JCAppleScript free?

Yes, JCAppleScript is open-source under the MIT License.

How do I install it in Claude Desktop?

Download the prebuilt jcas-mcp.mcpb bundle from the GitHub releases, then add it to your Claude Desktop config at ~/Library/Application Support/Claude/claude_desktop_config.json with the command path.

What authentication is required?

No authentication is required. The server runs locally on your macOS machine and uses native AppleScript/JXA APIs. You may need to grant macOS accessibility permissions for the server to control applications.

Can I use arbitrary AppleScript code?

Yes, the execute_applescript, execute_jxa, and tell_application tools allow arbitrary code execution. However, these are disabled by default in safe mode (JCAS_SAFE_MODE=1), which restricts the server to only pre-built, sanitized registry commands.

Can I add support for custom applications?

Yes, you can implement the ScriptableApp protocol to add commands for any scriptable macOS app, or load community app definitions via JSON manifests using the JCAS_APP_MANIFESTS environment variable.

README (reference)

Source of truth, from the repository.

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:

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

Then add the targets you need:

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

Quick Start

Using the Core Engine

import JCAppleScript

let engine = AppleScriptEngine.shared

// Execute raw AppleScript
let result = try engine.execute("""
    tell application "Finder"
        display dialog "Hello from Swift!"
    end tell
""")

// Send a command to an application
let output = try engine.tell(application: "Music", command: "play")

// Execute a script file with variable substitution
let 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 executing
try engine.checkSyntax("tell application \"Finder\" to activate")

// All execution APIs also have async variants
let asyncResult = try await engine.execute("return 40 + 2")

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

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

Using App Shortcuts

import AppShortcuts

let registry = AppRegistry.shared

// Execute a pre-built command
let result = try registry.executeCommand("messages.send_message", arguments: [
    "recipient": "+15551234567",
    "message": "Hello from JCAppleScript!"
])

// Discover available commands
let commands = registry.commands(forApp: "Reminders")
for cmd in commands {
    print("\(cmd.id): \(cmd.name) - \(cmd.description)")
}

// Search across all apps
let 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):

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

Build the server:

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:

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 runtime
AppRegistry.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

// Export all registered apps as manifest JSON
let 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:

[
  {
    "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.

Related MCP servers

TOTokenKnows logo

Distill AI coding sessions into weekly reports, ADRs and a knowledge graph - self-hosted

4
Python
MIT
View repository →

Backlink & domain authority MCP for AI agents: referring domains, link gap, toxic review queue

View repository →

Domain search MCP: .com names verified available live via Verisign RDAP - not AI guess lists

0
JavaScript
MIT
View repository →

Token-efficient Ghidra reverse engineering for AI agents—decompile, xrefs, and annotate ELF/Mach-O/PE binaries with Swift/ObjC support.

35
Python
MIT
View repository →
KAKalshi MCP Server logo

Self-hosted MCP server for Kalshi prediction market trading via DFlow on Solana

1
TypeScript
View repository →

MCP server for Limitless Exchange prediction markets on Base

0
TypeScript
View repository →