Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

fschrhunt/Edoras

Repository files navigation

Edoras

Edoras is a local Safari control layer for agents on macOS. It exposes a stdio MCP server plus a native Swift helper so an agent can inspect Safari tabs, attach to a tab, open an agent-owned tab, navigate it, observe page state, and show visible presence in Safari without a Safari extension.

It is built for agents that should use Safari, not a generic headless browser. The browser stays visible, the attached tab is explicit, and foreground actions refuse to run unless Safari is actually frontmost.

The presence UI has two parts:

  • A clean static blue marker on the real Safari tab button.
  • A glowing animated blue border around the visible page area when the attached tab is also the visible Safari tab.

Edoras is intentionally local-first. It does not collect telemetry, grant macOS permissions for you, enable safaridriver, or install a browser extension.

Requirements

  • macOS with Safari
  • Xcode Command Line Tools or SwiftPM
  • Node.js 18 or newer
  • A local MCP-capable host such as Claude Desktop, Codex, or another stdio MCP client

Quick Start

git clone https://github.com/fschrhunt/Edoras.git
cd Edoras
npm install
npm run build
npm test
npm run doctor

Then request the macOS permission prompts:

npm run request-permissions

request-permissions can open the right System Settings pane, but macOS still requires you to grant permissions manually.

macOS Permissions

Edoras uses Apple Events and Accessibility APIs to work with Safari.

Grant permissions to the app or host process that launches Edoras. Depending on how you run it, that may be Terminal, iTerm, Claude Desktop, Codex, node, swift, or the built edoras-helper.

Recommended setup:

  1. Open System Settings.
  2. Go to Privacy & Security.
  3. Enable Accessibility for the host process that will run Edoras.
  4. Go to Privacy & Security -> Automation.
  5. Allow the host process to control Safari when macOS asks.
  6. In Safari, enable Develop -> Allow JavaScript from Apple Events for richer page observation.

If you do not see the Develop menu in Safari:

  1. Open Safari Settings.
  2. Go to Advanced.
  3. Enable "Show features for web developers".
  4. Use Develop -> Allow JavaScript from Apple Events.

Check your setup at any time:

npm run doctor

Install Locally

For a stable local command path:

npm run install-local

This builds release binaries and creates symlinks in ~/.local/bin:

  • edoras-helper
  • edoras-menubar
  • edoras-mcp

Use a different destination if needed:

EDORAS_BIN_DIR=/usr/local/bin npm run install-local

MCP Setup

Edoras runs as a local stdio MCP server.

Use this command:

node <path-to-edoras>/bin/edoras-mcp.js

For release builds, set EDORAS_HELPER:

EDORAS_HELPER=<path-to-edoras>/.build/release/edoras-helper node <path-to-edoras>/bin/edoras-mcp.js

Generic MCP Config

{
  "mcpServers": {
    "edoras_safari": {
      "command": "node",
      "args": ["<path-to-edoras>/bin/edoras-mcp.js"],
      "env": {
        "EDORAS_HELPER": "<path-to-edoras>/.build/release/edoras-helper"
      }
    }
  }
}

If you installed locally and ~/.local/bin is on your PATH, you can use:

{
  "mcpServers": {
    "edoras_safari": {
      "command": "edoras-mcp",
      "env": {
        "EDORAS_HELPER": "<path-to-edoras>/.build/release/edoras-helper"
      }
    }
  }
}

Claude Desktop

Claude Desktop commonly reads MCP config from:

~/Library/Application Support/Claude/claude_desktop_config.json

Add edoras_safari under mcpServers, then fully quit and reopen Claude Desktop.

Codex

If your Codex setup supports MCP servers in ~/.codex/config.toml, add:

[mcp.edoras_safari]
command = "node"
args = ["<path-to-edoras>/bin/edoras-mcp.js"]

[mcp.edoras_safari.env]
EDORAS_HELPER = "<path-to-edoras>/.build/release/edoras-helper"

Restart Codex or reload its MCP configuration after editing.

MCP Tools

The MCP server exposes:

  • safari_status
  • safari_attach_current
  • safari_list_tabs
  • safari_open_tab
  • safari_navigate
  • safari_focus_tab
  • safari_observe
  • safari_click
  • safari_type
  • safari_key
  • safari_screenshot
  • safari_ocr
  • safari_show_presence
  • safari_end_session
  • safari_close_agent_tab

Suggested first tool calls:

  1. safari_status
  2. safari_open_tab with a harmless URL such as https://example.com
  3. safari_observe
  4. safari_show_presence

What Agents Can Do

  • Inspect Safari status and visible tabs.
  • Attach to the current tab or open an agent-owned tab.
  • Navigate, observe, click, type, and send keys with foreground checks.
  • Capture screenshots and OCR through the local helper.
  • Show visible tab/page presence so the human can see when Safari is under agent control.

Direct Helper

You can test without MCP:

swift run edoras-helper status
swift run edoras-helper doctor
swift run edoras-helper list-tabs
swift run edoras-helper open-tab --url https://example.com
swift run edoras-helper observe
swift run edoras-helper show-presence
swift run edoras-helper overlay-status
swift run edoras-helper end-session

Menu Bar App

Edoras includes a small native menu bar controller:

swift run edoras-menubar

The menu bar app provides common actions such as status, attach current tab, open agent tab, show presence, run doctor, and request permissions.

To launch it at login:

npm run launch-agent:install

To remove the launch agent:

npm run launch-agent:uninstall

Behavior And Safety

  • safari_open_tab opens and tracks an Edoras-owned tab.
  • safari_close_agent_tab only closes tabs Edoras opened itself.
  • safari_attach_current attaches to the current Safari tab, so use it only when that tab is meant for the agent.
  • safari_navigate can navigate the attached Edoras tab without focusing Safari.
  • safari_click, safari_type, and safari_key are foreground actions. They refuse to run unless Safari is frontmost and the attached Edoras tab is visible.
  • Tab presence only uses real Safari tab-button geometry.
  • Page presence only draws around the visible page for the attached visible tab.
  • Window-level highlighting is diagnostic only through show-presence --mode window.

Verification

Run the full local check:

npm install
npm run build
npm test

Presence verification touches live Safari geometry, so run it locally when Safari is available:

npm run verify:presence

npm run verify:presence validates geometry without forcing a long-lived visible overlay. To test the visible overlay:

EDORAS_VISUAL_TEST=1 npm run verify:presence

If Safari is not open or the attached tab is not visible, presence verification may skip page checks instead of failing.

Troubleshooting

If tools are missing in your MCP host:

  • Confirm the MCP config uses absolute paths.
  • Confirm Node.js is installed and available to the host.
  • Fully quit and restart the MCP host.
  • Run EDORAS_HELPER=<path-to-edoras>/.build/release/edoras-helper node <path-to-edoras>/bin/edoras-mcp.js manually and check for JSON-RPC startup errors.

If Safari control fails:

  • Run npm run doctor.
  • Recheck Accessibility and Automation permissions.
  • Confirm Safari is running.
  • Enable Safari Develop -> Allow JavaScript from Apple Events for richer observation.

If presence appears in the wrong place:

  • Run swift run edoras-helper observe.
  • Check tabPresence.source and pagePresence.source.
  • Run swift run edoras-helper overlay-status while the overlay is visible.

Privacy

  • Local state is stored in ~/Library/Application Support/Edoras.
  • Edoras does not collect telemetry.
  • Safari and macOS permissions remain local and user-granted.
  • safaridriver is optional and is not enabled automatically.

Limitations

  • Safari tab geometry is best-effort because Safari does not expose a stable public tab-rectangle API.
  • Exact page-region detection depends on Accessibility. Edoras uses a conservative content-area fallback when needed.
  • Background navigation is supported, but background clicking and typing are intentionally refused.
  • Edoras is macOS/Safari-only.

License

MIT

About

Safari-focused local agent control for live tabs, page visibility, and tab presence

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors