Let an AI agent run DedNets
DedNets ships an MCP server: point an AI coding agent at it and the agent
can enroll a machine, publish a service at a public HTTPS URL, and wire up a
watchdog, using the same API you would. It runs locally, out of the
dednetsctl binary, and talks only to your Console with a token you mint and
can revoke. (Since v0.4.1.)
The one-line install
Section titled “The one-line install”(Since v0.4.3. macOS and Linux.) One command does everything on this page:
curl -fsSL https://dednets.com/install-cli.sh | shIt installs dednetsctl (sha256-verified against what your Console publishes),
remembers your Console, offers to put it on your PATH, turns on a daily
background update check, asks for an API token, and configures the AI agent hosts
it finds - Claude Code (plugin plus marketplace auto-update) and Claude Desktop.
Restart your agent afterwards and ask it to “list my DedNets hosts”.
Point it at a self-hosted Console, or answer nothing at all:
curl -fsSL https://dednets.com/install-cli.sh | sh -s -- --console https://console.example.comcurl -fsSL https://dednets.com/install-cli.sh | sh -s -- --yes --token dak_your_token_hereIt is safe to re-run, and it is the fastest way to check a setup: every step
reports ok, changed or skipped, and a step that is already correct writes
nothing.
1. Console ok https://console.dednets.com (publishes 0.4.3)2. PATH ok ~/.local/bin is on PATH3. auto-update ok on (checked once a day; DEDNETS_NO_UPDATE_CHECK disables it)4. login ok already logged in to https://console.dednets.com5. agent hosts ok Claude Code ok plugin dednets@dednets installed, marketplace auto-update on Claude Desktop ok MCP server "dednets" -> ~/.local/bin/dednetsctlPrefer to do it yourself, or on Windows? The manual steps are below and are not
going away. If you already have the CLI, dednetsctl setup runs the same wizard
without the download.
Enrolling a host (a server that exports apps) is a different, separate
command that the Console’s “Connect a host” wizard mints for you. Do not confuse
https://dednets.com/install-cli.sh (your workstation) with your Console’s
/install.sh (a host).
1. Get the server
Section titled “1. Get the server”The MCP server is a subcommand of dednetsctl. Let npx fetch it for you,
download the CLI yourself, or install it with Homebrew.
Using Claude Code? Install the plugin in step 3 and skip this step entirely: it brings its own binary resolution.
| You want | Use | Because |
|---|---|---|
| One command, everything wired up | curl … install-cli.sh | sh (above) |
installs the CLI, logs you in, configures your agent hosts, keeps itself updated |
| Nothing installed system-wide | npx -y @dednets/mcp (Option A) |
follows your Console automatically, verified by sha256 |
A real, upgradable CLI on your PATH |
brew install dednets/tap/dednetsctl (Option C) |
one command, brew upgrade later; pinned to a version you choose |
| No Node and no Homebrew, or Windows | curl from /dist (Option B) |
works anywhere, and you manage upgrades |
Option A: npx, with nothing to install
Section titled “Option A: npx, with nothing to install”(Since v0.4.1. Needs Node 20.9 or newer, and a Console publishing v0.4.1 or newer.)
npx -y @dednets/mcp --probe-onlyThat downloads dednetsctl from your Console (DEDNETS_CONSOLE, default
https://console.dednets.com), checks it against the sha256 that Console
publishes, caches it under ~/.cache/dednets (%LOCALAPPDATA%\dednets\cache on
Windows) and exits without starting anything. Nothing is installed
system-wide, and the CLI always follows the Console you point at, including a
self-hosted one.
Run it once before wiring up an agent so the first session does not wait for the
download. Then use the npx configuration in step 3.
If it prints dednets mcp failed: console_too_old, that Console has not been
upgraded to v0.4.1 yet; use Option B against it, or ask whoever operates it to
upgrade.
Claude Code users should prefer the plugin (step 3) and can skip this step.
Option B: download the CLI
Section titled “Option B: download the CLI”Download it from your Console and put it on your PATH:
# macOS (Apple Silicon)curl -fsSLo dednetsctl https://console.dednets.com/dist/darwin-arm64/dednetsctl# macOS (Intel): .../dist/darwin-amd64/dednetsctl# Linux: .../dist/linux-arm64/dednetsctl or .../dist/linux-amd64/dednetsctlchmod +x dednetsctl && sudo mv dednetsctl /usr/local/bin/dednetsctl mcp -h # prints the flags; nothing is startedOn Windows, in PowerShell (curl there is an alias for Invoke-WebRequest
and takes different arguments, so call it by its real name):
$dir = "$env:LOCALAPPDATA\DedNets"New-Item -ItemType Directory -Force -Path $dir | Out-NullInvoke-WebRequest -Uri https://console.dednets.com/dist/windows-amd64/dednetsctl.exe ` -OutFile "$dir\dednetsctl.exe"& "$dir\dednetsctl.exe" mcp -hThe CLI is called dednetsctl since v0.4.1 (it was dedmeshctl). There is no
alias, and the old /dist/<platform>/dedmeshctl URLs no longer resolve, so
re-download it with the command above if you still have the old binary.
Builds are published for macOS (Apple Silicon and Intel), Linux (amd64,
arm64) and Windows (amd64, as dednetsctl.exe). (Windows and Intel-Mac
builds since v0.4.1.) Windows gets the CLI, not the host agent: a Windows
machine can drive your DedNets account, and the hosts you enroll still run
Linux or macOS.
The Windows build is cross-compiled and unit-tested, and has not been run on a
Windows machine by us. mcp itself is the portable part of the CLI: it writes
no files, opens no unix sockets and reads no config directory. Two areas are
built but unverified there: the mTLS client-identity commands (login,
client enroll, attach) write their key and certificate with POSIX file
modes Windows ignores, and attach never puts the console into raw or
virtual-terminal input mode, so interactive use would be line-buffered and
locally echoed. Colored output (view) needs Windows Terminal or PowerShell
7; legacy conhost.exe shows the escape codes literally.
Option C: Homebrew (macOS and Linux)
Section titled “Option C: Homebrew (macOS and Linux)”(Since v0.4.1.)
brew install dednets/tap/dednetsctldednetsctl mcp -h # prints the flags; nothing is startedThe formula covers macOS (Apple Silicon and Intel) and Linux (arm64 and amd64), and installs a single binary. There is no Homebrew formula for Windows: use Option B there.
A Homebrew install pins one CLI version, the one the formula was cut from,
and brew upgrade dednetsctl moves it. That is the difference from Option A,
where the CLI follows whichever Console you point at. Against an older
self-hosted Console a pinned CLI is exactly the case the version-skew warning
below is for, so expect it and read it rather than filing it as a bug.
2. Mint a scoped token
Section titled “2. Mint a scoped token”In the Console, go to Settings > API
tokens > Create token. Name it
after the agent (claude-code), tick the scopes you want it to have, and copy
the dak_… secret: it is shown exactly once.
(The one-line installer above asks for this token and stores it for you, so if you took that path you only need this page open to create it.)
For the full onboarding journey below, tick Read-only, Manage hosts, Manage services and Manage watchdogs. Add Signals if you want the agent to close or report signals. For a token that can only look, tick just Read-only. What each scope unlocks: API tokens and scopes.
The agent holds this token. Give it the least you need, and revoke it from the same page when you are done.
3. Connect your agent
Section titled “3. Connect your agent”Claude Code
Section titled “Claude Code”Plugin (recommended)
Section titled “Plugin (recommended)”(Since v0.4.1. macOS and Linux; on Windows use the manual configuration below.)
# 1. tell Claude Code where your Console is, and store your tokenexport DEDNETS_CONSOLE=https://console.dednets.com # omit if you use the hosted Consoledednetsctl login # Console > Settings > API tokens
# 2. install the pluginclaude plugin marketplace add dednets/dednets-claude-pluginclaude plugin install dednets@dednets(dednetsctl login is since v0.4.3. On older versions, or if you prefer,
export DEDNETS_TOKEN=dak_... instead.)
Prefer login over exporting DEDNETS_TOKEN here. The plugin’s MCP server
inherits the environment of the app that launches it, so if you start Claude
Code from the Dock or Spotlight rather than a terminal, it never sees anything
you exported in your shell profile, and every DedNets tool fails as
unauthorized. The stored token does not depend on how you launch the app.
DEDNETS_TOKEN still takes priority whenever it is set.
The plugin finds the CLI for you, in this order: $DEDNETSCTL, then dednetsctl
on your PATH. It also brings a skill that walks the parts the MCP tools cannot
do themselves, such as running an enroll command on the machine being enrolled.
Both variables are read when Claude Code starts, so restart it after changing
either one. /mcp then lists dednets.
The Console’s Use with AI button links straight back to this page, so you can start from either end. (Since v0.13.7 the Console links here instead of repeating the install blocks; between v0.4.1 and v0.13.6 it showed its own copy of them with your Console’s URL filled in.)
With npx instead of an installed CLI
Section titled “With npx instead of an installed CLI”(Since v0.4.1.) If you took Option A in step 1, name npx as the command and
skip the binary entirely:
{ "mcpServers": { "dednets": { "command": "npx", "args": ["-y", "@dednets/mcp"], "env": { "DEDNETS_CONSOLE": "https://console.dednets.com", "DEDNETS_TOKEN": "dak_your_token_here" } } }}Add "-read-only" to args after the package name for a look-but-do-not-touch
server.
Manual configuration
Section titled “Manual configuration”Create .mcp.json in the project you work from:
{ "mcpServers": { "dednets": { "command": "dednetsctl", "args": ["mcp"], "env": { "DEDNETS_CONSOLE": "https://console.dednets.com", "DEDNETS_TOKEN": "dak_your_token_here" } } }}Or add it from the command line:
claude mcp add dednets \ --env DEDNETS_CONSOLE=https://console.dednets.com \ --env DEDNETS_TOKEN=dak_your_token_here \ -- dednetsctl mcpThen /mcp inside Claude Code should list dednets as connected.
Claude Desktop
Section titled “Claude Desktop”The same block goes in the app’s config file, which differs per OS. Claude
Desktop does not inherit your shell PATH, so give the absolute command
path in both cases, and restart the app after editing the file. That applies to
npx too: use the output of which npx (often /usr/local/bin/npx or a path
under ~/.nvm/) rather than the bare word. (Since v0.4.1.)
macOS and Linux
Section titled “macOS and Linux”~/Library/Application Support/Claude/claude_desktop_config.json:
{ "mcpServers": { "dednets": { "command": "/usr/local/bin/dednetsctl", "args": ["mcp"], "env": { "DEDNETS_CONSOLE": "https://console.dednets.com", "DEDNETS_TOKEN": "dak_your_token_here" } } }}Windows
Section titled “Windows”%APPDATA%\Claude\claude_desktop_config.json. Give the expanded absolute path
to the .exe (the config file is not a shell: environment variables such as
%LOCALAPPDATA% are not expanded inside it), and remember that JSON needs
every backslash doubled. (Since v0.4.1.)
{ "mcpServers": { "dednets": { "command": "C:\\Users\\you\\AppData\\Local\\DedNets\\dednetsctl.exe", "args": ["mcp"], "env": { "DEDNETS_CONSOLE": "https://console.dednets.com", "DEDNETS_TOKEN": "dak_your_token_here" } } }}Any other MCP client
Section titled “Any other MCP client”| Setting | Value |
|---|---|
| Transport | stdio |
| Command | dednetsctl, or dednetsctl.exe on Windows (absolute path if the client does not use your PATH) |
| Args | ["mcp"], or ["mcp", "-read-only"] to publish only the read tools |
| Env | DEDNETS_CONSOLE (your Console base URL), DEDNETS_TOKEN (your dak_… token) |
With npx instead, the command is npx and the args are ["-y", "@dednets/mcp"]
(add "-read-only" after that for the read tools only). The environment is the
same. (Since v0.4.1.)
4. Check it works
Section titled “4. Check it works”Ask the agent: “list my DedNets hosts”. It should call host_list and answer
with your fleet. If it says it has no such tool, see
Troubleshooting.
5. What the agent can do
Section titled “5. What the agent can do”| Ask for | It does | Needs scope |
|---|---|---|
| “add this machine to my network” | enrolls a host, then hands you the exact install command to run on it | Manage hosts |
| “which of my hosts are online?” | lists the fleet with versions and status | Read-only |
| “give this container a public HTTPS URL” | publishes an app and returns the https://… address |
Manage services |
| “open port 25565 for my game server” | a raw public port, or a port on your own gateway host | Manage services |
| “publish my dashboard but only let me and bob see it” | publishes it behind a DedNets login and adds bob to its access list; everyone else is stopped at the edge (since v0.10.0) | Manage services |
| “revoke bob’s access to that dashboard” | removes him from the access list, effective on his next click (since v0.10.0) | Manage services |
| “let host A reach host B’s database” | a proxy port; nothing becomes public | Manage services |
| “put my Proxmox console on pve.lab.example.com” | a reverse proxy host on one of your gateways: turns the host’s reverse proxy on if you ask it to, points a hostname under your wildcard at an https://192.168.…:8006 upstream on that host’s own network, with HTTPS from the gateway and an optional DedNets login in front (since v0.14.0) |
Manage hosts for the switch, Manage services for the proxy host |
| “serve my app on blog.example.com” | records your domain, hands you the DNS records to create, verifies it, then points the hostname at the app (since v0.4.5; owning the name and publishing on it are two steps since v0.7.0, and the agent can do both since v0.9.1) | Manage services |
| “give every CI branch its own hostname under lab.example.com” | records the wildcard *.lab.example.com, hands you the two DNS records, and verifies it once. After that the agent points any label at any app on its own - pr-1234.lab.example.com needs no new record, no new claim, no new verification and no certificate step (the first HTTPS request issues it) (wildcards since v0.6.0; the agent can publish a label since v0.9.1) |
Manage services |
| “move api.lab.example.com to the new service” / “take that hostname down” | re-points one hostname in place, or stops it serving while leaving the domain and every other hostname alone (since v0.9.1) | Manage services |
| “take blog.example.com down” | removes the custom domain and every hostname bound to it, after you confirm (since v0.4.5) | Manage services |
| “is my service healthy?” | status, uptime and health-check state for one target | Read-only |
| “alert me if my nightly backup stops running” | creates a watchdog and gives you the cron wiring | Manage watchdogs |
| “why did my watchdog alert last night?” | recent transitions, uptime buckets, likely causes | Read-only |
| “what is currently wrong?” | lists open signals: one record per condition, with how many times each has been reported (since v0.9.0) | Read-only |
| “show me the details of the SSH brute-force signal” | that signal in full, with the payload the reporting script sent and its history of state changes | Read-only |
| “the disk issue is fixed, close it” | resolves the signal. This is reversible: if the condition returns, the same key reopens the same record | Signals |
| “report a test condition so I can check the wiring” | posts a real occurrence, which can reach your phone. Ask for a throwaway key you can delete afterwards | Signals |
Ready-made workflows (slash commands)
Section titled “Ready-made workflows (slash commands)”The server also ships whole workflows as MCP prompts. In Claude Code they
appear as slash commands after / (type /dednets to filter); other clients
list them in a prompt picker. Each one is a checklist the agent follows, and
each takes optional arguments. (Since v0.4.1.)
| Command | Does | Arguments |
|---|---|---|
/dednets:onboard_host |
enrolls a machine and waits for it to come online | host, flavor |
/dednets:review_fleet |
read-only review of every host and what it serves | kind |
/dednets:publish_app |
exports a service and hands back the public address | app, host, proto |
/dednets:remove_host |
shows what breaks, then revokes after you confirm | host |
/dednets:troubleshoot_watchdog |
reads a monitor’s history and names likely causes | watchdog, range |
Arguments are optional: run the command with none and it asks you for what it
needs. With -read-only only review_fleet and troubleshoot_watchdog are
offered, because the others need a tool that changes something.
Prefer starting from the Console? Three pages carry a Use with AI button that names the scopes your token needs, links back to this guide for the install, and lists the ready-made prompts for that page - the same text these slash commands use, so you can copy one straight into your agent:
| Console page | Prompts it offers |
|---|---|
| Hosts | add, review, and remove hosts (since v0.4.1) |
| Services | publish an app at a public URL (since v0.4.3) |
| Watchdogs | troubleshoot a watchdog, read-only (since v0.4.3) |
Each dialog also links back to the guide for what that page does, so you can go either way between the Console and these docs.
The agent cannot mint or revoke API tokens, change your account, or touch anyone else’s resources, whatever you ask it for.
6. A worked example
Section titled “6. A worked example”This is a real run, not an illustration. The prompt was “deploy this machine as a new mesh host, run an HTTP service on it, expose it at a public URL, and configure a watchdog for it”, given to an agent that had the DedNets tools and a shell on a fresh Linux VM, and nothing else. What it did:
- Enrolled the host. It asked for the
systemdinstall flavor (the only one since v0.12.0) and got a one-time join token plus a ready-to-run command. - Ran the install command on the machine itself, over its shell. This is the step the agent cannot do on your behalf without access: it needs a shell on the target machine, or you paste the command yourself.
- Waited for the host to come online, checking the fleet.
- Started a small HTTP service on
127.0.0.1:8080as a systemd unit, then published it as appdemowithproto: httpandpublic: true. That returned anhttps://demo-<username>.<domain>address which answered200end to end. - Created a watchdog (5 minute period, 60 second grace) and wired a cron
entry that pings start, runs the check, then pings success or fail. The
watchdog read
upon the next ping.
It took about 50 turns and a few minutes. Give the agent shell access to the target machine, or be ready to paste one install command yourself.
Keeping it up to date
Section titled “Keeping it up to date”(Since v0.4.3.) A CLI that drifts behind its Console fails in the least readable way there is: a tool call that looks like it was called wrong. Two commands, and one switch, keep that from happening.
dednetsctl self-update -check # what does my Console publish?dednetsctl self-update # fetch it, verify the sha256, swapThe one-line installer turns on a daily background check (you can decline
it). It works the way you would want it to: at most one check a day, the command
you typed finishes on the binary it started with and adds no delay, and a
detached child does the download in the background, so the next command you run
is the new version. It logs one line to ~/.cache/dednets/update.log and never
prints anything.
dednetsctl config # what am I configured for, and why?dednetsctl config set auto-update off # or ondednetsctl config set console https://console.example.comconfig is the command to run when something points at the wrong place: it shows
the resolved Console and where each value came from, so an exported
DEDNETS_CONSOLE that overrides your stored setting is visible rather than
mysterious. Precedence is -console flag, then DEDNETS_CONSOLE, then the
stored value; with none of those set the CLI talks to the hosted Console,
https://console.dednets.com (since v0.8.1). Your token is never printed.
To disable the check in one environment only, set DEDNETS_NO_UPDATE_CHECK=1.
self-update will not touch a CLI it does not own, and says what to run
instead: a Homebrew install gets brew upgrade dednets/tap/dednetsctl, and the
npx shim already re-resolves itself on every start.
Troubleshooting
Section titled “Troubleshooting”- The agent has no DedNets tools. Either the config file is not where the
client reads it, or
dednetsctlis not on the client’sPATH(Claude Desktop: use the absolute path). Restart the client after editing the config. The fastest fix isdednetsctl setup, which writes both clients’ config for you and reports what it changed. - Every DedNets tool fails as
unauthorized. No token reached the server. Rundednetsctl login, or setDEDNETS_TOKENin theenvblock, then restart the client. Since v0.4.3 the server starts either way and says this on each call; before that it exited instead, which showed up as the next item. - The plugin fails to connect, with
-32000and nothing else. The server process died before it could say why. Two causes, in order of likelihood:dednetsctlis not where the plugin looks (it tries$DEDNETSCTL, then yourPATH), or you are on a version before v0.4.3, where a missing token also exited. Run the wrapper by hand to see the real error:~/.claude/plugins/cache/dednets/dednets/*/bin/dednets-mcp. If it reportscli_not_found, install the CLI or pointDEDNETSCTLat it. Note that an install predating v0.4.1 providesdedmeshctl, the old name, which the plugin will not use. - A call was refused for scope. The error names the scope to add. You cannot widen an existing token: mint a new one with the extra scope and update the config.
- Everything 404s or answers nonsense.
DEDNETS_CONSOLEmust be the full base URL including the scheme (https://console.dednets.com). Since v0.4.3, rundednetsctl config: it prints the Console actually in use and where that value came from, so an exported variable overriding your stored setting is visible. install-cli.shrefuses with a checksum mismatch (since v0.4.3). The bytes it downloaded did not match the sha256 your Console publishes for that release. Nothing was installed and the download was deleted. A Console being redeployed at that moment explains it, so retry once; if it repeats, do not use that download and tell whoever operates the Console.self-updatesays the directory is not writable (since v0.4.3). The CLI is somewhere only root can write, usually/usr/local/bin. Re-run it withsudo, or reinstall with the one-line installer, which uses~/.local/bin.- A call fails with
console_outdated, or the log warns about versions (since v0.4.1). Thedednetsctlbinary and the Console are on different releases. On its first tool call the server prints one line on stderr naming both versions and keeps running; a call that needs an endpoint the Console does not have then fails with afix:line instead of a bare 404. Fix it from whichever side you control: ask the Console operator to upgrade, or reinstall the CLI from that Console -curl -fsSLO https://<console>/dist/darwin-arm64/dednetsctl(or thelinux-…/darwin-amd64/windows-amd64/dednetsctl.exepath for your machine). The same version with a different-<sha>suffix is not skew and is never reported. - My Homebrew CLI and my Console disagree on the version (since v0.4.1).
Expected:
brew installpins the release the formula was cut from, so a Console on a different release produces exactly the skew warning above. Runbrew upgrade dednetsctl. If the Console is the older side, upgrade it, or switch tonpx -y @dednets/mcp(Option A), which follows the Console. brew install dednets/tap/dednetsctlsays there is no available formula. That tap has not published a formula yet, or you have an old cached copy of it:brew updateand retry.- The install command the agent gives me fails to download. Install commands are generated for a console reachable over HTTPS on port 443. A self-hosted console on another port hands out a command whose download URL does not resolve; enroll that host from the Console’s own Deploy a daemon wizard instead.
- I want a look-but-do-not-touch setup. Add
"-read-only"toargs: only the read tools are published, so no tool call can change anything. - npx says
console_too_old(since v0.4.1). That Console publishes a release older than v0.4.1, from before the CLI was renamed, so there is nodednetsctlfornpxto fetch. Ask whoever operates it to upgrade, or install the CLI yourself with Option B in step 1 and point your client at the binary. - npx says
checksum_mismatch(since v0.4.1). The bytes downloaded did not match the sha256 that Console publishes. Nothing was run and the download was deleted. A Console being redeployed at that exact moment explains it, so retry once; if it repeats, do not use that download and tell whoever operates the Console. - The first npx run is slow. It is fetching a CLI of roughly 12 MB and
verifying it. Every later run reuses the cached copy until the Console
publishes a new version. Run
npx -y @dednets/mcp --probe-onlyonce to warm it before an agent host starts the server. - Windows: the client shows no DedNets server at all. Download the
.exepath (windows-amd64/dednetsctl.exe); the suffix-less file is not published and Windows would not run it. Inclaude_desktop_config.jsonevery backslash in the path must be doubled, or the JSON is invalid and the client drops the whole server entry without saying so.