
macOS Automator
STDIOExecute AppleScript and JavaScript for Automation on macOS through MCP server.
Execute AppleScript and JavaScript for Automation on macOS through MCP server.
This project provides a Model Context Protocol (MCP) server, macos_automator
, that allows execution of AppleScript and JavaScript for Automation (JXA) scripts on macOS. It features a knowledge base of pre-defined scripts accessible by ID and supports inline scripts, script files, and argument passing.
The knowledge base is loaded lazily on first use for fast server startup.
package.json
engines).docs/automation-permissions-example.png
(placeholder image).The primary way to run this server is via npx
. This ensures you're using the latest version without needing a global install.
Add the following configuration to your MCP client's mcp.json
(or equivalent configuration):
{ "mcpServers": { "macos_automator": { "command": "npx", "args": [ "-y", "@steipete/macos-automator-mcp@latest" ] } } }
Alternatively, for development or if you prefer to run the server directly from a cloned repository, you can use the provided start.sh
script. This is useful if you want to make local modifications or run a specific version.
Clone the repository:
git clone https://github.com/steipete/macos-automator-mcp.git cd macos-automator-mcp npm install # Ensure dependencies are installed
Configure your MCP client:
Update your MCP client's configuration to point to the absolute path of the start.sh
script within your cloned repository.
Example mcp.json
configuration snippet:
{ "mcpServers": { "macos_automator_local": { "command": "/absolute/path/to/your/cloned/macos-automator-mcp/start.sh", "env": { "LOG_LEVEL": "DEBUG" } } } }
Important: Replace /absolute/path/to/your/cloned/macos-automator-mcp/start.sh
with the correct absolute path on your system.
The start.sh
script will automatically use tsx
to run the TypeScript source directly if a compiled version is not found, or run the compiled version from dist/
if available. It respects the LOG_LEVEL
environment variable.
Note for Developers: The start.sh
script, particularly if modified to remove any pre-existing compiled dist/server.js
before execution (e.g., by adding rm -f dist/server.js
), is designed to ensure you are always running the latest TypeScript code from the src/
directory via tsx
. This is ideal for development to prevent issues with stale builds. For production deployment (e.g., when published to npm), a build process would typically create a definitive dist/server.js
which would then be the entry point for the published package.
execute_script
Executes an AppleScript or JavaScript for Automation (JXA) script on macOS.
Scripts can be provided as inline content (script_content
), an absolute file path (script_path
), or by referencing a script from the built-in knowledge base using its unique kb_script_id
.
Script Sources (mutually exclusive):
script_content
(string): Raw script code.script_path
(string): Absolute POSIX path to a script file (e.g., .applescript
, .scpt
, .js
).kb_script_id
(string): The ID of a pre-defined script from the server's knowledge base. Use the get_scripting_tips
tool to discover available script IDs and their functionalities.Language Specification:
language
(enum: 'applescript' | 'javascript', optional): Specify the language.
kb_script_id
, the language is inferred from the knowledge base script.script_content
or script_path
and language
is omitted, it defaults to 'applescript'.Passing Inputs to Scripts:
arguments
(array of strings, optional):
script_path
: Passed as standard arguments to the script's on run argv
(AppleScript) or run(argv)
(JXA) handler.kb_script_id
: Used if the pre-defined script is designed to accept positional string arguments (e.g., replaces placeholders like --MCP_ARG_1
, --MCP_ARG_2
). Check the script's argumentsPrompt
from get_scripting_tips
.input_data
(JSON object, optional):
kb_script_id
scripts designed to accept named, structured inputs.--MCP_INPUT:yourKeyName
). See argumentsPrompt
from get_scripting_tips
.Other Options:
timeout_seconds
(integer, optional, default: 60): Maximum execution time.output_format_mode
(enum, optional, default: 'auto'): Controls osascript
output formatting flags.
'auto'
: (Default) Uses human-readable for AppleScript (-s h
), and direct output (no -s
flags) for JXA.'human_readable'
: Forces -s h
(human-readable output, mainly for AppleScript).'structured_error'
: Forces -s s
(structured error reporting, mainly for AppleScript).'structured_output_and_error'
: Forces -s ss
(structured output for main result and errors, mainly for AppleScript).'direct'
: No -s
flags are used (recommended for JXA, also the behavior for JXA in auto
mode).include_executed_script_in_output
(boolean, optional, default: false): If true, the output will include the full script content (after any placeholder substitutions for knowledge base scripts) or the script path that was executed. This is appended as an additional text part in the output content array.include_substitution_logs
(boolean, optional, default: false): If true, detailed logs of placeholder substitutions performed on knowledge base scripts are included in the output. This is useful for debugging how input_data
and arguments
are processed and inserted into the script. The logs are prepended to the script output on success or appended to the error message on failure.report_execution_time
(boolean, optional, default: false): If true
, an additional message with the formatted script execution time will be included in the response content array.SECURITY WARNING & MACOS PERMISSIONS: (Same critical warnings as before about arbitrary script execution and macOS Automation/Accessibility permissions).
Examples:
{ "toolName": "execute_script", "input": { "kb_script_id": "safari_get_active_tab_url", "timeout_seconds": 10 } }
input_data
:
{ "toolName": "execute_script", "input": { "kb_script_id": "finder_create_folder_at_path", "input_data": { "folder_name": "New MCP Folder", "parent_path": "~/Desktop" } } }
Response Format:
The execute_script
tool returns a response in the following format:
{ content: Array<{ type: 'text'; text: string; }>; isError?: boolean; }
content
: An array of text content items containing the script outputisError
: (boolean, optional) Set to true
when the script execution produced an error. This flag is set when:
Example Response (Success):
{ "content": [{ "type": "text", "text": "Script executed successfully" }] }
Example Response (Error):
{ "content": [{ "type": "text", "text": "Error: Cannot find application 'Safari'" }], "isError": true }
get_scripting_tips
Retrieves AppleScript/JXA tips, examples, and runnable script details from the server's knowledge base. Useful for discovering available scripts, their functionalities, and how to use them with execute_script
(especially kb_script_id
).
Arguments:
list_categories
(boolean, optional, default: false): If true, returns only the list of available knowledge base categories and their descriptions. Overrides other parameters.category
(string, optional): Filters tips by a specific category ID (e.g., "finder", "safari").search_term
(string, optional): Searches for a keyword within tip titles, descriptions, script content, keywords, or IDs.refresh_database
(boolean, optional, default: false): If true, forces a reload of the entire knowledge base from disk before processing the request. This is useful during development if you are actively modifying knowledge base files and want to ensure the latest versions are used without restarting the server.limit
(integer, optional, default: 10): Maximum number of results to return.Output:
Example Usage:
{ "toolName": "get_scripting_tips", "input": { "list_categories": true } }
{ "toolName": "get_scripting_tips", "input": { "category": "safari" } }
{ "toolName": "get_scripting_tips", "input": { "search_term": "clipboard" } }
{ "input": { "script_content": "tell application \"Safari\" to get URL of front document" } }
{ "input": { "script_content": "tell application \"Mail\" to get subject of messages of inbox whose read status is false" } }
{ "input": { "script_content": "tell application \"Finder\" to get name of every item of desktop" } }
{ "input": { "script_content": "tell application \"Finder\" to make new folder at desktop with properties {name:\"My New Folder\"}" } }
{ "input": { "script_content": "display notification \"Important Update!\" with title \"System Alert\"" } }
{ "input": { "script_content": "set volume output volume 50" } }
(0-100){ "input": { "script_content": "the clipboard" } }
osascript
errors will be returned in the stderr
or error message. Test complex scripts locally using Script Editor (for AppleScript) or a JXA runner first.timeout_seconds
(default 60s), it will be terminated. Increase the timeout for long-running scripts.script_path
is an absolute POSIX path accessible by the user running the MCP server.output_format_mode
is set to 'direct'
or 'auto'
(default). Using AppleScript-specific formatting flags like human_readable
with JXA can cause errors. If AppleScript output is not parsing correctly, try structured_output_and_error
or structured_error
.LOG_LEVEL
: Set the logging level for the server.
DEBUG
, INFO
, WARN
, ERROR
LOG_LEVEL=DEBUG npx @steipete/macos-automator-mcp@latest
KB_PARSING
: Controls when the knowledge base (script tips) is parsed.
lazy
(default): The knowledge base is parsed on the first request to get_scripting_tips
or when a kb_script_id
is used in execute_script
. This allows for faster server startup.eager
: The knowledge base is parsed when the server starts up. This may slightly increase startup time but ensures the KB is immediately available and any parsing errors are caught early.start.sh
or similar):
KB_PARSING=eager ./start.sh
env
, like mcp-agentify
):
{ "env": { "LOG_LEVEL": "INFO", "KB_PARSING": "eager" } }
For detailed instructions on local development, project structure (including the knowledge_base
), and contribution guidelines, please see DEVELOPMENT.md.
See DEVELOPMENT.md for details on the project structure, building, and testing.
You can supplement the built-in knowledge base with your own local tips and shared handlers. Create a directory structure identical to the knowledge_base
in this repository (or a subset of it).
By default, the application will look for this local knowledge base at ~/.macos-automator/knowledge_base
.
You can customize this path by setting the LOCAL_KB_PATH
environment variable.
Example:
Suppose you have a local knowledge base at /Users/yourname/my-custom-kb
.
Set the environment variable:
export LOCAL_KB_PATH=/Users/yourname/my-custom-kb
Or, if you are running the validator script, you can use the --local-kb-path
argument:
npm run validate:kb -- --local-kb-path /Users/yourname/my-custom-kb
Structure and Overrides:
knowledge_base
(e.g., 01_applescript_core
, 05_web_browsers/safari
, etc.)..md
tip files or _shared_handlers
(e.g., .applescript
or .js
files).id:
or generated from filename/path) in your local knowledge base matches an ID in the embedded knowledge base, your local version will override the embedded one.my_utility.applescript
) in your local _shared_handlers
directory will override any embedded ones with the same name and language within the same category (or globally if you place them at the root of your local KB's _shared_handlers
)._category_info.md
in your local KB can also override those from the embedded KB for the same category.This allows for personalization and extension of the available automation scripts and tips without modifying the core application files.
Contributions are welcome! Please submit issues and pull requests to the GitHub repository.
This server provides powerful macOS automation capabilities through AppleScript and JavaScript for Automation (JXA). Here are some of the most useful examples:
{ "input": { "kb_script_id": "terminal_app_run_command_new_tab", "input_data": { "command": "ls -la" } } }
{ "input": { "kb_script_id": "chrome_open_url_new_tab_profile", "input_data": { "url": "https://example.com", "profile_name": "Default" } } }
{ "input": { "kb_script_id": "safari_get_front_tab_url" } }
{ "input": { "kb_script_id": "chrome_execute_javascript", "input_data": { "javascript_code": "document.title" } } }
{ "input": { "kb_script_id": "systemsettings_toggle_dark_mode_ui" } }
{ "input": { "kb_script_id": "system_clipboard_get_file_paths" } }
{ "input": { "kb_script_id": "finder_create_new_folder_desktop", "input_data": { "folder_name": "My Project" } } }
{ "input": { "kb_script_id": "fileops_read_text_file", "input_data": { "file_path": "~/Documents/notes.txt" } } }
{ "input": { "kb_script_id": "calendar_create_event", "input_data": { "title": "Meeting", "start_date": "2023-06-01 10:00", "end_date": "2023-06-01 11:00" } } }
{ "input": { "kb_script_id": "mail_send_email_direct", "input_data": { "recipient": "[email protected]", "subject": "Hello", "body_content": "Message content" } } }
{ "input": { "kb_script_id": "music_playback_controls", "input_data": { "action": "play" } } }
Use the get_scripting_tips
tool to explore all available automation capabilities organized by category.
This project is licensed under the MIT License. See the LICENSE file for details.