Screen time parental control apps all report their own status. Read the accessibility tree instead.

Four enforcement models, one blind spot, and a separate accessibility-tree audit on top. Every app you can choose from on macOS, Apple Screen Time included, answers the question “is it still on?” with its own opinion. If a child disables the app, the status view goes with it. This guide names the four enforcement models underneath the category, admits what each one is good at, and documents a separate audit layer that reads the accessibility tree directly so tamper shows up as a plain text diff.

M
Matthew Diakonov
12 min read
4.8from Open source, 380+ GitHub stars
No kernel extension
No MDM enrollment
Six MCP tools
Works with any vendor

The blind spot every “best screen time apps” article misses

Pick up any ten roundups of screen time parental control apps and the top picks rotate through the same short list: Apple Screen Time, Qustodio, Bark, Norton Family, Mobicip, Circle. The comparisons are about features. Web filtering. App limits. Schedules. Location. Reports. The comparisons are honest, and if you are picking for features, pick whichever app fits.

What no roundup asks: what does the reporting path look like when a child turns the app off? The answer for every listed app is the same. Each one reports its own status, through its own channel. Apple Screen Time reports inside System Settings, which the child also controls. Qustodio, Bark, and Norton Family stream a heartbeat from an agent on the device, which the child can quit. A DNS filter is bypassed by switching Wi-Fi networks. An MDM profile is removable from the Profiles pane.

The blind spot is category-wide. It is not “pick a better app.” It is “add a verifier that is independent of whichever app you picked.”

Four enforcement models, and an audit layer that sits on top

Whichever enforcement model you pick, the accessibility tree is the signal.

Apple Screen Time
Qustodio agent
Bark Desktop
Router DNS filter
MDM profile
Accessibility tree
macos-use MCP
Agent / LLM
Parent alert

The four models, named honestly

Every parental control app you can run on macOS falls into one of these four. Mix them if you like; in practice most households end up with two.

Built-in: Apple Screen Time

Enforced by the OS through Family Controls. Strongest on iPhone, weakest on macOS where a child with admin rights can flip it off in Settings and keep the passcode screen from ever appearing.

Network: DNS + VPN filters

Block at the edge. Great for YouTube, Reddit, adult sites over HTTPS. Useless the moment the device leaves the network or uses DoH.

Agent: Qustodio, Bark, Norton Family, Mobicip

Third-party daemon enforces time and site rules locally and streams reports to a vendor cloud. Shrink-wrapped UX. Each vendor's dashboard reports its own liveness.

Managed: MDM profile

A configuration profile pushes restrictions through the OS. Usually via Apple School Manager, Jamf, Kandji, or a family-tier MDM. Enterprise-grade, but visible as a removable row in Settings.

On top of any of them: AX audit

Read the same accessibility tree the OS renders. No kernel extension. No vendor SDK. One timer loop, one diff per tick, and the signal is independent of whichever app you chose.

What the AX audit actually produces

The server exposes a tool called refresh_traversal. Given a process id, it re-reads that app’s entire accessibility tree, diffs it against the prior snapshot, and returns a compact summary plus a file path on disk. On a minute timer pointed at System Settings, it looks like this when a Screen Time toggle flips:

macos-use audit tick

The important line is ~ 'Screen Time' AXValue '1' -> '0'. Three things matter about it. One, it names the element by its visible title, so it is grep-able. Two, it records the before and after values, so the direction of the change is unambiguous. Three, it is a plain text line, so it ships into any alerting channel without a parser.

The anchor: one loop in Swift decides what a tamper looks like

The diff pipeline is a single for loop that walks the set of modified elements between two consecutive snapshots and emits one text line per AXValue transition. It lives in the main server binary, around line 843 of Sources/MCPServer/main.swift. It is short enough to read in one sitting.

Sources/MCPServer/main.swift

The loop does not know that the element is a Screen Time checkbox. It does not care which vendor rendered the UI. It treats every AXUIElement the same way. That is why the same code path works for the System Settings window and for a third-party parental control app’s main window, assuming the vendor exposes state to accessibility APIs.

The numbers, verifiable from the repo

0MCP tools (main.swift:1300-1408)
0Element cap per traversal
0Line where AXValue diff fires
0 kextKernel extensions required

Six tools defined between main.swift:1300 and main.swift:1408. Traversal truncates at 5000 elements per call (enforced inside the tree walker, tested by scripts/test_mcp.py). The AXValue diff emission sits at main.swift:843. No kernel extension participates in the audit path.

Model vs. model: what the AX audit catches that the vendor cannot

This is not a feature comparison of vendors. It is a side-by-side of what each enforcement model tells you versus what the AX tree tells you, so you can see why the two should run together.

FeatureVendor self-reportAX audit layer
Built-in (Apple Screen Time)Reports status inside Settings, which the child also controls.AX tree shows 'Screen Time' AXCheckBox value even if the child hides the Settings window.
Agent apps (Qustodio, Bark, Norton Family)Vendor dashboard shows online/offline, driven by the agent's own heartbeat.AX snapshot of the vendor's UI records whether its toggles match the vendor-reported state.
Network filters (DNS, VPN)Blocks at the network edge. If the device switches to a hotspot, filter is gone.AX snapshot of System Settings Wi-Fi pane reveals SSID changes and VPN connection state.
MDM profileProfile visible inside Settings > Privacy and Security > Profiles, can be removed.AX diff fires when the profile row disappears from the Profiles list in System Settings.

Setting this up alongside an existing app

The whole point of this layer is that it does not replace whatever parental control app you already use. You keep that app. You add an audit on top. The setup is five steps, and none of them touch your vendor.

1

Pick whichever parental control app you already trust

Apple Screen Time, Qustodio, Bark, Norton Family, Circle, a DNS filter, your MDM. This audit layer is vendor-neutral and the enforcement app keeps its own job.

2

Install and grant the MCP server Accessibility permission

System Settings, Privacy and Security, Accessibility, add the mcp-server-macos-use binary. No Full Disk Access. No Screen Recording unless you want PNG evidence.

3

Prime a snapshot of the panes you care about

Call macos-use_open_application_and_traverse with identifier com.apple.systempreferences to open System Settings, then click into the Screen Time pane. The first traversal sets the baseline.

4

Run refresh_traversal on a timer from your agent or cron

Once a minute is usually enough. The tool returns a compact diff with added, removed, and modified elements. Store the file path, not the full tree, to keep context small.

5

Alert on any AXValue transition on tracked toggles

A Screen Time flip emits `~ 'Screen Time' AXValue '1' -> '0'`. A Downtime flip emits `~ 'Scheduled' AXValue '1' -> '0'`. Pipe those lines to your alerter.

AXValue

One attribute transition emits one line. Everything else in the audit path is downstream of that.

Sources/MCPServer/main.swift:843

Surfaces the AX audit has been pointed at

com.apple.systempreferencesApple Screen TimeQustodioBark DesktopNorton FamilyMobicipCircleJamf MDMKandji MDMRouter DNSAXCheckBoxAXValuerefresh_traversal

The counted numbers

0

Enforcement models in the category

0

Audit layer that rides on top

0

Line of main.swift where the diff fires

0

Kernel extensions in the audit path

The honest trade

This audit layer does not replace enforcement. It is not a parental control app. It does not block YouTube, it does not meter Roblox, it does not ship a vendor dashboard for your phone. It reads the accessibility tree. A child who knows what they are doing can still kill its process, the same way they can kill Qustodio or Bark.

What it buys you is independence. The enforcement app and the audit layer die separately. If the app is killed, the audit is still reading the System Settings tree and sees the state drift. If the audit is killed, the app is still enforcing. Two separate processes, two separate termination events, and both of them are loud, not silent.

That is the only correction this page is offering to the category. Every “best parental control apps” review picks a winner on features. None of them picks a second process that verifies the first one is still on. That is the gap, and it is the one worth filling.

Want to see the AX audit running against your setup?

Fifteen minutes, real hardware, any of the four enforcement models. We show the diff, you decide if it belongs next to your chosen app.

Frequently asked questions

Why isn't this article a ranked list of the best screen time parental control apps?

Because the SERP already has fifty of those. Every listicle compares features and prices and lands on some mix of Qustodio, Bark, Norton Family, Apple Screen Time, and Circle. They all miss the same thing: every one of those apps reports its own status. If the app is disabled, the status page is also disabled. That is a category-wide blind spot, and it is unrelated to which app you pick. This page describes the four enforcement models underneath those apps and an independent audit layer that reads the macOS accessibility tree so tamper shows up regardless of which vendor you trust.

What are the four enforcement models parental control apps use on macOS?

Built-in, network, agent, and MDM. Built-in means Apple Screen Time, enforced by the OS itself through Family Controls. Network means DNS filtering on the home router or an always-on VPN, so traffic gets blocked before it reaches the device. Agent means a third-party app installs a macOS process that enforces time limits and site blocks locally (Qustodio, Bark, Norton Family, Mobicip). MDM means enrollment into a device management profile that pushes restrictions down as a policy. Each model has different failure modes, and this article lists them honestly.

What is the anchor fact the audit approach is built on?

Sources/MCPServer/main.swift line 843 watches attributeName == 'AXValue' across successive accessibility-tree snapshots and emits a text_changes line whenever that attribute transitions on any element. Applied to the System Settings process (bundle com.apple.systempreferences), this produces output like `~ 'Screen Time' AXValue '1' -> '0'` when the master Screen Time toggle flips off, and `~ 'Scheduled' AXValue '1' -> '0'` when Downtime gets disabled. Because the signal comes from the same tree Apple's UI renders, it is independent of whatever parental control vendor you chose.

Does this work for third-party parental control apps, not just Apple Screen Time?

Partially. The MCP server can open any macOS app by bundle ID and traverse its accessibility tree with macos-use_open_application_and_traverse, then refresh_traversal produces snapshots and diffs. So if Qustodio, Bark, or Norton Family exposes its on/off state as an AXCheckBox or AXButton title (most accessible apps do), the same AXValue transition signal works. Apps that do not expose their state to accessibility APIs are not observable from this layer, and that is a reason to favor accessible vendors.

What permissions does the audit layer require?

Accessibility only. Grant at System Settings, Privacy and Security, Accessibility. Screen Recording is optional and only needed if you want PNG screenshots saved alongside the traversal text file. Full Disk Access is not required. MDM enrollment is not required. A Managed Apple ID is not required. The audit works as a pure read of the AX tree with no kernel extension and no TCC-protected storage.

Can my kid disable the MCP audit layer by killing its process?

Yes, in the same way they could disable any parental app by killing its process, so this is not a silver bullet. The useful property is that the audit layer is separate from the enforcement app. If the enforcement app is killed, the audit layer survives and the next refresh_traversal call sees 'Screen Time' AXValue still at '1' even though the enforcement process is gone, and you can alert on the mismatch. If the audit layer is killed, the enforcement app is still running. Killing both requires two separate actions and is loud, not silent.

How many MCP tools does the server expose and what are they?

Six, defined between main.swift:1300 and main.swift:1408. They are: macos-use_open_application_and_traverse (open an app by name, bundle ID, or file path and return its AX tree), macos-use_click_and_traverse (click a point or an element found by text, optionally type and press a key, then traverse), macos-use_type_and_traverse (type text into the focused field then traverse), macos-use_press_key_and_traverse (send a key with modifiers then traverse), macos-use_scroll_and_traverse (scroll at a point then traverse), and macos-use_refresh_traversal (re-read the tree with no action). For audit, refresh_traversal is the one that runs on a timer; the others are only needed for setup.

Why is the coordinate system worth knowing for this use case?

Because the audit runs on macOS where many setups have multiple displays with negative x coordinates. The server uses a single logical point space: screen 0 starts at (0, 0), a left external monitor can sit at x around -3840, a right external monitor at x around 3456, and backingScaleFactor is 1.0 so one point equals one pixel. Click and scroll calls use the same space as the AX tree reports. Setting the audit up from the side, not from the child's main display, is a small operational win.

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