DEV Community

DeviceShelf
DeviceShelf

Posted on • Originally published at deviceshelf.app

Wiring a local network scanner into an AI assistant with MCP

I build DeviceShelf, a local-first network scanner. Its Server edition is the headless, always-on one, and as of build 1.5.3 it speaks the Model Context Protocol (MCP). That means an assistant like Claude Desktop can answer questions about your network from your own live data: "what's online right now?", "anything new or offline since yesterday?", "which devices have certificates expiring soon?", "how does tonight differ from last week's snapshot?"

This post is about how that's wired, and more to the point how it's fenced in, because handing a language model a read of your network inventory is the sort of thing that deserves some paranoia. I'm the developer, so take the enthusiasm with the usual pinch of salt; the design choices below are the interesting part.

What the endpoint exposes

All told it's 22 tools (14 read-only, 8 opt-in actions), 3 guided prompts, 4 attachable resources, and an optional live mode that pushes changes to the client as they happen. MCP is the glue: the assistant discovers those tools and calls them, instead of you copy-pasting dashboard output into a chat window.

Everything stays on your LAN

The MCP endpoint runs inside the DeviceShelf Server, on the same port as the API, behind a bearer token, reachable only on your LAN. There's no DeviceShelf cloud connector and no remote OAuth. The only thing that ever leaves your network is whatever the AI client you chose to connect decides to send. It reads the same in-process data that backs the dashboard, so the model's view can't drift from what you see with your own eyes.

The read side

The 14 read tools cover the whole monitoring surface. Inventory is network_summary for the one-shot overview, list_devices with filters and pagination, find_device for free-text lookups ("the printer", "my NAS"), get_device for full per-host detail (open ports, OS, SNMP, TLS, matched CVEs, notes), and list_interfaces for multi-NIC collectors.

Monitoring adds list_changes, list_alarms, list_checks, get_device_history, get_device_uptime (per-device uptime over up to 90 days) and list_offline_devices. Security is one call: security_overview surfaces expiring and expired certificates, self-signed certs, and hosts with known CVEs grouped by severity, across the whole network without a lookup per host. And list_snapshots / diff_snapshots compare two named captures, or a capture against the live scan, so "what's new since the audit in May?" becomes a single question.

The write side is opt-in, twice

Writes are off by default. You turn them on with a second, separate switch (DEVICESHELF_MCP_ALLOW_ACTIONS=true), and only then does the assistant get action tools: rename or retag a device, acknowledge an alarm, create or delete monitor checks in plain language, save a named snapshot, trigger an on-demand scan or a TCP port check, or fire a test notification. The probing actions (scan_now, port_check) are restricted to your own locally-attached subnets and rate-limited.

If even that feels too loose, DEVICESHELF_MCP_CONFIRM_ACTIONS=true makes the impactful actions ask the client for a yes first, using MCP elicitation, so a scan never runs without you clicking confirm.

Prompts and resources

For people who don't want to learn tool names, the server ships three guided prompts that show up in the client's prompt picker: a security audit, a "what changed recently" report, and "identify unknown devices". One click, useful answer. It also exposes four read-only resources (deviceshelf://network/summary, deviceshelf://devices, deviceshelf://alarms, deviceshelf://security/overview) a client can attach as context without any tool call at all.

Live mode

By default the endpoint is stateless request/response. Set DEVICESHELF_MCP_LIVE=true and it switches to stateful sessions: clients can subscribe to the device, alarm and summary resources and receive resources/updated notifications when the inventory changes, so the assistant stays current without polling. Idle sessions close after 30 minutes.

Treating it as a security surface

An AI reading your inventory gets the same scrutiny as any other client:

  • /mcp is auth-required, exactly like the API. No token, no answer.
  • A scoped token (DEVICESHELF_MCP_TOKEN) is accepted for /mcp only, never for the admin API or metrics, so the AI client never holds an admin credential.
  • All tool calls are rate-limited (token bucket, default 300/min) and audit-logged by tool name and outcome, never by arguments.
  • Device-reported strings (hostnames, banners, cert subjects) are untrusted input: control and text-spoofing characters (bidi, zero-width) are stripped and values truncated before they reach the model, and the model is told to treat them as data.
  • An Origin allowlist guards against DNS rebinding from a browser.

That last group is the reason I'd trust this on my own network. Prompt-injection through a hostname a rogue device set to something clever is a real risk, and stripping the spoofing characters plus flagging the strings as data is the boring, correct answer.

Turning it on

In /etc/deviceshelf/server.env (or your Docker environment):

DEVICESHELF_MCP_ENABLE=true
Enter fullscreen mode Exit fullscreen mode

Restart the server. The endpoint is served at http://<your-server>:8088/mcp with the bearer token. To connect Claude Desktop, bridge to it with mcp-remote. Keep --allow-http (it's plain http on your LAN) and pass the token via an env var, which sidesteps a Windows argument-quoting bug:

{
  "mcpServers": {
    "deviceshelf": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://<your-server>:8088/mcp",
               "--transport", "http-only", "--allow-http",
               "--header", "Authorization:${AUTH}"],
      "env": { "AUTH": "Bearer <your-token>" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Any MCP client that speaks Streamable HTTP can connect directly. It's available from deviceshelf-server 1.5.3 (Docker image ghcr.io/wealthwallet/deviceshelf-server:1.5.3, .deb, or later), off by default and fully additive, so existing servers are untouched until you set DEVICESHELF_MCP_ENABLE.

Where it stands

MCP is part of the Server edition rather than a separate purchase, and it works during the 7-day trial so you can evaluate it; the endpoint returns 402 once an unlicensed trial expires. The Server edition itself is still public beta, so treat it as early, and if a tool returns something wrong or a check behaves oddly I'd genuinely like the report. The full write-up with the client configs (Cursor, VS Code, Windsurf, Cline, Gemini CLI) is on the DeviceShelf blog, and the project lives at https://deviceshelf.app.

Top comments (2)

Collapse
 
topstar_ai profile image
Luis

I appreciate how you've implemented the MCP endpoint within DeviceShelf Server, ensuring that all data remains on the local LAN and only the chosen AI client can access it. The separation of read and write tools, with write actions being opt-in, is a thoughtful design choice, especially with the added layer of confirmation for impactful actions. The guided prompts and attachable resources also seem like a convenient way to simplify interactions for users who don't want to learn the intricacies of the tool names. Have you considered adding any additional security measures, such as encryption for the data in transit between the DeviceShelf Server and the AI client, or do you think the existing bearer token and LAN-only approach provide sufficient protection?

Collapse
 
mads_hansen_27b33ebfee4c9 profile image
Mads Hansen

This is a great example of where MCP needs very explicit safety boundaries.

A local network scanner sounds harmless until the assistant can turn “what is on my network?” into repeated probing, broad CIDR scans, or actions against devices the user did not intend to include.

The design details I’d care about:

  • require an explicit target range
  • default to read-only discovery
  • rate-limit scans aggressively
  • show the exact command or probe plan
  • separate discovery from mutation/remediation tools
  • log every scan request and result
  • make private/public network assumptions visible

MCP is useful here because it can make the tool contract clear. But the contract needs to be narrower than “agent can scan network.”