npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

netscope-mcp

v0.1.2

Published

Read-only MCP server for ISP/NOC operators: look at your network (MikroTik RouterOS first) without handing the model any write access.

Readme

netscope-mcp

CI Security npm License: Apache-2.0 OpenSSF Scorecard

Give your LLM eyes on your ISP network, without giving it hands.

netscope-mcp is a strictly read-only Model Context Protocol server for ISP/WISP network operators. It lets an AI assistant (Claude, Codex, Cursor, any MCP client) inspect many MikroTik RouterOS (v6/v7) routers and switches at once, using one-call diagnosis recipes built for NOC work. VyOS and GenieACS (TR-069) support is planned for v0.2.

Status: v0.1. npm publication is pending; until then install from a release tarball or from source (see Quickstart). Not affiliated with or endorsed by MikroTik. "MikroTik" and "RouterOS" are trademarks of their owners.

netscope-mcp demo: asking an AI assistant about a router, a link and a customer, read-only

The problem

A NOC engineer at a small ISP answers the same questions all day: Is this router healthy? Why is this optical link weak? Which router is customer X on? What is plugged into this port? Each answer means logging in to several routers and running a handful of commands.

An LLM can do that legwork, but handing a model a RouterOS login with write access is a bad idea: one hallucinated /system reset-configuration or /ip firewall filter remove can take down customers. Most MikroTik MCP servers expose the whole router and rely on you to be careful.

Why read-only matters

netscope-mcp makes the safe thing the only thing:

  • Deny-by-default allowlist. Only print, monitor … once, /<menu> export hide-sensitive, ping and traceroute on a positive list of menus are ever sent. Anything else is refused before credentials are loaded or a device is contacted.
  • Secrets never reach the model. Output is redacted by key name, by pattern and by the exact credential values the server holds; script bodies are masked.
  • A read-only router account is the real boundary. The guard is one layer, not a sandbox. We show you how to create the RouterOS user so that even a bug in this project cannot change a router.
  • Auditable. 1,290+ automated tests including a security corpus (770 allowlist cases, 73 redaction cases, HTTP and property tests) run in CI, plus gitleaks, CodeQL, dependency review and OpenSSF Scorecard.

Why it is different

| | Typical MikroTik MCP | netscope-mcp | |---|---|---| | Goal | Manage a router through an LLM (often including writes) | Let an LLM observe a fleet safely | | Write protection | Optional read-only switch, or none | Read-only is the only mode: deny-by-default allowlist of print, monitor … once, /<menu> export hide-sensitive, ping, traceroute | | Secrets in output | Returned as the router sends them | Redacted by key name, by pattern and by the exact credential values the server knows; script bodies masked | | Tool design | Roughly one tool per RouterOS menu | Nine tools plus diagnosis recipes (health, neighbors-map, pppoe-lookup) | | Many routers | One device per call | Batch across routers in one call; one failing router does not fail the rest | | "Which router has customer X?" | Query routers one by one | pppoe-lookup across all routers, or a periodic snapshot you can search in milliseconds |

Features

  • Deny-by-default command guard: no abbreviations, no write verbs, no scripts, where only on non-secret columns, safe columns forced on /ppp secret, /user, /radius, /snmp.
  • Redaction on every response; exact scrubbing of known credentials in error messages.
  • Recipes that replace 5–25 raw calls with one answer.
  • Multi-router batch (up to 30 commands): parallel across routers, sequential per router over one reused session.
  • Optional snapshot store with cross-router search and explicit data age.
  • Account-lockout protection: per-device queue, session reuse, cooldown after a rejected login.
  • Output clipping, concurrency limits, timeouts, JSONL audit log (no secret values).
  • Transports: stdio (default) and Streamable HTTP with a mandatory bearer token.
  • API-SSL (port 8729) with certificate verification by default, optional fingerprint pinning, SSH (with host-key pin) for export.

60-second overview

  1. Create a read-only RouterOS user (a read policy group, API access only).
  2. Describe your routers in routers.yaml (credentials come from environment variables or a 0600 file, never plain YAML).
  3. Add the server to your MCP client and ask in plain language:

"Which router has customer [email protected] connected, and is its uplink optical level OK?"

A full worked example is in docs/DEMO.md. The detailed steps follow.

Quickstart

Requires Node.js 20 or newer (--snapshot needs Node.js 22.5 or newer for node:sqlite).

1. Create a read-only RouterOS user

Do this first. The tool-level guard is one layer; a read-only router account is the real boundary. See docs/ROUTEROS-READONLY-USER.md.

2. Install

From a release tarball (or build one yourself with npm ci && npm run build && npm pack):

npm install -g ./netscope-mcp-0.1.0.tgz
netscope-mcp --version

From source, without installing: npm ci && npm run build, then use node dist/cli.js wherever this guide says netscope-mcp.

3. Describe your routers

Create routers.yaml (a complete example with every field is in routers.example.yaml):

settings:
  audit_log: stderr

routers:
  - id: core-1
    host: 192.0.2.10        # documentation address (RFC 5737)
    port: 8729
    family: routeros
    group: backbone
    tls_fingerprint256: "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF"   # replace with your router's SHA-256 pin (or use tls_ca_file: /path/to/ca.pem)
    credentials: { user_env: ROS_CORE1_USER, pass_env: ROS_CORE1_PASS }

Credentials are never accepted as plain values in YAML: only environment-variable names or a mode-0600 file. Full schema: docs/CONFIG.md.

4. Check the configuration, then run

export ROS_CORE1_USER=netscope-ro
export ROS_CORE1_PASS='<long random password>'
netscope-mcp --config ./routers.yaml --check     # prints "configuration OK: 1 router(s)."
netscope-mcp --config ./routers.yaml             # stdio transport

5. Connect your client

Claude Code:

claude mcp add netscope \
  --env ROS_CORE1_USER=netscope-ro --env ROS_CORE1_PASS='<password>' \
  -- netscope-mcp --config /path/to/routers.yaml

Claude Desktop / Cursor (claude_desktop_config.json, ~/.cursor/mcp.json):

{
  "mcpServers": {
    "netscope": {
      "command": "netscope-mcp",
      "args": ["--config", "/path/to/routers.yaml"],
      "env": { "ROS_CORE1_USER": "netscope-ro", "ROS_CORE1_PASS": "<password>" }
    }
  }
}

Codex CLI (~/.codex/config.toml):

[mcp_servers.netscope]
command = "netscope-mcp"
args = ["--config", "/path/to/routers.yaml"]

[mcp_servers.netscope.env]
ROS_CORE1_USER = "netscope-ro"
ROS_CORE1_PASS = "<password>"

Prefer no passwords in client configs? Use credentials: { file: /etc/netscope-mcp/core-1.cred } (mode 0600, lines user=…, password=…).

Streamable HTTP (several users, or a client that cannot spawn processes):

export NETSCOPE_MCP_TOKEN="$(openssl rand -hex 32)"
netscope-mcp --config ./routers.yaml --http 127.0.0.1:8080
# clients: POST http://127.0.0.1:8080/mcp with  Authorization: Bearer <token>

6. Try it

"List my devices, then run the health recipe on core-1 and tell me if anything looks wrong."

"Which router has customer [email protected] connected?"

Sample output: docs/RECIPES.md.

Tools

| Tool | Purpose | |---|---| | list_devices | List configured devices (filter, group); never credentials. | | mikrotik_read | One read-only command: print (with where/proplist/count-only), monitor … once, /<menu> export hide-sensitive (SSH; full menu path only, e.g. /ip service export hide-sensitive). | | mikrotik_batch | Up to 30 {device, command} items, fault-tolerant. | | mikrotik_recipe | health, neighbors-map, pppoe-lookup. | | ping / traceroute | From a router (or local when enabled) to a literal IP address. | | snmp_get | SNMP v2c GET/walk on an allowlisted set of subtrees (max 500 rows). | | switch_read | Ready-made reads for CRS switches; SwOS over SNMP. | | mikrotik_snapshot | Periodic data and cross-router search, always with data age. Needs --snapshot. |

Each response is concise text plus structuredContent; failures are real errors (isError: true) with a cause: policy, auth, timeout, connect, not-found, device, busy, config.

Tested on

Tested read-only against real devices on 2026-10-22 (RouterOS API with the bundled SSH runner; SNMP v2c where reachable). A check mark means every tool listed worked and no parsing problem was seen.

| Device (family) | RouterOS / SwOS | API tools, recipes | export via SSH | SNMP | |---|---|---|---|---| | hEX RB750Gr3 (mmips) | 6.48.6 (long-term) | yes | not yet tested | not reachable in the test network | | RB450Gx4 (arm) | 7.12.1 (stable) | yes | not yet tested | not reachable in the test network | | hEX RB750Gr3 (mmips) | 7.24.4 (stable) | yes | not yet tested | yes | | x86 (bare metal) | 7.23.8 (long-term) | yes (no /system routerboard, /system health reports only state=disabled) | yes | yes | | CRS310-1G-5S-4S+ (arm) | 7.23.5 (long-term) | yes (switch_read, SFP health) | yes | yes | | CRS326-24S+2Q+ (mipsbe) | 7.23.5 and 7.23.8 (long-term) | yes (switch_read, SFP, PSU/fan health) | yes | yes | | CSS326-24G-2S+ | SwOS 2.16 | n/a (SNMP only) | n/a | yes (switch_read sysinfo, interfaces) |

  • RouterOS 6.x: API tools work (flat /system health, oct/22/2026 dates are returned as the router writes them). export over SSH on v6 and RouterOS 6.49.x are not yet tested (no such device with SSH access was available); treat them as unverified.
  • SNMP and SSH need network reachability from the MCP host: a NAT port-forward that only exposes the API port will make SNMP/SSH time out. These failures are reported cleanly and do not affect the API tools.
  • Redaction and the allowlist behave identically on v6 and v7 in the tests above; regression fixtures for both shapes are in test/unit/compat.test.ts.

Security at a glance

  • Read-only by construction: anything not on the allowlist is refused with a policy error before a device is contacted.
  • Secrets are redacted before they reach the model.
  • redact_pii (on by default) masks the device half of customer MAC addresses and free-text columns. PPP login names are not masked by default (pppoe-lookup needs them); set redact_ppp_names: true to mask them too. See docs/CONFIG.md.
  • HTTP mode refuses to start without a token of at least 32 characters, binds to loopback by default, validates Host and Origin, accepts POST /mcp only and sends no CORS headers.
  • Plain API (port 8728) and unverified TLS work only with settings.allow_insecure: true.
  • Limits, stated honestly: the guard is a tool-level layer, not a sandbox. Always use a RouterOS account whose policy is read-only.

Details: SECURITY.md · docs/ROUTEROS-READONLY-USER.md

Documentation

Demo · Recipes · Configuration · Snapshot · FAQ · Bahasa Indonesia

Library use

The core is importable without MCP: import { NetScope, planRosCommand, redactText } from 'netscope-mcp/core'; the MCP and HTTP front-ends are in netscope-mcp/server.

Used in production

netscope-mcp was built by, and is used daily at, a small Indonesian ISP to give its NOC assistant read access to dozens of MikroTik routers (backbone, aggregation and edge). It is exercised against real fleets, not only simulators. Names and addresses are intentionally omitted here; if you run it, please open an issue or discussion and tell us your scale (anonymous is fine) so we can list adopters.

Roadmap

  • v0.1 — RouterOS v6/v7 (API, API-SSL, SSH for export), recipes, batch, snapshot, SNMP v2c, CRS/SwOS switches, stdio + HTTP.
  • v0.2 — VyOS read tools, GenieACS read-only tools, SNMPv3, RouterOS v7 REST transport.
  • v0.3 — change detection between snapshots, per-token device ACLs, MCP prompts/resources.

Contributing

Issues and pull requests are welcome, especially: RouterOS version quirks, new read-only recipes, translations of the docs, and security-test cases for the allowlist. Read CONTRIBUTING.md first (read-only is a hard requirement; fixtures use only documentation addresses). Report vulnerabilities privately as described in SECURITY.md.

License

Apache-2.0. See LICENSE and NOTICE.