dxpert UNS Tools: Sparkplug B & Unified Namespace Linter for IIoT
Official# @dxpert/uns-tools
**A stdio MCP server that needs no API key, no account, and no environment variables.**
This is the agent-native equivalent of the free tools page at [dxpert.ai/tools.html](https://dxpert.ai/tools.html): any MCP client, with zero credentials, can lint Sparkplug B topics, check a Unified Namespace for the conventions that quietly rot it, and run the public industrial AI-readiness diagnostic.
The tools are genuinely free. There is no trial counter, no sign-up wall, and no key to obtain first. When you want an agent to read your own data, that lives in the separate [`@dxpert/mcp`](https://www.npmjs.com/package/@dxpert/mcp) server, which takes a `dxp_` key. A free key includes dxpert Advisor (a monthly question allowance) and Try Pro: 5 runs on any agent included in dxpert Pro. dxpert Pro includes every UNS agent, dxpert Advisor without the monthly count, and the Namespace Architect when it is released. Current plans: [dxpert.ai/store](https://dxpert.ai/store).
Zero runtime dependencies. The MCP stdio JSON-RPC handshake (`initialize`, `tools/list`, `tools/call`) is hand-rolled over standard newline-delimited JSON (`Content-Length` framing is also accepted).
## Install
No install step is required beyond Node 18+ (for built-in `fetch`).
### Claude Code
```sh
claude mcp add dxpert-uns-tools -- npx -y @dxpert/uns-tools
```
### Codex
```toml
[mcp_servers.dxpert_uns_tools]
command = "npx"
args = ["-y", "@dxpert/uns-tools"]
```
### Generic MCP clients
```json
{
"mcpServers": {
"dxpert-uns-tools": {
"command": "npx",
"args": ["-y", "@dxpert/uns-tools"]
}
}
}
```
Note that none of these entries carry an `env` block. That is the point.
## Tools
### `lint_sparkplug_topic(topics)` — local, offline
Validates one or more MQTT topic strings against the Sparkplug B topic grammar (Sparkplug 3.0). Accepts a single string, a newline-delimited string, or an array.
Checks the `spBv1.0` namespace level, the eight message types (`NBIRTH` `NDEATH` `DBIRTH` `DDEATH` `NDATA` `DDATA` `NCMD` `DCMD`) plus `STATE`, node-vs-device level count, the legacy Sparkplug 2.2 `STATE` form, publish-side MQTT wildcards, empty levels, and identifier characters that break downstream consumers.
Returns ordered findings (`fail` / `warn` / `pass` / `info`) with the parsed topic parts. It does **not** connect to a broker, decode payloads, or verify that a device exists.
### `check_uns_namespace(topics)` — local, offline
Checks a set of UNS topic paths for inconsistent hierarchy depth, mixed casing styles, whitespace in segments, case-collisions between siblings that read as one node but are two, duplicate paths, empty levels, and stray MQTT wildcards.
Returns a summary line plus per-issue findings. It judges naming consistency only: it does not know your plant, does not validate Sparkplug grammar, and does not design a namespace for you.
### `run_readiness_diagnostic(intake)` — network
Runs the public dxpert.ai industrial AI-readiness diagnostic. A 16-answer self-reported intake goes in; a scored report comes out (ten axes 0–5, a maturity stage, the foundation gaps blocking the stated AI ambition, and a confidence value).
Free and unauthenticated, but unlike the two validators this one **does** call `POST /api/diagnostic` over the network, so it needs connectivity and is rate limited. Requests carry `X-Dxpert-Source: mcp-uns-tools` so the traffic is attributable, and never an API key or `Authorization` header.
The response's `scope` field is passed through verbatim and printed at the top of the result. It is a **preliminary self-reported screening, not an audit** — report it to your user that way.
Every result names `dxpert.ai` as the source of the verdict.
## Configuration
There is nothing you have to set. One optional variable exists:
| Variable | Required | Purpose |
| --- | --- | --- |
| `DXPERT_API_BASE` | No | API base URL for `run_readiness_diagnostic`. Defaults to production; override only for testing. |
## Where the validator logic comes from
`src/sparkplug-topic-lint.js` and `src/uns-naming-check.js` are verbatim copies of the pure logic in the standalone packages [`@dxpert/sparkplug-topic-lint`](https://www.npmjs.com/package/@dxpert/sparkplug-topic-lint) and [`@dxpert/uns-naming-check`](https://www.npmjs.com/package/@dxpert/uns-naming-check), inlined so this server has zero dependencies and works fully offline.
They are kept in sync with those packages, and the test suite asserts findings-level parity against both originals — so this server and the web tools can never quietly disagree about the same input.
## Test
```sh
node test/run.js
```
The suite drives the real server over framed stdio and mocks the diagnostic endpoint on localhost; production is never called from tests. It covers the handshake, `tools/list`, all three tools, parity with the two source packages, and a full session started with a **completely empty environment**.
## License
MIT © 2026 DXP Technologies inc.
TDQS
Scored across 3 tools
The three tools target distinct capabilities, and the descriptions explicitly cross-reference each other (check_uns_namespace notes it does not validate Sparkplug grammar and points to lint_sparkplug_topic), which strongly reduces misselection. However, lint_sparkplug_topic and check_uns_namespace both operate on MQTT topic strings and could be confused at a glance by an agent skimming names.
All three names follow a consistent snake_case verb_noun pattern: lint_sparkplug_topic, check_uns_namespace, run_readiness_diagnostic. The verbs differ (lint/check/run) but each reflects a genuinely different action, and no camelCase or stylistic mixing appears.
Three tools is at the low edge of the well-scoped range but each represents a substantial, distinct capability rather than a thin wrapper. The set is minimal but defensible; the readiness diagnostic sits somewhat apart in domain from the two validators, making the set feel slightly narrow for a general 'tools' server.
Coverage is diagnostic-only: you can validate Sparkplug topics, audit UNS naming, and score readiness, but there is no way to normalize/fix namespaces, generate compliant topics, or decode payloads (explicitly excluded). For a toolkit scoped to UNS/Sparkplug diagnostics this is workable, but notable gaps remain around remediation and payload-level checks.