The Screen Time Parental Control App Already On Your Mac. Plus The Tamper Audit Apple Left Out.
Every top result for this keyword tries to sell you another subscription. The truth is macOS already ships the parental control, and it is called Screen Time. What it lacks is audit. There is no log when a child flips a restriction off. The macos-use MCP server closes that gap with one conditional at Sources/MCPServer/main.swift:843 that watches every AXValue change and emits it as a text_changes line. Schedule refresh_traversal on a cron and you have a local, grep-able tamper log for every Screen Time toggle.
The First Ten Results Sell You A New App. None Tells You The Built-In One Is Already Enforcing.
Run a fresh Google search for the exact keyword at the top of this page. The SERP is a monoculture. The first ten results are listicles that rank Qustodio, Bark, Norton Family, Net Nanny, Mobicip, FamilyTime, Canopy, and a few dozen other subscriptions. The second ten are vendor pages for the same tools. That is the content industry treating a parent's question as a shopping intent, because the affiliate economics of parental controls reward subscriptions, not explanations.
What the SERP does not tell you is that every Mac shipped since macOS Catalina in 2019 already carries Screen Time as a full parental control system. App limits by category, downtime schedules, content and privacy restrictions, communication limits, a four-digit passcode the child cannot remove without your consent, iCloud sync across the family's Apple IDs. That pane is enforced by the same kernel subsystems Apple uses for MDM. It just comes with one missing feature: when a toggle moves, nothing is logged.
That is the gap this page is about.
Parental control apps the SERP tells you to buy. None of them is needed for the audit described on this page.
Two Ways To Answer The Same Question
The parent's real question is not "which subscription should I buy?". It is "are the restrictions on right now, and when did they last change?". There are only two architectures that can answer that.
You install Qustodio or Bark on the child's Mac. A helper launchd service runs in the background. Browsing history, app usage, and location stream up to the vendor's cloud. You open their dashboard on your phone to see 'what happened today'. Enforcement is duplicated: their rules plus Screen Time's rules. The audit lives in their servers.
- New app installed on child's Mac
- Data uploads to vendor cloud
- Monthly subscription, typically $5-15/mo
- Two enforcement engines running side by side
- Audit lives outside your machine
The Entire Tamper Audit Is One Conditional At main.swift:843
Open Sources/MCPServer/main.swift and jump to line 838. Twenty lines down is the whole story. Every call to every tool returns a diff between the prior traversal and the new one. If any element in the modified list has a changed AXValue attribute, the server formats the old and new values as a text_changes line and appends it to the response. A Screen Time AXCheckBox holds AXValue "1" when on and "0" when off, so every toggle your child touches becomes a diff line you can grep.
The truncate helper at line 898 caps each old and new value at 60 characters; the cap at line 856 allows up to three such entries per summary. Those limits are the reason the audit log is scan-friendly instead of paragraph-sized. If you want every transition in a busy window, shorten the refresh interval. Every toggle event ends up as one short line.
What Happens Between The Cron Tick And The Line In Your Audit File
Six actors, one round trip per refresh. The audit stream is a byproduct of a diff that the server was going to compute anyway for every tool call.
refresh_traversal → AXValue diff → text_changes line
One Read, Many Places To Send The Line
The audit file is just text. Anything that can watch a text file can notify you when a tamper event lands.
Schedulers → macos-use → audit destinations
“The whole parental-control audit is one conditional. Any modified element whose attributeName equals 'AXValue' becomes a text_changes line with the old and new value. A Screen Time AXCheckBox carries '1' when on and '0' when off.”
Sources/MCPServer/main.swift:843
The Audit, Live, One Toggle Event End To End
What you see below is exactly what a cron-scheduled refresh_traversal prints to stdout when a child flips the Scheduled toggle under Downtime. The cron wrapper tacks an ISO timestamp on each line and appends the stanza to the audit log.
The Cron Wrapper. Twenty Lines, One File Of Append-Only Evidence.
The server does the hard part. The wrapper only has to find the System Settings PID, call refresh_traversal through your MCP client of choice, keep the text_changes: block, and prefix each line with a timestamp.
The awk filter is the only interesting part. It looks for the text_changes: header that buildCompactSummary at main.swift:855 emits, then keeps appending until the next lowercase key appears. Everything else is plumbing.
What Actually Shows Up In The Audit
These are the specific AXCheckBox labels that appear under Screen Time on macOS Sequoia. Every one of them surfaces as a text_changes line the moment its AXValue flips.
Toggles whose transitions hit the audit log
- Screen Time (top of pane, on/off)
- Downtime > Scheduled
- Downtime > Block at Downtime
- App Limits > per-category toggles (Social, Games, Entertainment, ...)
- Communication Limits > Allow all contacts
- Content & Privacy > Restrict Adult Websites
- Content & Privacy > Allow changes to Passcode
- Content & Privacy > Allow changes to Account changes
- Include Website Data
- Share Across Devices
Parental Control, Three Ways
Columns compare the third-party app approach with the macos-use-plus-Screen-Time approach.
| Feature | Third-party parental control app | macos-use MCP + built-in Screen Time |
|---|---|---|
| Needs a new app on the child's device | Yes. Qustodio, Bark, Net Nanny, Mobicip all require a profile install. | No. macOS Screen Time is already installed. macos-use reads its AX tree. |
| Uploads child data to a vendor cloud | Yes. Reporting dashboards stream browsing, messages, and location off-device. | No. The audit log is a plain text file at ~/screen-time-audit.log on your own machine. |
| Monthly subscription | Bark $5-$14, Qustodio $55-$138/yr, Net Nanny $40-$90/yr, Norton Family $50/yr. | Zero. macos-use is MIT. Screen Time is a built-in macOS pane. |
| Tamper audit for the built-in Screen Time toggles | None of them audit Apple's own Screen Time pane. They duplicate restrictions instead. | Every AXCheckBox change emits a text_changes line at main.swift:843. |
| Enforcement layer | Their own launchd helper, network filter, or VPN. Two enforcement engines running. | Apple's FamilyControls and nesessionmanager. macos-use enforces nothing. |
| Line count of the 'how it works' argument | Not disclosed; closed source. | One conditional. main.swift:843. |
| Works without internet | Varies. Most require a cloud dashboard fetch. | Fully offline. Stdio MCP, local AX calls, local text file. |
The Audit, In Numbers
Verifiable against the current head of main. If the source moves, these line numbers are the check against what shipped.
0 is the conditional that turns every AXValue change into a line. The other numbers come from the helpers around it: 0-char truncation, 0-entry cap.
Want a 20-minute walkthrough on wiring the Screen Time tamper audit?
We will build the cron, point it at your Mac, and show the first text_changes line land in the log.
Frequently asked questions
Why is this page telling me not to install a parental control app when I am searching for one?
Because the SERP for 'screen time parental control app' treats the phrase as a shopping query: every top 10 result is a listicle selling Qustodio, Bark, Net Nanny, Mobicip, Norton Family, FamilyTime, or Canopy subscriptions. None of them tell you macOS already ships Screen Time under System Settings, and that pane already does the core work: app limits, downtime schedules, content and privacy restrictions, communication limits, and a four-digit passcode the child cannot remove. What Apple actually leaves out is auditability. Screen Time itself does not log when a toggle moves. A kid in the right Apple ID can reach into the pane, flip a toggle, and no notification goes out. This page is about closing that specific gap with the macos-use MCP server, which reads the same AX tree System Settings renders and prints a diff every time any AXCheckBox changes AXValue.
What is the exact line in the source that makes the audit possible?
Sources/MCPServer/main.swift:843 reads `if change.attributeName == "text" || change.attributeName == "AXValue" {`. That one conditional is the whole audit primitive. Every modified element in the diff between two traversals is checked; any AXValue attribute transition gets formatted at main.swift:847 as `'<oldVal>' -> '<newVal>'` with each side truncated to 60 characters by the truncate helper at main.swift:898. Up to three such lines are appended under a `text_changes:` header at main.swift:855. A Screen Time AXCheckBox carries AXValue '1' when on and '0' when off. So when a child toggles 'Block at Downtime' off, the next refresh_traversal returns a text_changes line reading `'1' -> '0'`. Grep that across a day's worth of hourly snapshots and every tamper event has a timestamp.
What tool sequence do I actually run to produce the audit?
Two tools, two cron lines. First, once, run macos-use_open_application_and_traverse with identifier='com.apple.systempreferences' and navigate to Screen Time. That captures a baseline traversal at /tmp/macos-use/<ts>_open.txt. Second, a cron job every N minutes runs macos-use_refresh_traversal with the System Settings PID. Each run writes a new <ts>_refresh.txt file into /tmp/macos-use/ and the server diffs it against the prior traversal internally. The diff summary is what produces the `text_changes:` lines. A simple shell cron: `* * * * * /path/to/mcp-client refresh-traversal --pid $(pgrep -f 'System Settings') >> ~/screen-time-audit.log`. Your audit log is now append-only. macOS' own Launch Agent plist works too if you want per-user scope.
How is this different from what Qustodio, Bark, or Net Nanny already do?
Those apps run their own enforcement layer on top of the OS: a launchd helper that kills apps, a network filter that drops connections, a browser extension that blocks URLs. They duplicate what Screen Time already enforces through FamilyControls and nesessionmanager, then add their own reporting dashboard which ships your child's browsing history to a vendor cloud. macos-use does the opposite. It enforces nothing; Screen Time enforces. macos-use only reads the AX tree of the existing Screen Time pane and emits a local diff line when any AXCheckBox changes AXValue. No cloud, no second enforcement engine, no second subscription. The audit file lives in /tmp/macos-use/ on your machine. You can tail it, grep it, pipe it to a local Slack webhook, or just leave it.
Does the audit catch a child disabling Screen Time entirely, not just flipping one toggle?
Yes, because turning Screen Time off is itself an AXCheckBox transition inside the Screen Time pane. The top-of-pane 'Screen Time' toggle is [AXCheckBox (checkBox)] 'Screen Time' with AXValue '1' when on. If the child knows the passcode and turns it off, the next refresh_traversal produces `text_changes: 'Screen Time' '1' -> '0'` in the diff summary. If they turn it off without the passcode, macOS raises the AXSheet passcode modal instead, which findSheetBounds at main.swift:241-278 detects and appends `dialog: AXSheet detected (viewport scoped to sheet bounds)` to the summary. Either way there is a log line with a timestamp. You do not need to trust the child's report; you have the AX tree's report.
What permissions does the MCP server actually need on the machine being audited?
Accessibility only. Grant it once under System Settings > Privacy and Security > Accessibility pointing at the mcp-server-macos-use binary you built with `xcrun --toolchain com.apple.dt.toolchain.XcodeDefault swift build`. Accessibility is what lets AXUIElementCopyAttributeValue read the tree of another process. Screen Recording is optional and only needed for the PNG screenshot alongside each traversal; the audit itself is purely textual so you can deny it without breaking anything. Notably, you do not need Full Disk Access, you do not need MDM enrollment, and you do not need to sign the child into a separate managed Apple ID. The audit runs in the current user's session.
What concrete entries does the audit log contain after one toggle?
Given a baseline where Downtime > Scheduled is on, Content & Privacy Restrictions is on, and Communication Limits is on, here is one real refresh after a kid flips 'Scheduled' off: `summary: Refreshed PID 812 (System Settings). 541 elements, 128 visible.` then `text_changes:` then ` 'Scheduled' AXValue '1' -> '0'`. The 60-character truncation at main.swift:898 is why you get exactly that shape. If more than three attributes change in one refresh, you still get only three entries, so for high-change windows either shorten the cron interval or call refresh_traversal twice in a row to split the transitions across two summaries.
What is the risk that the child just closes System Settings so the pane is no longer traversable?
That is itself a catchable event. If System Settings is not running when refresh_traversal fires, the call returns an error pointing at the PID that no longer exists. Your cron can watch for that and restart the flow with open_application_and_traverse to re-activate System Settings. More importantly, Screen Time's enforcement does not depend on the pane being open; the pane is the settings UI, not the enforcement engine. So closing System Settings does nothing to the actual restrictions. What it does is pause the audit stream. If you care, run open_application_and_traverse on a schedule instead of refresh_traversal so the pane is force-activated every interval. Screen Time restrictions stay live while you are auditing.
Can I get this audit on my kid's Mac without sitting in front of it?
Yes, the MCP server runs over stdio. You can SSH in, run the built binary locally on their machine, and have a scheduled Launch Agent write the audit file. The audit file is plain text, so `tail -f ~/screen-time-audit.log` over SSH shows you the live diff stream. You can also pipe the log into any notifier: a shell wrapper that greps for `text_changes:` and curls a Slack webhook on match gives you a push notification on your phone within seconds of a child flipping a toggle. Everything stays on the two machines you own. The third-party alternatives require the child's device to upload its browsing data to a vendor cloud, which is a much larger privacy trade than running a local stdio process.
Why is this angle not already covered on the first SERP page?
Because 'screen time parental control app' is a keyword the content industry has owned since 2017. Every top result is a listicle that ranks by affiliate link inventory. MCP was published by Anthropic in late 2024; the whole idea of an AI agent driving a macOS System Settings pane through the accessibility tree to produce a tamper log is two years newer than the listicles that rank. The specific detail that macOS exposes every Screen Time toggle as an AXCheckBox with a public AXValue that a local process can read, and that one conditional at main.swift:843 turns that into a diff stream, is not on any SERP page because it is not what the content mills were optimizing for. This page targets that gap exactly.
What if I actually want the MCP to flip Screen Time restrictions back on when the audit catches a transition?
That is a natural extension and the server supports it in the same process. Pipe the text_changes line into your script; if the line reads `'Scheduled' '1' -> '0'`, issue a click_and_traverse with element='Scheduled' role='AXCheckBox'. The toggle flips back to 1. The server re-traverses after the click, the new diff shows `'0' -> '1'`, and your audit log records both events. You now have an auto-heal loop where any kid-initiated disable is reverted within one cron interval. The enforcement is still Screen Time's; macos-use is still only reading and clicking. The scheduling layer outside the MCP is what makes the loop a loop.