macOS 15 SequoiaSystem SettingsAXCheckBoxNo new app

Control The Screen Time App Already On Your Mac. Without Installing Another One.

Every top result for this keyword sells you a different phone blocker. Skip that. macOS ships Screen Time as a pane inside System Settings made entirely of standard accessibility controls, which means an AI agent with an MCP bridge can flip Downtime, add an App Limit, or enter the passcode sheet with zero new software. The uncopyable detail is one line: AXCheckBox sits inside interactiveRolePrefixes at Sources/MCPServer/main.swift:917, which is why the Downtime "Scheduled" toggle surfaces inline on every traversal with its bounding box.

M
Matthew Diakonov
10 min read
5.0from open source
Screen Time already ships on every Mac as a System Settings pane
AXCheckBox is registered at Sources/MCPServer/main.swift:917
The passcode modal is caught as AXSheet by findSheetBounds at main.swift:241-278
One click_and_traverse flips the Downtime toggle; one tool call, one round trip

The SERP Tells You To Install An App. You Already Have One.

Google "control screen time app" and you get the same five listicles: ScreenZen, Freedom, FamilyTime, Qustodio, Jomo, Canopy. All of them are third-party subscriptions built to do what macOS Screen Time already does: block apps at a schedule, enforce downtime windows, filter website categories, report weekly usage. The SERP treats this keyword as transactional. Install another blocker on your phone.

Nothing on the SERP tells you that macOS already has Screen Time under System Settings. Nothing on the SERP tells you that every control in that pane is a standard AX element with a public role, a label, and a bounding box. And nothing on the SERP tells you that a local MCP server can drive that pane from a sentence without a single extra install.

That is this page.

Apps the SERP says you need to control screen time. None of them are installed for this page to work.

ScreenZenFreedomFamilyTimeQustodioJomoCanopyOffScreenStayFreeOpalScreen Time Labsone.secAppBlock

Sentence In, Toggle Out

Any MCP client that speaks stdio can call the six macos-use tools. The server funnels every request through the same accessibility traversal, and the destination is the real Screen Time pane inside System Settings, not a shadow copy.

The round trip

Claude Desktop
Cursor
Zed
macos-use
Downtime toggle
App Limits
Passcode sheet

The One Line Of Swift That Makes Every Screen Time Toggle An Agent Target

Open Sources/MCPServer/main.swift and jump to line 917. Not a comment, not a procedure, an array literal. AXCheckBox shares its row with AXButton, AXLink, AXTextField, and AXTextArea. That membership is what turns every Downtime toggle, every App Limits per-category switch, and every "Share Across Devices" row into a visible, targetable element in the compact summary the MCP returns on every tool call.

Sources/MCPServer/main.swift

Delete the "AXCheckBox" string from that array and the Scheduled toggle is still in the accessibility tree, but it drops out of the inline summary. The agent then has to grep the raw AX dump for the role and reconstruct the bounding box by hand. With the registration in place, one grep AXCheckBox against the traversal text file is enough to find Scheduled plus every other on/off switch in the pane.

The Screen Time Passcode Sheet, And Why It Does Not Break Automation

The first time you turn Screen Time on, System Settings raises a modal with four digit buttons and a Cancel/Continue pair. That modal is an AXSheet. If the server used the outer window bounds for its viewport check, half the sheet would fall outside in_viewport=true and the agent could not address the digit buttons. macos-use catches the sheet explicitly and scopes the viewport to its frame. The stderr line to look for is:

log: findSheetBounds: found AXSheet at (600, 260, 400, 360)
Sources/MCPServer/main.swift

Once the sheet is scoped, every digit button inside it comes out of the traversal as [AXButton (button)] "1" with a bounding box inside (600, 260, 400, 360). The agent taps the four digits with four click_and_traverse calls. The response pipeline at main.swift:746 annotates the summary with dialog: AXSheet detected (viewport scoped to sheet bounds), which is your signal the passcode modal is up.

What The Agent Does Between "Turn On Downtime" And The Toggle Flipping

Four MCP round trips. The agent never types a pixel coordinate; every click copies x, y, w, h straight from the traversal text file at /tmp/macos-use/.

1

open_application_and_traverse on com.apple.systempreferences

System Settings launches (or activates). The traversal is written to /tmp/macos-use/<ts>_open.txt with a PNG screenshot alongside. The response carries the PID of System Settings and the file path. The agent now knows the sidebar layout.

2

click_and_traverse with element='Screen Time'

The server runs findElementByText (main.swift:1126) against the AX tree, finds the Screen Time sidebar row, and clicks at its center. The post-action traversal returns a diff showing the detail view's new elements: Downtime, App Limits, Communication Limits, Always Allowed.

3

click_and_traverse with element='Downtime'

Enter the Downtime section. If this is the first Screen Time interaction on this Mac, the passcode AXSheet appears. findSheetBounds (main.swift:241-278) scopes the viewport; the agent tap-types four digits into the AXButton row, then Continue, then Continue again to confirm.

4

click_and_traverse with element='Scheduled' role='AXCheckBox'

One call flips the Downtime toggle. The diff block prints AXCheckBox AXValue "0" -> "1" with the bounding box. Follow-up calls pick 'Custom' in the days AXPopUpButton and type the start/end times into the two AXTextFields. Every step verifies with the returned diff.

The Stderr Log Of One Real "Turn On Downtime" Run

Pipe the MCP server into python3 scripts/test_mcp.py with the four-call sequence and this is what prints. The AXSheet detection line is the one that tells you the passcode modal was handled.

macos-use MCP server — stderr

The Tool Call That Flips The Scheduled Toggle

Either form works. The text-match form uses findElementByText at main.swift:1126 plus the role filter at main.swift:1315. The coordinate form copies x, y, w, h from the traversal text file. Both hit the same code path and both flip the AXCheckBox in one round trip.

mcp-call.json
1 line

AXCheckBox inside interactiveRolePrefixes is the whole argument. Remove that one string and Downtime's Scheduled toggle stops appearing in the visible-elements summary on every traversal.

Sources/MCPServer/main.swift:917

Screen Time Control, Five Ways

The SERP recommends rows 1-4. Row 5 is what this page is about.

FeatureThird-party blockersmacos-use MCP + built-in Screen Time
Needs a new app installedYes. ScreenZen, Freedom, Jomo, Opal, AppBlock all require itNo. macOS already ships Screen Time in System Settings.
Monthly subscriptionFreedom, Jomo, Qustodio: yes. Most range $2-10/mo.Zero. Screen Time is free; macos-use is MIT.
Driven by a sentence to an LLMNo. GUI toggles only; no MCP, no CLI, no API.Yes. 'Turn on Downtime 10pm-7am weekdays.' routes through four MCP calls.
Enforcement depthMost run in user space and can be bypassed by quitting the appScreen Time itself enforces (FamilyControls, nesessionmanager). macos-use only flips the toggle.
Cross-device syncVaries per vendor; usually proprietary cloudApple's existing iCloud sync via the built-in Share Across Devices toggle.
Handles the first-run passcode modalNot applicable (their own UI)findSheetBounds at main.swift:241-278 scopes viewport to the AXSheet.
Line count of the 'why this works' argumentNot applicableOne line. main.swift:917 inside interactiveRolePrefixes.

Sentences That Turn Into Screen Time Actions

Each card below is one prompt into an MCP client. Each becomes a few grep calls against the traversal text file plus a short chain of click_and_traverse calls. Nothing here talks to a third-party server.

Turn on Downtime every weeknight at 10pm

The agent walks to System Settings > Screen Time > Downtime, flips the AXCheckBox labeled 'Scheduled', picks 'Custom' in the AXPopUpButton day selector, and types the start/end times into the two AXTextFields. The diff block confirms each toggle flipped before continuing.

Set a 30-minute daily limit on Instagram

Navigate to App Limits, click Add Limit, tick the AXCheckBox next to Social, type '30' into the minute AXTextField. All three actions ride the same interactiveRolePrefixes registration at main.swift:917.

Block a website without installing a blocker

Content & Privacy > Web Content > Limit Adult Websites, then add the URL to the Restricted AXTextArea. The agent round-trips through AXButton rows inside the Add Website AXSheet.

Flip 'Share Across Devices' off for this Mac

One click_and_traverse with element='Share Across Devices' and role='AXCheckBox'. The toggle's AXValue flips from 1 to 0 and the diff block prints the change. Your iPhone stops seeing this Mac's Screen Time data.

Set a Screen Time passcode (first-run)

The moment you turn anything on, System Settings raises an AXSheet. findSheetBounds at main.swift:241-278 scopes the viewport to the sheet, and the agent tap-types the four digits into the AXButton row. No guessing where the buttons moved.

Clear usage data on Fridays

A simple launchd schedule triggers the agent to open Screen Time > Usage and click 'Reset Statistics'. The click becomes a CGEvent posted at the AXButton's center. No app to install, no cron hack, just one sentence at 9am Friday.

The Page In Numbers

Pulled from the current head of main. If the source moves, these line numbers are the check against what shipped.

0line where AXCheckBox sits in interactiveRolePrefixes
0closing line of findSheetBounds (passcode sheet)
0MCP tools the agent uses, total
0third-party Screen Time apps required

0 is the line. The rest of this page traces back to it, plus lines 0-0 for the passcode sheet.

Drive Screen Time From A Sentence Tonight

Clone mediar-ai/mcp-server-macos-use, build with xcrun swift build, grant Accessibility permission once, add the binary to Claude Desktop's MCP config, and tell the model to turn Downtime on at 10pm. First call opens System Settings, second walks to Screen Time, third opens Downtime (handles the passcode sheet if needed), fourth flips the AXCheckBox. No new app installed.

Get macos-use on GitHub

Frequently asked questions

Why use the built-in macOS Screen Time pane instead of ScreenZen, Freedom, or Jomo?

Because Screen Time is already installed, already has a kernel-level reach (it enforces through FamilyControls and nesessionmanager under the hood, same as MDM restrictions), and already syncs across your Apple ID if you want it to. The thing missing from it is a programmable interface. Third-party apps like ScreenZen, Freedom, and Jomo exist because Screen Time ships no CLI and no public API. macos-use gives you the programmable surface by driving the Screen Time pane's existing AX tree. You keep Apple's enforcement path; you just stop needing a human finger to flip the toggles. No subscription, no new app, no syncing a second policy layer on top of the one macOS already enforces.

What exactly is the 'one line in main.swift' that makes this work?

Sources/MCPServer/main.swift:917 reads: '"AXButton", "AXLink", "AXTextField", "AXTextArea", "AXCheckBox",' as the first line of the interactiveRolePrefixes array. AXCheckBox is the role macOS assigns to every on/off switch in the System Settings > Screen Time pane: the Downtime toggle, the Share Across Devices toggle, the Include Website Data toggle, the per-category App Limits toggles. Because AXCheckBox sits inside that array, isInteractiveRole at main.swift:923-925 returns true for those toggles, and buildVisibleElementsSection at main.swift:933 onward emits them inline in the compact summary with their exact x, y, w, h. Without that one string in that one array, the Downtime toggle would be buried in the raw AX dump and the agent would have to reconstruct its bounding box by hand.

Screen Time pops a passcode sheet the first time you turn it on. How does the MCP not lose its place?

Because findSheetBounds at Sources/MCPServer/main.swift:241-278 walks every window's children looking for an element whose role equals 'AXSheet'. When System Settings drops the 'Create a Screen Time Passcode' modal over the pane, that modal is an AXSheet. findSheetBounds returns its frame, and the response pipeline at main.swift:631-651 uses that frame as the viewport for the enrichment pass instead of the outer window bounds. That means the four digit buttons plus the Cancel and Continue buttons inside the sheet all come back marked in_viewport=true with coordinates scoped to the sheet. The stderr log prints 'log: findSheetBounds: found AXSheet at <frame>' so you can watch it happen. The response even appends 'dialog: AXSheet detected (viewport scoped to sheet bounds)' to the compact summary at main.swift:746.

What actually happens when Claude Desktop receives 'turn on Downtime from 10pm to 7am every weekday'?

Four MCP round trips, roughly. (1) macos-use_open_application_and_traverse with identifier=com.apple.systempreferences, which activates System Settings and writes /tmp/macos-use/<ts>_open.txt plus a screenshot. (2) macos-use_click_and_traverse with element='Screen Time' to open the Screen Time pane from the sidebar. (3) macos-use_click_and_traverse with element='Downtime' to navigate into the Downtime section. (4) One or more click_and_traverse calls to toggle the AXCheckBox for 'Scheduled', choose 'Custom' in the AXPopUpButton day picker, and type 10:00 PM / 7:00 AM into the AXTextField time boxes. Every call returns a diff block showing which elements changed, so the agent verifies the toggle flipped before moving on. If the passcode sheet appears, findSheetBounds catches it and the agent tap-types the four digits into the AXButton row inside the sheet.

Does the agent need Screen Recording permission, or just Accessibility?

Accessibility only for toggling controls. The MCP requests Screen Recording exclusively for the PNG screenshot that ships alongside every traversal (saved to /tmp/macos-use/<ts>_<tool>.png, one file per call). You can deny Screen Recording and the toggle path still works; you just lose the visual verification layer. Accessibility permission is what lets AXUIElementCopyAttributeValue and CGEventPost read the tree and send the click events at main.swift:1085-1089 and the SDK's InputController respectively. Grant it once under System Settings > Privacy and Security > Accessibility, pointing at the mcp-server-macos-use binary, and every Screen Time control becomes addressable.

What are the concrete Screen Time controls that show up as AXCheckBox in the traversal?

On macOS Sequoia 15: 'Scheduled' under Downtime, 'Block at Downtime' under Downtime, the 'Include Website Data' toggle under Usage, 'Share Across Devices' under the top of the pane, the 'Allow at Downtime' selector expansion, and every per-limit toggle under App Limits. Each of those surfaces as [AXCheckBox (checkBox)] "<label>" (x,y w×h) in the compact summary. The AXPopUpButtons (Every Day / Custom, day-of-week pickers) and AXTextFields (time entry) show up alongside them. AXButton rows inside the passcode AXSheet cover digits 0-9 and Cancel / Continue. You do not need to guess the roles; grep the traversal file for the label you see on screen and the role is printed in brackets at the start of the line.

Why does the SERP for 'control screen time app' never mention macOS or MCP?

Because the query has been treated as commercial-intent since 2017 for 'install an app to block apps on my phone'. Every top result is a listicle of third-party blockers (Freedom, ScreenZen, FamilyTime, Canopy, Jomo, OffScreen, Qustodio) or their vendor pages. The word 'control' in the query is read as 'restrict' rather than 'programmatically drive'. macOS Screen Time is an entire built-in pane that almost no SERP content references, and MCP as a protocol for agents to drive macOS was not even a concept at the time those listicles were indexed. This page targets the gap: a native macOS pane that you already have, with a public accessibility tree, and a local MCP server that can read and write it from a sentence.

How do I verify the Screen Time pane is actually AX-addressable on my machine?

One minute of terminal work. Build with xcrun --toolchain com.apple.dt.toolchain.XcodeDefault swift build. Run python3 scripts/test_mcp.py and have it call open_application_and_traverse on com.apple.systempreferences. Grep /tmp/macos-use/<latest>_open.txt for 'Screen Time' to find the AXStaticText in the sidebar. click_and_traverse with element='Screen Time'. In the next file, grep for 'AXCheckBox' and you will see lines like [AXCheckBox (checkBox)] "Scheduled" (x,y w×h) for Downtime's Scheduled toggle. No guessing; the role is printed in the line. Fire click_and_traverse against that x,y,w,h and it flips. The stderr log prints the exact click coordinate via ActionCoordinator so you can verify it landed at the toggle's center.

Is there a race condition between clicking Screen Time in the sidebar and the pane fully rendering?

In practice the response from click_and_traverse already re-traverses after the click and returns the new tree. If the pane is still animating in, the visible-elements section may contain the sidebar but not the detail view yet; in that case the agent calls refresh_traversal one more time, or issues the next click with element='Downtime' which will match once rendered. The tool is deliberately designed to retraverse post-action instead of returning mid-animation; you do not have to add sleep() between steps. If you hit a slow case (rare), the diff block at main.swift:610-711 returns empty added/removed lists and the agent knows to refresh.

Can I schedule this so my Mac locks itself at 10pm without me typing anything?

Yes, but the scheduling layer lives outside macos-use. Any scheduler that can call an MCP server over stdio at a cron time works: Raycast with a cron extension, a launchd plist calling a short Node script that speaks JSON-RPC, or Claude Code's own scheduled prompts. The payload is the same four-tool sequence above. Screen Time itself will still be what enforces the 10pm lock; macos-use is only the bridge that flipped the Scheduled toggle at 9:59. The result is: at 10pm Downtime engages system-wide (including on your linked iPhone if Share Across Devices is on), and at 7am macos-use runs the reverse sequence to disengage. Neither the Mac nor the agent needs a third-party Screen Time replacement.

macos-useMCP server for native macOS control
© 2026 macos-use. All rights reserved.