Skip to main content
Glama
DanFashauer

SignalGrid MCP

by DanFashauer

SignalGrid MCP

An MCP (Model Context Protocol) server that exposes macOS-native device trust signals — the facts about a Mac that cannot be gathered from a Linux container or a cloud runner. Every tool is strictly read-only: nothing on the device is ever mutated.

What it answers

Signal

Tool

Who is this machine? (serial, UUID, chip, activation lock)

signalgrid_device_identity

What OS build is it on?

signalgrid_os_info

Are SIP / FileVault / Gatekeeper / firewall on?

signalgrid_security_posture

What remote access is exposed? (SSH, Screen Sharing, SMB, ARD)

signalgrid_sharing_services

Is it MDM/DEP enrolled? What profiles are installed?

signalgrid_mdm_status

Is it patched? Are auto-updates on?

signalgrid_software_updates

Are XProtect / MRT malware definitions current?

signalgrid_xprotect_status

What got installed, and when?

signalgrid_install_history

DNS, proxies, VPNs, interfaces

signalgrid_network_posture

What's listening on the network?

signalgrid_listening_services

What persists across reboots? (launchd items)

signalgrid_launch_items

Any third-party kernel extensions?

signalgrid_kernel_extensions

Any stranded/conflicting system extensions?

signalgrid_system_extensions

Who has accounts? Who is admin?

signalgrid_local_users

What apps are installed, and who signed them?

signalgrid_installed_apps

What's running right now?

signalgrid_process_snapshot

Is removable storage (a data-egress channel) connected?

signalgrid_removable_media

Does the device auto-lock when left idle? (walk-up risk)

signalgrid_screen_lock

Is this app properly signed & notarized?

signalgrid_codesign_inspect

Everything above the fold, in one call

signalgrid_posture_report

The SignalGrid decision for this Mac (allow / step-up / restrict / deny)

signalgrid_trust_verdict

The aggregate report is also exposed as an MCP resource at signalgrid://posture. Call signalgrid_posture_report with include_verdict: true to get the raw facts and the folded allow/step-up/restrict/deny decision in one round-trip (the same fail-safe computation as signalgrid_trust_verdict).

Design principles

  • Read-only, always. Every tool carries readOnlyHint: true, destructiveHint: false. No command mutates state.

  • Unknown ≠ off. Posture checks distinguish "the check ran and said X" from "the check could not run" (missing binary, timeout, needs elevation). enabled: null always means unknown — investigate, don't grade.

  • No shell, no injection. Every command is an argv list executed without a shell; user input is never interpolated into a command line.

  • Context-efficient. Large inventories (apps, processes, launch items, install history, listeners) are paginated (limit/offset, standard total/has_more/next_offset envelope), filterable (name_contains), and render as a compact markdown table by default or JSON on request.

  • Degrades gracefully. On a non-macOS host, or when a probe needs elevation, tools return structured error/unknown text — they never crash.

How these signals reach the Grid (sourcing)

SignalGrid's decision fabric classifies every signal by how it is obtained — api (a vendor read API), native (a first-party integration), grid_collected (SignalGrid does the lifting itself), or unavailable (a real gap). This server is the grid_collected path for macOS: SIP, FileVault, Gatekeeper, MDM enrollment, XProtect currency and the rest are facts no cloud API hands you faithfully in real time — you read them on the device.

Every signal here is therefore classified grid_collected at medium fidelity — deliberately not high. The reads are authoritative, but the fabric never over-trusts a signal it had to collect itself, and some probes degrade to unknown without elevation.

The server publishes this mapping so a connecting fabric can discover each signal's provenance, as the MCP resource:

signalgrid://sourcing

It lists every posture-report section → the fabric signal it feeds → its acquisition method and fidelity. tests/test_sourcing.py pins the manifest as a bijection with the report sections, so no section can go un-sourced and no stale entry can linger. (The per-signal descriptions are prose, not checked against collector output.)

Install

Requires Python ≥ 3.10 on the Mac being assessed.

cd signalgrid-mcp
pip install -e .          # or: uv pip install -e .

Run

stdio transport (the server must run on the Mac it is assessing, as a subprocess of the MCP client):

signalgrid-mcp            # console script
# or
python -m signalgrid_mcp.server
# or (back-compat)
python server.py

Claude Desktop / Claude Code config

{
  "mcpServers": {
    "signalgrid": {
      "command": "python3",
      "args": ["/Users/<you>/signalgrid-mcp/server.py"]
    }
  }
}

Inspect interactively

npx @modelcontextprotocol/inspector python3 server.py

Permissions & elevation

The server intentionally runs unelevated. Some probes therefore report null/unknown rather than an answer:

  • profiles list, systemsetup, and some launchctl print system/... targets want root.

  • tmutil latestbackup and the Time Machine preference need Full Disk Access.

  • Unelevated lsof only sees the current user's listeners.

This is by design: an unattended trust agent should not hold root. Treat null as "unresolved signal" and escalate out-of-band if it matters.

Verify (turnkey, on the Mac)

One command sets up, tests, and inspects the live server end to end:

./verify.sh

It creates a venv, installs, runs pytest, then inspects the server over MCP stdio — listing and calling every tool. See RUNBOOK.md for the step-by-step Mac verification, including how to chase down any signal that reads unknown against real macOS output.

Testing

pip install -e ".[dev]"
pytest

The smoke tests run on any OS (they exercise the graceful-degradation paths on Linux CI); the meaningful signal values obviously require macOS. For a Node-free protocol inspection (no browser, no npx):

python tools/inspect_stdio.py          # human-readable
python tools/inspect_stdio.py --json   # machine-readable summary

Layout

signalgrid-mcp/
├── server.py                  # back-compat stdio entry point
├── verify.sh                  # one-command turnkey verify (install + test + inspect)
├── RUNBOOK.md                 # step-by-step Mac verification runbook
├── src/signalgrid_mcp/
│   ├── app.py                 # FastMCP instance + shared annotations
│   ├── runner.py              # subprocess plumbing (run/text/probe/run_json)
│   ├── formatting.py          # pagination, filtering, markdown/JSON rendering
│   ├── sourcing.py            # grid_collected sourcing manifest (signalgrid://sourcing)
│   ├── server.py              # entry point (main)
│   └── tools/                 # one module per signal domain
├── tools/inspect_stdio.py     # Node-free MCP inspector (protocol/read-only/honesty)
├── tests/test_smoke.py
├── tests/test_parsers.py      # parser fixtures pinned against captured output
└── evaluation.xml             # MCP eval suite (read-only Q&A pairs)
-
license - not tested
-
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DanFashauer/signalgrid-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server