Dev.to Security πŸ” Cybersecurity πŸ‘ 0 πŸ“– 4 min read

I Let ChatGPT Work on My Mac. The Hard Part Was Saying No

ChatGPT can explain almost any routine computer task. Letting it perform that task introduces a more interesting question: who decides which actions are allowed? I build Mac MCP, an open-source local execution layer for

ChatGPT can explain almost any routine computer task. Letting it perform that task introduces a more interesting question: who decides which actions are allowed?

I build Mac MCP, an open-source local execution layer for macOS. It gives MCP-compatible AI clients access to browser automation, files, shell commands, and native apps. I originally wanted less copying and pasting between a conversation and my desktop. Instead, I found myself spending a lot of time designing what happens when an agent asks for something it shouldn't be able to do.

This is a practitioner's account of architectural trade-offs, not a formal security audit.

Keep the conversation separate from execution

A model is useful for interpreting intent: β€œCheck my repository and tell me what changed.” The local service is responsible for actual operations: reading Git status, locating files, calling browser tools, and returning evidence.

Those two layers have different responsibilities. The model should be allowed to propose a sequence of steps. It should not be the authority that expands its own permissions.

This separation also means the execution layer isn't tied to a single AI model or subscription. Mac MCP exposes a native MCP interface, with a smaller REST/OpenAPI compatibility surface for clients that need it. A ChatGPT panel is optional; it doesn't change the server's permission model for other clients.

That's a product decision as much as a technical one. I can change the conversation interface without rebuilding the local boundary that protects the machine.

A harmless-sounding instruction can cross a boundary

Imagine asking: β€œCheck whether my development environment is healthy.”

Reading recent logs is reasonable. Running a status command may also make sense. Deleting a runtime directory or uploading your private environment file does not.

All four operations might be expressible with a powerful shell tool. That is why a tool name alone makes a poor security policy.

Mac MCP uses capability profiles and explicit boundaries around sensitive operations. Its secure bootstrap also fails closed when important settings are missing. For a public endpoint, authentication is required; local transport by itself is not a same-user sandbox.

I want an agent to explain which operation would help, not infer that because the user's goal is benign, every possible means of achieving it is authorized.

Permission and approval are different questions

There are two decisions worth separating:

  1. May this client perform this category of operation at all?
  2. If it may, does this particular risky action require a one-time human confirmation?

A blocked capability should remain blocked even when an approval interface is present.

The optional Mac MCP server approval layer can ask for Allow Once or Block on qualifying high-risk actions. The decision is scoped to the specific operation. It is not a lifetime credential that the agent can casually reuse for another task.

That distinction prevents an unfortunate pattern: an agent performs a small, approved change, and later interprets the user's earlier click as blanket trust.

Of course, too many approval prompts create fatigue. The answer can't simply be β€œask before everything.” Good tools need useful read-only operations and clear risk categories so routine inspection doesn't feel like a security ceremony.

Don't sacrifice the user's desktop to make the demo look alive

The machine has another scarce resource: the owner's focus.

An AI agent that opens a new Safari tab in the foreground every few seconds may complete its task and still be an awful assistant. In Mac MCP, ordinary browser operations can target existing, real Safari or Chrome tabs in the background. The user can keep typing in another window.

This is not the same as promising that every macOS interaction can be done invisibly. Some native UI fallbacks are foreground-only. Those behaviors need explicit gating, and the tool should fail rather than silently stealing focus when it cannot satisfy a background-only request.

In a product, not interrupting the user is a feature you have to engineer.

An outcome should be observed, not imagined

I also learned to distrust confident completion messages.

Suppose an agent clicks Submit on a web form. The tab closes before any confirmation arrives. The model could say β€œDone.” It could also automatically retry. Neither is necessarily correct.

The useful response is to distinguish what was attempted, what was observed, and what is still unknown. Replaying an uncertain write might create a duplicate.

The same principle appears when the agent restarts its own local service. The original connection may disappear during a successful restart. That isn't proof of success or failure. The new process needs its own health check before the assistant can report a completed recovery.

A good execution layer returns enough structured evidence for the conversation layer to be truthful.

What I would test before trusting the system

I'd test a read-only client requesting a destructive write, an unavailable approval service, a browser tab disappearing during a mutation, and a server restart that drops the caller's connection.

I'd also check that a client cannot turn on foreground control by slipping an optimistic parameter into a tool request. These are ordinary integration tests with uncomfortable scenarios, not exotic attacks.

The goal is not to market a β€œperfectly safe agent.” It is to make the limits inspectable and the failures explicit.

Why I keep building it

A useful desktop agent should feel less like a robot operating your mouse and more like a well-behaved collaborator. It needs tools, but the boundaries around those tools determine whether I'd actually trust it with my daily work.

The most interesting line of code in an agent project is sometimes the one that says no.

Mac MCP is available on GitHub under the MIT license. I'd welcome feedback on where you draw the line between strict local control and convenient autonomy.

Disclosure: I'm the Mac MCP maintainer. I used AI assistance to draft and edit this article; the engineering decisions and views described here are mine.

πŸ“° Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.