Back to Browse

Computer MCP Server

Developer ToolsModerate7.2MCP RegistryLocal
Free

Server data from the Official MCP Registry

macOS computer use with the guardrails on: passwords blacked out, writes need consent, all logged.

About

macOS computer use with the guardrails on: passwords blacked out, writes need consent, all logged.

Security Report

7.2
Moderate7.2Low Risk

Computer MCP is a well-engineered macOS automation server with strong security-by-design principles. Password redaction, mandatory human approval for sensitive operations, and comprehensive audit logging are implemented correctly. Code quality is good with proper error handling. No malicious patterns, hardcoded credentials, or dangerous dependencies detected. Minor code quality observations (broad exception handling, Danish-language comments, lack of input validation on some parameters) are typical for a mature security-focused tool and do not warrant significant deductions. Supply chain analysis found 1 known vulnerability in dependencies (0 critical, 1 high severity). Package verification found 1 issue.

7 files analyzed · 6 issues found

Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.

Permissions Required

This plugin requests these system permissions. Most are normal for its category.

File System Read

Reads files on your machine. Normal for tools that analyze or process local data.

File System Write

Writes or modifies files on your machine. Check that this is expected for the tool.

HTTP Network Access

Connects to external APIs or services over the internet.

env_vars

Check that this permission is expected for this type of plugin.

system_info

Check that this permission is expected for this type of plugin.

clipboard

Check that this permission is expected for this type of plugin.

What You'll Need

Set these up before or after installing:

readonly | ask (default) | allowOptional

Environment variable: CMCP_MODE

Seconds a consent dialog waits before refusing. Default 60.Optional

Environment variable: CMCP_ASK_TIMEOUT

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-agent360dk-computer-mcp": {
      "env": {
        "CMCP_MODE": "your-cmcp-mode-here",
        "CMCP_ASK_TIMEOUT": "your-cmcp-ask-timeout-here"
      },
      "args": [
        "-y",
        "@agent360/computer-mcp"
      ],
      "command": "npx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

Computer MCP

Computer use you can actually leave running.

A macOS computer-use MCP server built for the part everyone skips: what happens in the hours you are not watching.

  • It does not take over your Mac. It presses buttons and fills fields in windows that stay behind the one you are in, and it leaves your pointer where you put it. Nothing gets minimised, nothing comes to the front, nothing steals what you are typing.
  • It does not pretend. When something is refused or fails, it says so and says why. The most common complaint about agents driving a computer is that they carry on as if it worked.
  • Several can run at once. No session lock, no one-at-a-time limit. Writes to the shared log take a short file lock, so two servers cannot break the chain between them.
  • It will not go near your passwords. Keychain, 1Password and eleven others ask every time, in every mode, and password fields are blacked out while the screenshot is still in memory.
  • You can read back what it did. Every call lands in an append-only log, fingerprinted rather than stored in clear.
  • Electron apps are not a blind spot. Slack, VS Code, Discord and Notion build their accessibility tree lazily, so most tools find an empty window. This one switches the tree on itself before it looks. Measured on a VS Code fork with two windows open: 0 buttons before, 728 after, same windows, same moment. CMCP_INGEN_ELECTRON=1 turns it off if you would rather the app did not pay for keeping a tree it otherwise would not build.

Honest limits: macOS only. It reads the accessibility tree, so an app that draws its own controls on a canvas and publishes nothing - some games, some plotting tools - is still a blind spot. A browser is a separate case: the switch above is an Electron API, and Chrome does not implement it. Measured on Chrome: 29 buttons before and after, unchanged. You get the browser's own window - tabs, toolbar, address bar - and not the page inside it. For a page, drive the browser with a browser tool.

No account, no API key, no model inside it. MIT.

npx @agent360/computer-mcp

No Swift needed: the package ships a universal binary for Apple silicon and Intel. It carries the ad-hoc signature macOS needs to run it at all - not a Developer ID signature, and not notarized. Gatekeeper may therefore ask you the first time.

computermcp.dev · Security model


Why

Handing an agent your keyboard, mouse and screen is the most useful thing you can give it and the least reversible. A screenshot of a working developer's Mac can contain a password manager mid-unlock, a .env open in the editor, or customer data. A stray keystroke in a terminal is not a typo - it is a command.

Most desktop-automation MCP servers hand all of that over at once, with no way to say that, but not that. So the careful people don't run them on the machine where the work actually is.

This is the same capability with the dangerous edges answered.

The three gates

1. Passwords never reach the model. Secure text fields and password-manager windows are painted opaque black on the bitmap in memory, before the PNG is written. There is no moment where an unredacted picture of your desktop exists as a file. Native fields expose the role AXSecureTextField; fields in a web page expose role AXTextField with the subrole AXSecureTextField. Checking only the role would catch native fields and let every browser password box through - so both are checked.

2. Nothing clicks until you say yes. The first write action opens a real macOS dialog naming what is about to happen. Password managers and terminals ask every single time, even after the session was approved, even in allow mode - that one is not configurable. If nobody answers the dialog, the answer is no.

3. Everything is written down. ~/.local/state/computer-mcp/audit.jsonl, mode 0600, append-only: every call, its target app, and whether it was allowed or refused with the reason. Typed text is stored as a length and a salted SHA-256 prefix, never in clear - an audit trail full of passwords is its own breach. The salt is random per run and never written down, because an unsalted hash of a short password can be guessed offline by whoever holds the log. The honest cost: two actions can be compared within one run, not across runs.

Each gate has a test, and each test has been mutation-checked: break the code on purpose and the test goes red. See Testing.

Install

# Claude Code
claude mcp add computer -- npx -y @agent360/computer-mcp
// Cursor, VS Code, Codex CLI, Windsurf - mcp.json
{
  "mcpServers": {
    "computer": { "command": "npx", "args": ["-y", "@agent360/computer-mcp"] }
  }
}

Then grant two macOS permissions: System Settings → Privacy & Security → Accessibility, and the same under Screen Recording. Ask your agent to call computer_permissions and it will tell you what is still missing.

Which app do you grant them to? macOS attributes these to the responsible process, and which process that is depends on how you launched the server. Run from a terminal, it is usually the terminal. Run by an MCP client over npx, it may be the client instead. The honest answer is: grant it to whichever app the system dialog names, and if no dialog appears, start with the app that launched the client and check computer_permissions again.

Untested, and we would rather say so: we have not yet measured this from a clean machine with permissions reset, so we cannot tell you with certainty which of the two it will be in your setup, nor whether upgrading the package re-prompts. The helper is ad-hoc signed, which means its code identity changes with every build - if macOS keys your grant to the helper rather than to the host app, an upgrade could silently revoke it. Issue #4 tracks the measurement. If you hit either behaviour, telling us what you saw is a real contribution.

Modes

CMCP_MODEBehaviour
readonlyWrite tools are not even listed. The agent can look and cannot touch.
askDefault. One dialog grants the session. Dangerous apps still ask every time.
allowWrites proceed without asking, still logged. Dangerous apps still ask.

CMCP_ASK_TIMEOUT (seconds, default 60) controls how long a dialog waits before it refuses.

Tools

28 tools: twelve that look, sixteen that touch. Twenty are offered by default, and the agent uses them without asking - the same way a browser tool drives a browser. Two gates survive that, and they are the two that matter:

  • Password managers ask every time. Keychain, 1Password and eleven others, in every mode, even after you have said yes. That is the whole difference between you may work and you may have my passwords.
  • Anything that deletes or clears asks every time, recognised from the words in the action itself.

Everything else goes straight through and straight into the log.

It runs in the background, and that is the default. Nothing moves your pointer, brings an app forward or types into the window you are using. Four of the tools that used to need the screen - computer_type, computer_key, computer_scroll and computer_click - now take an app, and the event goes into that app's own queue instead of the global input stream. Measured on a machine while someone was working on it: the text arrived in the app, the pointer stayed where they had left it, and the front window did not change. Every key press, click, scroll and typed string answers with took_screen, so you never have to take our word for it.

Honest about how far that goes: typing and key presses are measured this way. Clicks and scrolls are built the same way and are not. A mouse event carries no window number, so whether an app accepts one it did not see the pointer arrive at is a question we have not answered yet. Until we have, the answer says took_screen: false about the screen - not that the click landed. The other writing tools - press, set_value, menu, window, drag, paste and move - do not carry the field yet.

computer_launch joins them with background: true: the app starts behind what you are doing, with nothing coming forward. Eight are still held back: move, activate, quit, space, window, drag, paste and ask_user. CMCP_BACKGROUND=0 gives you those too - and a typo will not turn it off, only 0, false, no or off. CMCP_MODE=ask puts one consent dialog per session in front of the first write, and CMCP_MODE=readonly leaves you the twelve that only look.

Both surviving gates are mutation-proved: break them in the source and the refusal turns into a free pass, which is how we know the test can fail.

What you get today, honestly. npx @agent360/computer-mcp currently serves 0.1.0, which has 12 tools. The 28 tools described here are the source: they are built and tested, but not published yet. Building from source takes about thirty-five seconds if you want them now. Look: computer_pending · computer_screenshot · computer_inspect · computer_find · computer_wait_for · computer_focused · computer_apps · computer_windows · computer_permissions · computer_displays · computer_menus · computer_audit

Touch: computer_launch · computer_quit · computer_paste · computer_window · computer_space · computer_menu · computer_press · computer_set_value · computer_ask_user · computer_click · computer_drag · computer_type · computer_key · computer_scroll · computer_move · computer_activate

computer_ask_user is the one that cannot carry a secret. It returns true or false, never text. The agent puts the cursor in the field, the dialog names the app and the window it is about to land in - written by the server, not by the model - and you type on your own keyboard. There is deliberately no route through this server for a password to reach a model.

computer_set_value writes into a field behind another window without moving your pointer, and refuses on a secure field every time. We removed that check on purpose once: the modified build wrote into the password box. It is the only thing standing there.

computer_wait_for waits for an element to appear instead of taking screenshots in a loop. Twenty polls cost one call here and twenty images the other way.

computer_inspect reads the accessibility tree - roles, titles, values, frames - so the agent can click a button by knowing where it is instead of guessing from pixels. computer_find narrows that to the elements matching a role, a title or a substring. Values of secure fields are never returned, not even to the agent.

Deliberately absent: no shell execution, no arbitrary file access, no URL fetching. Each would be one line of code. A computer-control server with a shell inside it is remote access under a friendlier name. If you want a shell, install a shell MCP server - then you have chosen it, and the choice is visible in your config.

Without taking over your screen

computer_click and computer_type go through the system's own input tap, so they land wherever the keyboard focus is and they move your real pointer. That is fine when you are watching. It is not fine when you are working in another window.

computer_press takes the other route: it fires the element's own accessibility action. That works while the window is behind another one, and it moves nothing on your screen. computer_find is how the agent locates the element to press.

computer_find  { "app": "com.apple.Safari", "role": "AXButton", "contains": "Log in" }
computer_press { "app": "com.apple.Safari", "contains": "Log in" }

Two or more matches is a refusal, not a guess - the agent gets the candidates and has to narrow it down, because pressing the first plausible button is exactly the kind of almost-right action nobody notices afterwards.

The consent dialog still comes to the front, and the apps on the always-ask list still ask every time. computer_press names its target app, and that name is what the gate judges - so pressing something in 1Password asks even when 1Password is nowhere near the front.

Several agents at once. Each MCP client starts its own server, so a second chat is just a second process. They share one audit log, and every line carries a per-server session mark - set CMCP_CLIENT=<name> and the line carries that too, so the log answers which conversation clicked. Fifty interleaved writes from two servers, zero torn lines: test/concurrent.mjs.

What is not solved yet: two servers pressing at the same time still share one pointer and one focused window, and there is no lock between them. Use computer_press for the background work, and keep the coordinate tools for the session you are actually watching.

What it does not do

  • macOS only (14+). No Windows or Linux build, and none planned.
  • Only what macOS marks as secure is redacted. A password in a plain text editor or a token in a terminal buffer is not marked and will not be hidden. Use readonly when the screen holds something the system cannot know about.
  • Consent is not containment. After you approve, the agent drives your real Mac - that is what you approved. If you need a boundary rather than a decision, run it in a VM. That is the honest answer, not a missing feature.
  • Prompt injection stays possible. The dialogs and the log make it visible rather than silent. They do not make it impossible.

Building from source

git clone https://github.com/Agent360dk/computerMCP
cd computerMCP/helper && swift build -c release     # the privileged binary
cd ../mcp-server && npm install
CMCP_MODE=readonly node index.js

The helper is a separate Swift binary with zero third-party dependencies. It is the part that uses Accessibility and Screen Recording, it is small enough to read in one sitting, and it can be replaced without touching the server. (Which process macOS grants those permissions to is a separate question, and an open one - see the note under Install.) Every package inside a binary that privileged is a vendor you are trusting without having chosen to.

Testing

./test/run-all.sh                # everything, full output kept in a log

python3 test/redaction-unit.py   # the four redaction checks
node test/server-e2e.mjs         # the MCP protocol, read paths, readonly refusal
node test/failclosed.mjs         # an unanswered dialog must refuse
node test/claims.mjs             # every claim this README makes
node test/concurrent.mjs         # two servers at once: no torn lines, both identifiable
./test/redaction-proof.sh        # live secure-field detection (needs a normal desktop)

claims.mjs checks the sentences on the front page against the code: that a terminal still asks in allow mode, that a harmless app does not (otherwise "refuse everything" would pass), that typed text reaches the log only as a length and a hash, and that no shell, file or URL tool has appeared.

Where a check cannot be made meaningfully - no secure field happens to be on screen - it reports SKIPPED, not passed. A green suite that measured nothing is the failure mode these tests exist to avoid.

redaction-unit.py builds its own image instead of measuring the live screen. The first version measured the real desktop - and on a machine where the editor runs full-screen the test window could not appear at all, so the test measured an empty screenshot and called it a pass. A security test that passes when it cannot see anything is worse than no test.

redaction-proof.sh still exercises the live path and needs a desktop that is not in full-screen mode. It fails loudly rather than skipping quietly.

Help build it

The redaction list holds the password managers we thought of. It does not hold your banking app, your company's secrets manager, or whatever is popular where you live. One team cannot write that list; many people adding one line each can - and every app someone contributes makes the tool safer for everyone who installs it afterwards.

That takes an issue form and no code. So does writing down how some Mac app actually behaves, which is knowledge that currently only exists in the heads of people who already fought it.

The wishlist is the rest: open items, sized honestly, none of them assigned. How contributing works.

Who makes this

Built by Agent360, a Danish shop building agents that do real work:

  • Browser MCP - the same idea for a real, logged-in Chrome. Written alongside this one, and the two share their lessons.
  • JesperAI - voice agents that hold an actual conversation on the phone.
  • ForbrugerAgenten - an agent that reads your household bills and switches your provider for you.

Everything here is MIT and runs on your machine. None of the above is required, bundled, or phoned home to.

What this project is for

Dev-troværdighed, not a growth engine. The same mandate as its sibling browser-mcp: honesty, correcting untrue claims, and guards that can actually go red. Growth, SEO and channel work are not the job unless asked for.

The full mandate, and the one reason this project is allowed to exist, is in MANDAT.md.

Privacy

Nothing leaves your machine because of this server. There is no account, no telemetry, no server of ours in the path, and no network call the server makes on its own.

  • Screenshots go to the MCP client you configured - the same place the rest of your conversation goes - and nowhere else. Secure text fields are blacked out in the image buffer before the PNG is ever written, so a password is not in the file that is sent.
  • The audit log lives only on your disk, at ~/.local/state/computer-mcp/audit.jsonl. It stores a salted fingerprint of typed text, never the text. Delete the file and it is gone.
  • We collect nothing. No identifiers, no usage counts, no crash reports.

Full policy: https://computermcp.dev/privacy.html

Licence

MIT © Agent360 Group ApS.

Reviews

No reviews yet

Be the first to review this server!