Skip to main content

Building a Shortcuts MCP Server

This approach integrates Claude's chat interface with macOS's automation capabilities, opening up entirely new workflows.

MCP
TypeScript
macOS
Automation
AI Tools
Open Source
Law Horne
August 7, 2025
7 min read

I recently released something that I'm genuinely excited about: a Shortcuts MCP server. I'm not only excited about the functionality it provides and how well it works, but also the workflow and documentation I put in place for it.

A TypeScript MCP server that connects Claude to your macOS Shortcuts library. Interactive workflows with file pickers, dialogs, and prompts work through AppleScript integration, while CLI handles discovery and management.

From the GitHub README

This summary captures what I wanted to achieve, but if you know shortcuts, you know this opens a whole world of automation. You get system integration, various Apple app integration, and third-party app support as well.

Real-World Integration Examples

For example, I use BetterTouchTool for window snapping and controlling my Stream Deck. BTT comes with quite a few shortcuts of its own: "Custom Move Resize," window management actions, and more. You can build Shortcuts with these actions, and now Claude has access to these features. I might use this to set up a particular window layout - perhaps Claude next to iA Writer, my markdown editor of choice.

Speaking of iA Writer, it also comes with a host of Shortcuts actions. A use case I started implementing a few months ago was loading prompts and context documents into the clipboard, then pasting them into Claude. Now I simply say "Run my 'Get Writing Guidance' shortcut" and all the information Claude needs to effectively edit my communications is available.

These actions also give me the ability to have Claude create markdown documents and add them directly to my iA Writer library.

Technical Implementation

The framework I used is called FastMCP. This made it extremely easy to get up and running, and by all accounts has been rock solid for me. I use Pino for logging and debugging. FastMCP provides logging, but it's available in tool context and not easily used in business logic files. The logs naturally end up where you'd expect to find them (~/Library/Logs/Claude/).

The codebase is relatively small, focusing on a few core tools and resources:

Tools:

  • run_shortcut - AppleScript execution with comprehensive logging
  • user_context - Read and update local preferences and usage tracking
  • view_shortcut - CLI editor opening with fallback guidance

Resources (automatically embedded):

  • shortcuts://available - Current shortcuts list
  • execution://runs/recent - Recent execution history (local only)
  • context://system/current - System state for time-based suggestions
  • context://user/profile - Local user preferences and patterns

These resources are automatically embedded because when each tool is called (excluding view_shortcut), these resources are returned. This allows Claude to know what shortcuts you have, your execution history (including successes and failures), date and time information, and your favorite shortcuts and workflows.

MCP Schema

The MCP standard includes descriptions and schema with each tool to help AI assistants understand how to use them, what parameters they need, what to expect back, and what effect the tool might have. Here's how the run_shortcut tool and user profile resource are defined:

server.addTool({
  annotations: {
    openWorldHint: true,     // Indicates tool can handle varied inputs
    readOnlyHint: false,     // Tool can modify system state
    title: "Run Shortcut",
  },
  description:
    "Execute a macOS Shortcut by name with optional input. Use when users want to run any shortcut including interactive workflows with file pickers, dialogs, location services, and system permissions. All shortcut types are supported through AppleScript integration.",
  async execute(args, { log }) {
    // AppleScript execution logic
    // Error handling and logging
    // Return shortcut output + embedded resources
  },
  name: "run_shortcut",
  parameters: z.object({
    input: z
      .string()
      .optional()
      .describe("Optional input to pass to the shortcut"),
    name: z.string().describe("The name of the Shortcut to run"),
  }),
});

server.addResource({
  description:
    "User preferences including favorite shortcuts, workflow patterns, current projects, and focus areas. Contains stored user preferences and contextual information for personalized recommendations.",
  async load() {
    // Load user preference file
    // Parse and format for Claude context
    // Return structured preference data
  },
  mimeType: "text/plain",        // Content type for the resource
  name: "User preferences & usage patterns",
  uri: "context://user/profile", // Unique identifier for the resource
});

The description and name properties are crucial - they provide valuable information for assistants to understand what's available and how to use it effectively. The parameters schema uses Zod validation to ensure type safety and provide clear parameter descriptions.

User Experience

Worth noting: these resources, though primarily accessed by Claude via tool calls, are also available in the Claude Desktop UI. Users can click the plus button in the lower left corner of the chat interface and see an entry for resources provided by installed MCP servers.

Claude Desktop UI showing MCP resources

Also available in Claude's interface are prompts that MCP servers might provide. The Shortcuts server includes one prompt that analyzes available shortcuts and recommends the best option for specific tasks:

Analyze the available shortcuts and user context from the embedded resources to recommend the best shortcut for this task.

Then analyze which shortcut(s) would best accomplish this task:
1. Look for exact matches first
2. Consider shortcuts that could be adapted  
3. If no perfect match exists, suggest the closest alternatives
4. Explain why you're recommending specific shortcuts
5. Provide usage guidance for the recommended shortcut(s)

IMPORTANT: When recommending shortcuts:
- Use the EXACT name from the shortcuts list (case-sensitive)
- AppleScript execution (run_shortcut) is more forgiving than CLI commands (view_shortcut)

Be specific about which shortcut to use and how to use it effectively.

Also, I should mention .dxt support! This is not only a more dependable way to install MCP servers, but I was able to provide this through as automated releases using Github workflows. Give it try if you're into Claude and Shortcuts.

More to Come

This approach integrates Claude's chat interface with macOS's automation capabilities, opening up entirely new workflows.

This has sparked new ideas for me regarding my Shortcuts - how best to build them and what I can achieve with them, especially when I'm in a development workflow. I'm particularly excited about the implications with the next version of macOS. The "Use Model" action allows you to query the on-device model, private cloud compute model, and ChatGPT, which opens even more workflow possibilities.

AI Collaboration

This has been an enjoyable process for me - from first planning around prototypes mostly generated by Claude Code to getting my own hands in the code, so to speak. And as impressive as Claude Code is, I definitely enjoyed writing this myself.

Why? I love to code. I love to learn, and I wanted to understand more about the MCP protocol and how to get the most out of it. Even though I believe I've established a way of collaborating with AI systems, there's still a difference between getting into the technology you're working with and producing something yourself.

This isn't to say it was all or nothing. Claude Code wrote my tests and helped with documentation - ironically, testing and documentation are chores many developers cite as things they don't like (I actually do enjoy them). But using Claude for these tasks was far more efficient than doing them myself.

The same goes for writing PR summaries, choosing keywords for the package.json and repository, and a chore I truly do not enjoy: naming functions. When it came to research and planning, collaborating with Claude made deciding on frameworks far faster and easier.

For building something for myself, for learning and understanding how to best use AI, this was the right mix for me. If I was building a product, maybe the balance would be different. Maybe more, maybe less, depending on the feature. I've thought about this quite a bit. As the quality of these tools evolves, I'm sure my approach will too.

Enjoyed this article? I share thoughts on component architecture, and AI-enhanced workflows, regularly.