<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DeviceShelf</title>
    <description>The latest articles on DEV Community by DeviceShelf (@deviceshelf).</description>
    <link>https://dev.to/deviceshelf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4022828%2F92dc3100-4e93-49c8-b92e-e8436b77eb76.png</url>
      <title>DEV Community: DeviceShelf</title>
      <link>https://dev.to/deviceshelf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/deviceshelf"/>
    <language>en</language>
    <item>
      <title>DeviceShelf for iOS is out of TestFlight and on the App Store</title>
      <dc:creator>DeviceShelf</dc:creator>
      <pubDate>Tue, 21 Jul 2026 15:36:26 +0000</pubDate>
      <link>https://dev.to/deviceshelf/deviceshelf-for-ios-is-out-of-testflight-and-on-the-app-store-20a4</link>
      <guid>https://dev.to/deviceshelf/deviceshelf-for-ios-is-out-of-testflight-and-on-the-app-store-20a4</guid>
      <description>&lt;p&gt;I'm the developer of DeviceShelf, a local-first network scanner for desktop, mobile and a headless server edition. Until this week the iOS app only existed on TestFlight. Apple has now approved version 1.3.0, so for the first time you can get it straight from the App Store: &lt;a href="https://apps.apple.com/app/deviceshelf/id6779666567" rel="noopener noreferrer"&gt;DeviceShelf on the App Store&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the app does on a phone
&lt;/h2&gt;

&lt;p&gt;The iOS app is not a companion viewer. It runs the same scanning engine as the desktop version: it scans the network you're on, identifies devices (vendor, type, OS fingerprint), shows open ports per device, builds a security report, and raises presence alerts when devices appear or drop off. You can export and share results from the phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The multicast entitlement
&lt;/h2&gt;

&lt;p&gt;iOS restricts multicast traffic for ordinary apps, and SSDP/UPnP discovery depends on it. Apple grants the multicast entitlement on request, and DeviceShelf's App Store build has it. In practice, UPnP/SSDP devices show up in scans on the phone the same way they do on desktop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Licensing
&lt;/h2&gt;

&lt;p&gt;The download is free and comes with a trial. Full features unlock in one of two ways: activate a DeviceShelf license, which covers desktop, mobile and the server edition with a single purchase, or use the in-app purchase upgrade on iOS. Pricing is on the website if you want the details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local-first, on mobile too
&lt;/h2&gt;

&lt;p&gt;Scans stay on the device. There is no cloud account, and the AI-assisted device identification is bring-your-own-key; no key is bundled or required.&lt;/p&gt;

&lt;p&gt;The app is still young, and a phone is an unforgiving place for a network scanner. If it mislabels a device on your network or misses one entirely, I'd genuinely like to hear about it.&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://deviceshelf.app" rel="noopener noreferrer"&gt;deviceshelf.app&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>networking</category>
      <category>mobile</category>
      <category>indiedev</category>
    </item>
    <item>
      <title>Wiring a local network scanner into an AI assistant with MCP</title>
      <dc:creator>DeviceShelf</dc:creator>
      <pubDate>Tue, 14 Jul 2026 20:00:19 +0000</pubDate>
      <link>https://dev.to/deviceshelf/wiring-a-local-network-scanner-into-an-ai-assistant-with-mcp-45o0</link>
      <guid>https://dev.to/deviceshelf/wiring-a-local-network-scanner-into-an-ai-assistant-with-mcp-45o0</guid>
      <description>&lt;p&gt;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 &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; (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?"&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the endpoint exposes
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything stays on your LAN
&lt;/h2&gt;

&lt;p&gt;The MCP endpoint runs &lt;em&gt;inside&lt;/em&gt; 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 &lt;em&gt;you&lt;/em&gt; 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  The read side
&lt;/h2&gt;

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

&lt;p&gt;Monitoring adds &lt;code&gt;list_changes&lt;/code&gt;, &lt;code&gt;list_alarms&lt;/code&gt;, &lt;code&gt;list_checks&lt;/code&gt;, &lt;code&gt;get_device_history&lt;/code&gt;, &lt;code&gt;get_device_uptime&lt;/code&gt; (per-device uptime over up to 90 days) and &lt;code&gt;list_offline_devices&lt;/code&gt;. Security is one call: &lt;code&gt;security_overview&lt;/code&gt; 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 &lt;code&gt;list_snapshots&lt;/code&gt; / &lt;code&gt;diff_snapshots&lt;/code&gt; compare two named captures, or a capture against the live scan, so "what's new since the audit in May?" becomes a single question.&lt;/p&gt;

&lt;h2&gt;
  
  
  The write side is opt-in, twice
&lt;/h2&gt;

&lt;p&gt;Writes are off by default. You turn them on with a second, separate switch (&lt;code&gt;DEVICESHELF_MCP_ALLOW_ACTIONS=true&lt;/code&gt;), 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 (&lt;code&gt;scan_now&lt;/code&gt;, &lt;code&gt;port_check&lt;/code&gt;) are restricted to your own locally-attached subnets and rate-limited.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Prompts and resources
&lt;/h2&gt;

&lt;p&gt;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 (&lt;code&gt;deviceshelf://network/summary&lt;/code&gt;, &lt;code&gt;deviceshelf://devices&lt;/code&gt;, &lt;code&gt;deviceshelf://alarms&lt;/code&gt;, &lt;code&gt;deviceshelf://security/overview&lt;/code&gt;) a client can attach as context without any tool call at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live mode
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Treating it as a security surface
&lt;/h2&gt;

&lt;p&gt;An AI reading your inventory gets the same scrutiny as any other client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/mcp&lt;/code&gt; is auth-required, exactly like the API. No token, no answer.&lt;/li&gt;
&lt;li&gt;A scoped token (&lt;code&gt;DEVICESHELF_MCP_TOKEN&lt;/code&gt;) is accepted for &lt;code&gt;/mcp&lt;/code&gt; only, never for the admin API or metrics, so the AI client never holds an admin credential.&lt;/li&gt;
&lt;li&gt;All tool calls are rate-limited (token bucket, default 300/min) and audit-logged by tool name and outcome, never by arguments.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;Origin&lt;/code&gt; allowlist guards against DNS rebinding from a browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning it on
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;/etc/deviceshelf/server.env&lt;/code&gt; (or your Docker environment):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DEVICESHELF_MCP_ENABLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the server. The endpoint is served at &lt;code&gt;http://&amp;lt;your-server&amp;gt;:8088/mcp&lt;/code&gt; with the bearer token. To connect Claude Desktop, bridge to it with &lt;a href="https://www.npmjs.com/package/mcp-remote" rel="noopener noreferrer"&gt;&lt;code&gt;mcp-remote&lt;/code&gt;&lt;/a&gt;. Keep &lt;code&gt;--allow-http&lt;/code&gt; (it's plain http on your LAN) and pass the token via an env var, which sidesteps a Windows argument-quoting bug:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deviceshelf"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcp-remote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://&amp;lt;your-server&amp;gt;:8088/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="s2"&gt;"--transport"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http-only"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--allow-http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="s2"&gt;"--header"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Authorization:${AUTH}"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"AUTH"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer &amp;lt;your-token&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Where it stands
&lt;/h2&gt;

&lt;p&gt;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 &lt;code&gt;402&lt;/code&gt; 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 &lt;a href="https://deviceshelf.app" rel="noopener noreferrer"&gt;https://deviceshelf.app&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>networking</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>What a local network scanner actually knows about your devices</title>
      <dc:creator>DeviceShelf</dc:creator>
      <pubDate>Sun, 12 Jul 2026 15:08:23 +0000</pubDate>
      <link>https://dev.to/deviceshelf/what-a-local-network-scanner-actually-knows-about-your-devices-2lkf</link>
      <guid>https://dev.to/deviceshelf/what-a-local-network-scanner-actually-knows-about-your-devices-2lkf</guid>
      <description>&lt;p&gt;I build DeviceShelf, a local-first network scanner, so I spend a lot of time staring at the question "what is this thing on my LAN?" Turns out there's no single answer. A scanner guesses, using a handful of weak signals that each get one part of the picture right and one part wrong. This post walks through those signals and where each one lies to you.&lt;/p&gt;

&lt;p&gt;Nothing here is specific to my tool. Any scanner works from roughly the same inputs, so this is meant to be useful whether you ever open DeviceShelf or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MAC address and the vendor behind it
&lt;/h2&gt;

&lt;p&gt;Every device on a local network has a MAC address, and the first three bytes are the OUI, the block assigned to a hardware vendor. Look that prefix up against the IEEE registry and you get a name: Apple, Ubiquiti, Espressif, Raspberry Pi Foundation. That one lookup is the cheapest and most reliable identifier you have. It's also the first one to fall apart.&lt;/p&gt;

&lt;p&gt;Modern phones rotate their MAC per network to stop being tracked, so the vendor you see is a placeholder, not Apple or Samsung. Some cheap gear ships with a MAC from whatever reference-design chip is inside, so a smart plug reports as the Wi-Fi module maker rather than the brand on the box. And anyone can set a MAC to anything. A spoofed address means the OUI is simply a lie you can't detect from the outside. So: good for a first pass, wrong often enough that you can't stop there.&lt;/p&gt;

&lt;h2&gt;
  
  
  mDNS and Bonjour
&lt;/h2&gt;

&lt;p&gt;Many devices announce themselves over multicast DNS. Printers, Apple gear, Chromecasts, a surprising number of IoT boxes. Ask the right multicast group and they'll tell you their hostname, service types, and sometimes a friendly model string. When a device participates, mDNS is the richest source you get for free, because the device is describing itself in its own words.&lt;/p&gt;

&lt;p&gt;The catch is participation. A locked-down sensor or a random Linux box says nothing, and silence reads the same as absence. You also can't trust the self-reported name too far, since a user can rename a device to whatever they like, and some vendors put marketing text where a model number should be.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSDP and UPnP
&lt;/h2&gt;

&lt;p&gt;SSDP is the discovery half of UPnP, and it's how routers, media servers, smart TVs and game consoles advertise themselves. A scanner sends a multicast search, listens for responses, then fetches the device description XML each responder points at. That XML often carries a manufacturer, model name and model number straight from the firmware, which is more structured than a hostname.&lt;/p&gt;

&lt;p&gt;UPnP has a reputation, mostly earned, for being chatty and inconsistent between vendors. Descriptions can be sparse, fields get left blank, and plenty of security-conscious setups disable it entirely. When it answers it's genuinely useful. You just can't count on it answering.&lt;/p&gt;

&lt;h2&gt;
  
  
  DHCP fingerprinting
&lt;/h2&gt;

&lt;p&gt;When a device asks the network for an address, its DHCP request carries a fingerprint: the specific options it requests, in a specific order, plus fields like the vendor class identifier. Different operating systems and stacks produce recognizably different requests, so with a decent signature database you can often tell Android from an IoT RTOS from a desktop OS without the device volunteering anything.&lt;/p&gt;

&lt;p&gt;Two honest limitations. You only see the request if you happen to be listening when the device renews its lease, which on a passive scan you usually aren't. And fingerprints drift as OS versions change, so a signature set goes stale and starts producing confident, wrong answers. It's a strong hint about device class, not proof of identity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open ports as a hint, not a verdict
&lt;/h2&gt;

&lt;p&gt;What a device exposes says something about what it is. Port 9100 leans printer. 554 suggests a camera speaking RTSP. 445 points at a Windows or SMB host, 22 at something with SSH. Stack a few of these together and a rough device type appears.&lt;/p&gt;

&lt;p&gt;I treat this as the softest signal of the set. A port tells you a service might be running, not what the box is for, and homelabbers run services on hardware that has nothing to do with the service's usual home. Aggressive probing also annoys fragile devices, so a scanner has to stay gentle, which means less data and more uncertainty. Useful for corroboration, weak on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional AI identification, with your own key
&lt;/h2&gt;

&lt;p&gt;When the mechanical signals disagree or come up thin, there's room for a model to weigh the messy evidence, the odd hostname, the vendor guess, the port pattern, the way a human would. DeviceShelf can do this, and it's strictly opt-in: you bring your own API key, nothing is bundled, and it does nothing unless you turn it on. Local-first means the default is that nothing about your network leaves your machine.&lt;/p&gt;

&lt;p&gt;Being blunt about it, an AI guess is still a guess. It can be confidently wrong, it depends entirely on the quality of the signals underneath, and it's an assist, not an oracle. I'd rather it be honestly uncertain than smoothly incorrect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why identification is a best guess
&lt;/h2&gt;

&lt;p&gt;Every signal here is partial. MACs get randomized and spoofed, half your devices stay silent, DHCP and port data show up late or not at all, and a good scanner combines the weak signals into something better than any one of them without pretending the result is certain. That's the honest frame: a network scanner narrows down what a device probably is, and tells you how sure it isn't.&lt;/p&gt;

&lt;p&gt;DeviceShelf is a young project and I'm still improving how it fuses these signals. If it mislabels something on your network, or misses a device you can see with your own eyes, I'd genuinely like to hear about it. That kind of report is what makes the next version better. You can find it at &lt;a href="https://deviceshelf.app" rel="noopener noreferrer"&gt;https://deviceshelf.app&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>privacy</category>
      <category>selfhosted</category>
      <category>go</category>
    </item>
    <item>
      <title>Building a local-first network scanner in Go, Wails and Flutter</title>
      <dc:creator>DeviceShelf</dc:creator>
      <pubDate>Thu, 09 Jul 2026 13:34:48 +0000</pubDate>
      <link>https://dev.to/deviceshelf/building-a-local-first-network-scanner-in-go-wails-and-flutter-4f87</link>
      <guid>https://dev.to/deviceshelf/building-a-local-first-network-scanner-in-go-wails-and-flutter-4f87</guid>
      <description>&lt;p&gt;Most network scanners I tried wanted a cloud account and a subscription just to tell me what was sitting on my own LAN. That bugged me enough to build the opposite: a scanner that runs on your machine, keeps the data there, and still tells you what every device is. It's called DeviceShelf, and this is a short tour of how it's put together.&lt;/p&gt;

&lt;h2&gt;
  
  
  One core, three front-ends
&lt;/h2&gt;

&lt;p&gt;The scanning and analysis live in a Go core: ARP/ping sweep, port checks, service probes, DHCP fingerprinting, SNMP, and the device-identification logic. On the desktop that core is wrapped with &lt;a href="https://wails.io" rel="noopener noreferrer"&gt;Wails&lt;/a&gt; — Go on the backend, a normal web UI on the front — so the same engine ships on macOS, Windows and Linux without three native rewrites. The mobile apps are Flutter, talking to the same concepts (a chunk of the identification logic is mirrored and unit-tested on both sides so behaviour matches). And there's a headless build of the core for a 24/7 server edition with no GUI at all.&lt;/p&gt;

&lt;p&gt;Keeping one engine and swapping the shell is the only reason a solo project can cover desktop, mobile and server without drowning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local-first, and meaning it
&lt;/h2&gt;

&lt;p&gt;"Local-first" is easy to put on a landing page and easy to quietly break. The rule here is simple: nothing about your network leaves the machine unless you switch something on. Device identification runs locally; the online fingerprint lookup is opt-in and off by default. If you want AI to help name a weird device, that's there too — but you bring your own key, so the calls are yours, not routed through a server I run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The parts that were actually hard
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identification.&lt;/strong&gt; Turning a MAC prefix, open ports, a DHCP fingerprint and an SNMP sysName into "this is a printer" is a pile of heuristics with sharp edges — a Nintendo Switch that looks like a network switch, say. It's ordered rules, not one magic classifier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live bandwidth.&lt;/strong&gt; Per-device throughput means packet capture (Npcap on Windows, BPF on macOS), which is platform- and permission-dependent and needs care to stay light.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The server edition.&lt;/strong&gt; Running unattended on a LAN changes everything: alert routing over ntfy/Gotify/webhook, threshold and dependency checks, and taming alert floods so it doesn't page you at 3am because Wi-Fi hiccuped.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where it is now
&lt;/h2&gt;

&lt;p&gt;Desktop and mobile are shipping; the server edition is an honest public beta. If you want to see what's on your own network without signing up for anything, that's the whole point.&lt;/p&gt;

&lt;p&gt;Full write-ups and release notes: &lt;a href="https://deviceshelf.app/blog" rel="noopener noreferrer"&gt;https://deviceshelf.app/blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>flutter</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
