Releases: netcopilot-labs/netcopilot
Release list
v2.3.0 — The Agent as a Tool
NetCopilot's MCP server now offers two pure surfaces, chosen at startup
with MCP_SURFACE and never mixed:
full(default) — every registry tool, byte-identical to v2.2.0.
Nothing added, nothing renamed, zero breaking: existing clients see
exactly what they saw yesterday.ask— a single tool,ask_netcopilot(question, site?), that runs
NetCopilot's COMPLETE internal agent server-side (deterministic routing,
the whole toolset, the eval-guarded answer quality) and returns the
grounded answer plus which tools it used (structuredContent = {status, tools_used}). About 100 schema tokens in the client's context
instead of ~5,500. Expect 10-60 s per call: a full agent conversation
runs behind it.
Why: measured in the v2.2.0 study, an external client used to pay the full
schema cost every turn while none of the internal routing/eval quality
traveled the wire. Now delegating clients get the expert; composing clients
keep the full atomic registry. Precedent: Sentry's use_sentry.
Also in this release:
- Errors are honest MCP citizens: provider down, loop errors, empty answers
and a 170 s hang guard all map toisErrorwith real messages; the
server boots and lists tools with no LLM configured. - Era-agnostic fastmcp import (public
fastmcp.toolspath) — verified on
fastmcp 3.2.4 and 4.0.0b1. - Gateway docs updated: the "structured results travel direct-only"
limitation is gone since gridctl v0.1.0-beta.14 (the upstream fix we
contributed, gridctl#849, verified end-to-end), and tool groups
(beta.15+) are documented as the per-client curation axis.
Suite: 1449 passed (9 new tests, also green on fastmcp 4.0.0b1).
v2.2.0 — Measured Registry Hygiene
Everything in this release traces to a measurement. An 864-call tool-selection
study (31B + 4B tiers, random and adversarial distractor arms) found no
count degradation at 33 tools — the failures that did exist were textual.
So this release fixes text, hardens the measuring instrument, and installs
gates so the registry stays healthy as it grows. The planned Tool-RAG build
was cancelled by its own feasibility data.
Highlights
get_security_policies→get_cisco_policies: the registry's worst
name collision (0.794 embedding similarity withget_firewall_policies,
both descriptions claiming Cisco ACLs) split on definitions-vs-verdicts.
Re-measured at 0.547.- Discriminability gate: new test fails any NEW tool pair above 0.70
similarity; the five known overlaps are explicit, documented debt. - Eval: all 33 tools asserted (25 → 40 questions), including
honest-negative questions — the assistant must say "none" when the network
has none. - The eval cannot lie: load-time catalogue validation (typo'd assertions
used to pass forever),requires:preconditions that SKIP (never FAIL)
when a feature is absent from the loaded run, and a baseline run-id guard
that stops cross-network diffs from reporting phantom regressions. llm/ollama.py→llm/openai_compat.py: one provider per wire
format, not per vendor.OLLAMA_*env vars unchanged (back-compat).- Version-drift guard: the declared version can no longer silently lag
the newest tag (it shipped stale twice).
Breaking change
The MCP tool get_security_policies is now get_cisco_policies. Clients
discovering tools via tools/list adapt automatically; hardcoded names must
update. Everything else is backwards compatible.
Full suite: 1440 passed. Live eval: 36 pass / 0 fail / 4 honest
skips, four identical consecutive runs.
v2.1.0 — Redundancy, First-Class
Three features that make network redundancy a first-class, fully-answerable domain — and make the agent's tool choice auditable.
🌐 FHRP (HSRP / VRRP) first-class
Your first-hop gateways are now modeled, checked, and answerable:
- VRRP collected (
show vrrp allparse-fallback), HSRP + VRRP modeled asfhrp_groupshared services — members, VIP, active router, per-member priority/timers - 14 executable FHRP health rules (no active router, no standby peer, VIP outside the subnet, priority conflicts, timer/version mismatches, missing auth/tracking…)
- Ask "how is VRRP configured?", "which router is the active gateway for VLAN 60?" — answered from the live network state, completely, in one call
trace_pathresolves a gateway VIP to its active router;blast_radiusreports each gateway as PROTECTED (a standby survives) or LOST- NetBox reconciliation: running-but-undocumented and declared-but-absent FHRP groups become drift findings
- New demo scenario:
demo/campus-ha/
🧭 Deterministic-first tool routing + a measured agent (merged via #19)
routing.yaml: known question intents route deterministically — for static-argument intents the orchestrator calls the tool itself and the model only narrates. Every entry must cite the documented failure that motivated it; every decision is an auditableroutingeventscripts/eval/: a 25-question answer-quality harness (routing accuracy, tools called, answer facts, security probes) with a model-stamped baseline — answer quality is a measured property now- ANSWER DEPTH calibration: open questions get the complete picture; pointed questions stay short
🔗 LAG / port-channel first-class
- The bundle lives on the Port-channel interface: protocol, oper status, per-member LACP state (bundled / activity / priority / partner)
- 8 executable LAG rules (bundle down, member not bundled, static bundles, speed mismatch, min-links, partner system-id mismatch, member-count mismatch, etherchannel guard); the 9th (
LACP_ERRORS) is honestlymanual_review— its counter isn't collected, and we don't fake checks - "Is the port-channel between core-sw-01 and acc-sw-03 healthy?" — answered, with the members
- FHRP-over-LAG correlation: if your gateway peers interconnect over a single-member bundle, the redundancy assessment says aloud that failover depends on one physical link
Numbers
- Tests: 1346 → 1423
- Eval: 25/25 × 3 consecutive runs (local Gemma), plus a 25-question adversarial edge audit: 0 broken, 0 hallucinations, security probes clean
- Zero new node labels, zero new MCP tools, zero provider changes — everything extends existing constructs
Full diff: v2.0.0...v2.1.0
v2.0.0 — The Declared Network
NetCopilot 2.0 joins three sources of truth into one deterministic model: the declared network (your NetBox), the observed network (collection), and the compute layer (your vCenter / ESXi).
Highlights
- One-click NetBox inventory. Collect your network, press Bootstrap: devices, interfaces, IPs and cables are staged, shown to you, and written to your NetBox after you approve.
- The Service view. Name an IP in NetBox IPAM ("lobby camera") and NetCopilot draws it on the switch and port that actually serves it, with an explicit confidence verdict: port-precise / gateway / approximate / never seen. A documented IP the network has no trace of is an answer, not an omission.
- Client networks. Tag a prefix
client-networkand it lands on its real access switch (its VLAN's member ports), with VLAN, port-channels and member links in the detail panel. - VMware integration (read-only, enforced by tests). One inventory row (
os: vcenteroros: esxi) and every service shows whether it is a VM, on which ESXi node, guest OS, VMware Tools state, CPU/mem, its health and its node's health. Idle VMs classify correctly: the network cannot see a machine that never talks, the hypervisor can. One batched PropertyCollector call per collection. Hypervisor host names never leave your machine (generic node-N labels). - Multi-site NetBox. Scope prefixes to sites and each run's Service view shows only its own site's services; cross-site skips are reported per item, never silent.
- No silent wipes. The service join reads NetBox strictly: a mid-pull failure keeps the previous service layer instead of deleting it and calling that "empty".
Verification
1346 tests (+32), including collector-level routing for both VMware modes, the strict-read/no-wipe contracts, site-scoping longest-match, and a wire-surface proof that the VMware integration is retrieval-only. Full pre-release audit (leaks / NetBox / VMware / UX / regression) with every finding fixed. Live-verified end-to-end against a real production network and a real vSphere cluster.
Docs
- INSTALLATION: new sections B2 Connect your VMware and B3 Connect your NetBox (bundled
--profile netboxor bring-your-own; NetBox can be added after NetCopilot at any time). - README: client networks, multi-site scoping, VMware capability.
- Docker image now includes the
[esxi]extra.
🤖 Generated with Claude Code
v1.5.0 — Tools that don't lie
Tools that don't lie
A quality sweep applying one rule to the whole MCP tool surface: never report a network as clean or complete when it isn't. Driven by a read-only audit of all 25 tools.
The headline fix — the false "0 findings". The findings loader conflated three states — "the graph is unreachable", "the query errored", and "the run genuinely has no findings" — into one indistinguishable result, so tools rendered "0 findings" for all three. A down graph read as a clean network. Now the loader raises a typed FindingsUnavailable (distinct from an empty result), and every consumer surfaces it honestly: primary findings tools return an error, dashboard APIs return 503 (not a false 404), and nothing presents a fabricated zero.
The rest of the sweep
- No "reads clean when not collected" — security posture, site summary, and device detail now account for uncollected devices instead of hiding them.
blast_radiusstops silently ignoringinterface/max_hops; its verdict and map highlight now carry the affected blast area and internet impact.- Captured-but-unread fields rendered — route active/inactive state, QoS policer-vs-shaper type, firewall schedule and logging flags.
- Honest status codes — empty or failed results return
no_data/error, not a misleadingok. - Two machine-readable verdicts where a real consumer exists — a findings severity summary and a security pass/warn/fail — with no speculative verdicts added elsewhere.
Backward-compatible; deterministic model snapshots unchanged. Verified end-to-end on a real production collection.
v1.4.0 — Path-tracing truth
The policy your automation couldn't see
trace_path now tells the whole truth about a flow — and closes a class of silent failure where firewall policies referencing the FortiGate Internet Service Database (ISDB) were invisible to the tracer. A flow governed by an Internet-Service block policy used to report "no matching firewall policy found." Now it returns a real blocked/permit verdict naming the policy.
What's new
- ISDB resolution over REST — Internet-Service references are resolved to their IP ranges via the FortiOS monitor API (referenced services only; explicit truncation flag on huge feeds; degrades gracefully). No SSH.
- Policies stored as data —
dst_isdb/src_isdbon policies; resolved feeds become:ISDBServicegraph nodes. - Every policy on the path — Cisco ACLs on transit devices are now evaluated at each hop (not just at the firewall), via one shared matcher on protocol and port.
- A typed reachability verdict —
trace_pathcarries{result, reasons, blocked_by, risks, return_path}to any MCP client: reachable / blocked / partial / unknown, with open findings on the path surfaced as risks, and honest reasons for anything it couldn't verify — never a clean-by-omission answer. - Flow-shaped tracing — optional
src_ip/protocol/dst_port, plusrun_idto trace a past run for pre/post-change path comparison. - Return-path awareness — a reverse walk flags asymmetric routing and stateless-ACL return holes.
Backward-compatible: all new trace_path arguments are optional. 1047 tests; deterministic model snapshots unchanged.
v1.3.0 — Change Validation: a deterministic verdict on every change
NetCopilot can now judge a network change, not just describe it.
The trap this release closes: after a change, the success check is usually chosen by whoever (or whatever) made the change — a local ping, a quick glance — and it passes. From anywhere else, things are broken. An agent grading its own homework picks the test it can pass. The antidote is a verdict chosen by policy, before the fact, and computed deterministically — never by the model.
✅ Change validation — pass / warn / fail
Declare what was supposed to change; NetCopilot diffs the pre-change and post-change snapshots and judges the drift:
- fail — a new
critical/highfinding appeared (regardless of scope), or any drift touches only devices outside the declared scope. - warn — new minor findings, drift with no declared scope, or changes that can't be attributed to a device — honest uncertainty, surfaced instead of silently dropped, and never escalated into a false fail.
- pass — every change touches the declared scope and nothing new broke.
The policy is explicit and documented — the policy is the spec. No LLM anywhere in the verdict path: same inputs, same verdict, every time. Operational noise (the drift feature's volatile/info field contract) never affects the result, and resolved findings are reported as the good news they are.
One engine, three surfaces
- MCP tool
validate_change— the 26th tool. Declared scope as an argument; the verdict travels to any MCP client as structured content. It appeared on the external server surface with zero server changes — the registry-generated surface from v1.2.0 doing exactly what it promised. - CLI pipeline gate —
netcopilot validate --after <run> [--before <run>] [--scope dev1,dev2]exits0/1/2= pass/warn/fail, so a change pipeline can gate on it directly:netcopilot validate --after $(post_change_run) --scope core-sw-01 || rollback
- Dashboard banner — the Audit-tab drift view now opens with an automatic green/amber/red verdict and its reasons, above the change list it already showed. In-app menu (
list_capabilities) updated accordingly.
Numbers
- Tests: 963 → 1000 passed
- MCP tools: 25 → 26 (external surface followed automatically)
- New verdict engine: pure function, every policy rule pinned by its own test; verdict schema frozen (external consumers can build on it)
Full changelog: v1.2.0...v1.3.0
v1.2.0 — From Tools to Contracts
Three releases of spec-driven hardening, in one theme: the discipline NetCopilot always practiced in prose is now machine-enforced — in the type system, in the rule catalog, and on the MCP wire.
🏛 A constitution as step 0
NetCopilot's operating principles are now codified in CONSTITUTION.md: context agent, never actuator · determinism over cleverness · null over guessing · least privilege in config · machine-enforced contracts over prose · evidence traceability. Every future spec and PR is checked against it.
📜 Rule-catalog spec hygiene
- First-class
status: active | deferred | manual_reviewon all 426 rules — deferral is now explicit metadata, never disguised by renaming. - Spec/implementation drift found by audit and fixed (CIS timezone rule aligned to its check; mismatch-family check-logic blocks corrected).
- The loader validates status and reports what it skipped — nothing silently disappears.
📦 Typed tool-result envelope
Every one of the 25 MCP tools now returns a frozen ToolResult(status, text, verdict, highlight, verbatim) instead of a free-form string:
- Named failure modes as machine-readable status codes:
no_data≠not_found≠ambiguous≠error. A tool that has no evidence says so in a way code can branch on — the antidote to false-OK results. - The contract is enforced, not requested: a handler returning anything else raises. Prose contracts drift; typed contracts fail loud.
- Three string-convention hacks (prose-scraping, inline markers, hardcoded tool-name sets) deleted; the orchestrator consumes typed fields. Model-facing text stayed byte-identical throughout.
🌐 The full MCP surface — generated, not enumerated
The server previously exposed 3 of 25 tools to external MCP clients while the README claimed the full surface (found by our own audit). Now:
- The surface is generated from the tool registry — names, descriptions, and parameter schemas have a single source of truth; a new tool appears externally with zero server changes. Drift between the internal and external surface is structurally impossible.
- The envelope travels: results carry
{status, verdict}as MCP structured content alongside verbatim text; tool failures map to MCP-nativeisError.no_datais a valid answer, not an error. - Root fix included: every tool context now carries the run's data directory, so file-backed tools (path tracing, OSPF detail, security posture) work identically over the external surface.
Any MCP client — Claude Desktop, an agent framework, a gateway — now sees everything NetCopilot can do, with a machine-readable contract on every result. Read-only, as always: the network is the MCP server, and it never changes devices.
Numbers
- Tests: 931 → 963 passed (+28 skipped)
- MCP tools exposed externally: 3 → 25
- Free-form
strtool contracts: 25 → 0 - Orchestrator: −85 lines (string-convention workarounds deleted)
Full changelog: v1.1.0...v1.2.0
v1.1.0 — Run-to-run drift
v1.1.0 — Run-to-run drift
"What changed on my network, and does it matter?" NetCopilot now compares any two runs of a site and tells you exactly what changed.
Highlights
- Deterministic drift engine — classifies every model entity as added / removed / changed, plus an
infotier for semi-volatile signals (counters, ARP/FDB, DHCP, session uptime), so an unchanged network shows zero false drift. - Three surfaces:
netcopilot diff <runA> <runB>(CLI)diff_runsMCP tool for chat + external agents, incl. "N runs ago" resolution- Audit-tab diff mode in the dashboard: grouped change list, click-to-filter, topology halos on affected elements + ghosts for removed ones
- Synthetic before/after demo pair (
demo/drift-demo/) with a golden regression guard. - README "What can NetCopilot do?" capabilities overview.
Under the hood
- ~59 new tests; goldens byte-identical; MCP tools 24 → 25.
- Same two runs always produce the same diff.
Context, never actuation — NetCopilot tells you what changed; you decide what to do.
Full changelog: v1.0.0...v1.1.0
NetCopilot v1.0.0 — Network Context Intelligence
Network Context Intelligence — a deterministic, verifiable model of your multi-vendor network, served over MCP to humans, LLMs, and agents. Open-source, Apache 2.0.
What's in v1.0.0
- Read-only multi-vendor collection (Cisco IOS-XE / IOS-XR, Fortinet) → an evidence-backed graph model in Neo4j. NetCopilot never writes to your devices.
- Deterministic & traceable — the same inputs always produce the same model, and every finding traces back to the device output that proves it.
- MCP-native — query your network as a tool from any LLM, agent, or the built-in dashboard.
- Multitenant — many networks in one deployment, isolated end-to-end by
site+run_id. - Bring your own — model (local, or Claude / Gemini / GPT), inventory, RAG documents, Telegram bot, and SMTP, all via
.env+models.yaml. No code changes. - One-command deploy —
docker compose up.
Get started
Quickstart and full guide in README and INSTALLATION.md. Deep-dives and the roadmap: netcopilot.io.