Skip to content

Edison-Watch/detectord

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Edison Quarantine Daemon

Open Rust code for the Edison Watch MCP quarantine system agent. It discovers the MCP (Model Context Protocol) servers configured across a machine's host apps (Claude Code, VSCode, …) and — when an admin requires it — quarantines them: moves them off the local config and onto the Edison Watch backend.

The target design (a privileged, non-stoppable, multi-user enforcement daemon) is specified in docs/architecture.md — read that for the why behind the decisions (root LaunchDaemon, getpeereid scoping, fail-closed policy, quarantine-first, level-triggered reconciliation, the frozen fingerprint contract). This README describes what is implemented today; the repo is mid-migration from a read-only detector toward that design.

Workspace

Crate Path Role Status
edison-detectord crates/edison-detectord/ Read-only engine: agent abstraction, discovery, fingerprint, filesystem watcher. Cross-platform, publishable. Reshaped
mcp_quarantine crates/mcp_quarantine/ Mutation + state + the reconcile planner. No privilege/IPC/network. Planner done; seen-store + writers WIP
mcp_detector_daemon crates/mcp_detector_daemon/ Long-lived macOS daemon wrapping the engine behind a Unix-socket IPC. Being reworked to the root enforcement model

Build everything: cargo build --workspace --release. Test: cargo test --workspace.

Motivation

MCP servers are configured independently by each host app — often in several places per app: a global user-level file, per-project files, and sometimes application state in a SQLite database. Quarantine is imposed by admins, so it must run as a system agent the user cannot stop. That posture — a privileged enforcement agent that assumes the local user is adversarial — drives the whole design.

Library — edison-detectord

The read-only engine. Cross-platform, no root, no network.

  • Agent abstraction. Each supported host app implements the Agent trait: name, is_installed, watch_targets, and discover. discover normalises each on-disk entry into a DiscoveredServer carrying its raw config ([ServerConfig::Stdio | Http | Unsupported]) and a location (where + how to mutate it).
  • Server fingerprint. fingerprint computes the stable identity used to ask "is this server already known to the backend?". It is a frozen cross-implementation contract — byte-for-byte identical to the Python backend and the TS client (sha256(identifier)[:16], secrets templatised first via secret_detection). Pinned by golden-vector tests. See docs/architecture.md §6.
  • Event-driven watching. Watcher uses notify-debouncer-full against parent directories (editors write configs via atomic rename, which breaks single-file watches) and emits ChangeEvents. (This edge-triggered watcher will be superseded by the daemon's level-triggered reconcile driver — see the design doc.)

Source shapes

Config sources differ in format (JSON / JSONC / SQLite state DB), scope (a single file can mix global and project entries, e.g. Claude Code's ~/.claude.json projects map), and location (project configs live inside each project dir). The Agent trait hides all of this; servers that expose no extractable command/url (e.g. VSCode extension-provider contributions) are emitted as ServerConfig::Unsupported — surfaced for reporting, skipped by enforcement.

Supported agents

Agent Status Cargo feature Notes
VSCode Implemented vscode Global, per-workspace, and extension/marketplace (state.vscdb) servers
Claude Code Implemented claude_code Global + per-project servers (~/.claude.json, .mcp.json)
Cursor, Claude Desktop, Zed, Codex Planned

Use as a dependency

[dependencies]
edison-detectord = "0.1"
use std::sync::Arc;
use edison_detectord::{Agent, Result, Watcher, clients::{ClaudeCode, VsCode}};

fn main() -> Result<()> {
    let agents: Vec<Arc<dyn Agent>> = vec![
        Arc::new(VsCode::discover()?),
        Arc::new(ClaudeCode::discover()?),
    ];
    let (events, _handle) = Watcher::new(agents).spawn()?;
    for ev in events {
        println!("{ev}");
    }
    Ok(())
}

discover() uses platform-specific paths; for tests/CI use from_paths(...). Each agent lives behind its own cargo feature (vscode pulls in rusqlite; both on by default).

Quarantine layer — mcp_quarantine

Mutation, persistent state, and the decision logic — no privilege, no IPC, no network (the daemon injects those). Everything here is unit-testable in a tempdir.

  • Reconcile planner (reconcile.rs) — implemented. The pure, level-triggered heart: plan(observed, oracle, policy) -> Vec<Action>. Quarantine-first — an unknown server is neutralised immediately, then surfaced for disposition; a known one is quarantined silently; the policy-off pass is inert; our own edison-watch entry and report-only servers are skipped. Being level-triggered, it is inherently tamper-resistant (a restored server simply reappears next pass).
  • Seen-store (the KnownOracle) and config writers (quarantine/restore, dispatched on SourceKind) — in progress.

Daemon — mcp_detector_daemon

Long-lived macOS process wrapping the engine over a Unix-domain socket. Today it is the original read-only design: it watches configs gated on Full Disk Access and reports ChangeEvents; it performs no mutation.

It is being reworked into the privileged enforcement daemon from the design doc: root LaunchDaemon, one socket with getpeereid per-user scoping, per-user reconcile workers, enrollment + fail-closed policy, an operator CLI (install/uninstall/unenroll/status), and a state.json status file. See docs/architecture.md §4–§10.

Repository layout

.
├── Cargo.toml                # virtual workspace
├── docs/architecture.md      # design source of truth
└── crates/
    ├── edison-detectord/      # read-only engine
    ├── mcp_quarantine/        # mutation + state + reconcile
    └── mcp_detector_daemon/   # macOS daemon binary

About

A Rust library for detecting and tracking MCP Client configuration files and databases

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages