---
title: "sdef2md: Turn any macOS app's scripting API into documentation and MCP tools"
description: "A Go CLI that converts macOS .sdef scripting definitions into clean Markdown, paired with a skill that generates complete Go MCP servers from the generated reference — bridging any scriptable app into LLM agents."
pubDatetime: 2026-04-24T12:00:00Z
author: hrbrmstr
tags: ["go", "macos", "mcp", "applescript", "jxa", "automation", "llm", "agents"]
---
> Original: [sdef2md: Turn any macOS app's scripting API into documentation and MCP tools](https://ai.rud.is/posts/2026-04-24-sdef-to-md-and-mcp-skill)

Every scriptable macOS application ships with a hidden API surface, locked inside an `.sdef` (scripting definition) – which is Apple's way of saying "a cryptic XML file you'll definitely hate reading." Want to automate Notes, Finder, Mail, or Safari? You start by parsing nested `<class>`, `<property>`, and `<command>` tags that are genuinely hostile to humans. I got tired of that particular tax, so I built `sdef2md` to fix it.

`sdef2md` is a single-file Go CLI with zero external dependencies that converts `.sdef` XML into clean, structured Markdown: tables of classes, properties, commands, enumerations, and value types, plus ready-to-use JXA, AppleScript, Go, and Swift invocation patterns.

```bash
sdef /System/Applications/Notes.app > notes.sdef
go run sdef2cmd.go < notes.sdef > notes-api.md
```

The output is readable by humans, but that's not really the point. It's designed for LLM agent workflows where an agent needs a structured, traversable API reference to act on rather than raw XML it has to interpret.

The new `skills/sdef-to-mcp/` directory takes that one step further: it's an agent skill that turns any `sdef2md`-generated Markdown into a complete, compilable Go MCP server. Generate the Markdown reference for any app, feed it to the skill, and it auto-detects the app name, generates tool registrations and handler stubs for every command and class, emits a ready-to-compile Go project with JXA script templates, and wires in error handling for TCC permissions, timeouts, and missing objects. The resulting server speaks stdio JSON-RPC, plugs into Claude Desktop or any other MCP client, and bridges to the target app via `osascript` — no direct Apple Events API access required.

Before this, building an MCP server for a macOS app meant manually reverse-engineering Apple Events, writing brittle AppleScript from memory, and guessing at object containment hierarchies until something stopped crashing. Now it's two commands and a scaffold you adapt rather than a blank page you fill.

Every generated project includes `main.go` (MCP server setup via `mark3labs/mcp-go`), `jxa/runner.go` (`osascript` exec wrapper with timeout and error parsing), `tools/*.go` (handlers for each detected command and class), and a `README.md` with build instructions and an adaptation checklist. The JXA scripts are starters, not production code – every one is tagged `// REVIEW: adapt this for <AppName>` — so you'll still need to verify property names, containment hierarchies, and command parameters for your specific target. But you're starting from something that compiles and has the right shape, which is most of the work.

```bash
git clone https://git.sr.ht/~hrbrmstr/sdef2md
cd sdef2md
go run sdef2cmd.go < any-app.sdef > any-app-api.md
```

If you've been wanting to script a macOS app from an LLM agent workflow, this removes most of the boilerplate. What's left is just adapting the generated JXA to the quirks of your specific target – and at least you know exactly what those quirks are, because the Markdown told you.

---

MIT license. Repo at [`https://git.sr.ht/~hrbrmstr/sdef2md`](https://git.sr.ht/~hrbrmstr/sdef2md).

