vor
Subscribes to an MQTT broker over Sparkplug B topics (spBv1.0/#) to receive live industrial telemetry samples for governed reads, while publishing nothing.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
vor
Vor is the governed reader of the Yggdrasil IIoT project. It is an MCP server (stdio) exposing exactly one tool, read_governed(question_id). It embeds no LLM; the MCP host does the reasoning. It answers with a value bound to a published Bifrost mapping release and a live Sparkplug B sample from Muninn, or with a deterministic refusal. Question ids are fixed in the configuration; a question id that is not configured is refused (binding-invalid, rule question-unknown). The host cannot ask for an arbitrary node or metric. Vor shares no code with Bifrost or Muninn: it reads only their published bytes (the Bifrost registry directory on disk, and Sparkplug B messages on an MQTT broker).
What an answer contains
An answer contains the following items, each with its source (a release file path plus its raw-byte SHA-256, or the MQTT topic the sample came on):
Semantic pin (stream_id, release_id, version, release_sha256, file, file_sha256, field_id, digest_rule "raw-bytes-sha256")
Verified head (headVersion, signedAt, expires, publishedBy, approvedBy)
Meaning (semanticId, name, description, lifecycle state, revision)
UCUM unit code
ISA-95 equipment path and its levels
Sparkplug binding (group, edge, device, metric, governed definition reference)
Temporal policy
Sample (value, quality good/uncertain, OPC UA status code, source and server timestamps, age)
Verdict (usable or usable-uncertain; carries a meaning-deprecated warning with the replacement semanticId when the meaning is deprecated)
A refusal has answer null and a verdict with usable false, a reason code, and evidence. A refusal never carries the sample value.
Related MCP server: RecoSearch
Refusals
Checks run in this fixed order; the first failing check decides the reason. Vor verifies the DSSE (in-toto Statement v1) head attestation of a stream with Ed25519 public keys from the trusted keys file outside the registry; publisher and approver must be different principals with different keys. Vor replays semantic lifecycle events from releases at every stream head in the registry; every head must verify.
Reason code | When it fires |
head-unverified | Head file or DSSE envelope missing, publisher and approver are the same principal, a signature does not verify against a trusted key, both signatures from the same key, statement subjects do not match the head and release.json, or the head is signed in the future. |
head-rollback | Head version below the stored floor, or the same version with a different statement. |
head-expired | The current time is at or past the head's expires. |
provenance-mismatch | release.json, the proposal, or a payload file does not match its recorded SHA-256 or identity. |
binding-invalid | The read binding is missing or does not resolve (fields, projection other than identity, stream, mapping set, target, semantic definition, equipment, mapping, member path, semantic id, metric, source node, unit, hierarchy path, device not equal to the ISA-95 path), or the question is not configured. |
meaning-retired | The meaning is retired in the semantic lifecycle. |
unit-unknown | The output unit is not a known UCUM code. |
policy-missing | The mapping has no valid temporalPolicy. |
no-sample | No sample for the bound metric in the current Sparkplug session. |
sample-unknown | The sample lacks a status code or source timestamp (or the timestamp the policy uses), or its type does not match the field's numeric type. |
bad-quality | OPC UA status severity is bad. |
uncertain-rejected | Severity is uncertain and the policy does not propagate uncertain input. |
future-sample | The evaluated timestamp is after now. |
stale | Sample age exceeds maxAgeMs. |
skew-exceeded | The spread of source timestamps exceeds maxSkewMs (zero for a single scalar input). |
location-mismatch | The Sparkplug device id is not the ISA-95 path from the release. |
(future-sample and stale cannot both apply to one sample.)
Configuration
The configuration file is JSON, named by the environment variable VOR_CONFIG. Relative paths resolve against the config file's directory.
{
"registry": "registry",
"trustedKeys": "trusted-keys.jsonl",
"stateDir": "state",
"mqtt": "tcp://localhost:1883",
"questions": {
"mixer1-temp": {"stream": "line1", "binding": "vor-binding-mixer1-temp",
"description": "Mixer1 process temperature in Cel"}
}
}registry: The Bifrost registry directory (it contains mappings/).
trustedKeys: JSON-lines file of trusted Ed25519 public keys.
stateDir: Where rollback floors (head version and statement digest) are written per stream.
mqtt: Broker URL.
questions: Question id to stream, read-binding id, and a description shown to the host in the tool description.
Run
Requirements: Python 3.11+. Dependencies: mcp (>=1.2,<2, FastMCP), paho-mqtt (>=2.0), cryptography (>=42).
Install:
pip install -e .
# for tests:
uv pip install -e ".[dev]"Run:
VOR_CONFIG=path/to/vor.json vor
# or:
VOR_CONFIG=path/to/vor.json python -m vor.serverAn MCP host launches it as a stdio server with command vor (or python -m vor.server) and the VOR_CONFIG environment variable set.
Joining a running edge node
Vor subscribes to spBv1.0/# with QoS 1 and publishes nothing. A session starts with an NBIRTH at seq 0; sequence numbers must continue modulo 256. A sequence gap, an NDEATH, a DDEATH, or an undecodable payload drops the cached samples until the next birth. Each data message replaces a sample whole; metadata is never carried over from an earlier message. Muninn puts the OPC UA source time in the metric timestamp and adds the properties Quality, ua_statuscode, and ua_server_timestamp to each metric.
Vor caches nothing until it sees a birth. If Vor starts after the edge node's NBIRTH, read_governed answers no-sample until the edge node births again. Vor does not request a rebirth itself, because it publishes nothing. A Sparkplug primary host application or an operator sends the rebirth request (an NCMD with Node Control/Rebirth = true); Muninn's own CLI has:
java -jar muninn.jar host <mqttUrl> rebirth <group> <edge>Verified live: started after the birth, Vor answered no-sample; after one rebirth request it answered usable with a sample about 1.3 s old.
Tests and fixtures
Run tests:
pytestTests include a refusal case for every reason, provenance tampering of release.json and each payload file, real MCP stdio round trips, and NBIRTH/DBIRTH/DDATA bytes captured from a real Muninn session (tests/fixtures/muninn-wire).
Every registry byte the tests verify was written by Bifrost's own CLI. Regenerate with:
(cd ../bifrost && mvn -pl gates -am package -DskipTests)
python scripts/make_fixtures.py [--bifrost ../bifrost]This requires /gates/target/bifrost-gates.jar. It writes tests/fixtures/registries/{active,deprecated,retired} and tests/fixtures/trusted-keys.jsonl; private keys are created in a temporary directory and deleted. tests/fixtures is marked -text in .gitattributes so line endings never change hash-pinned bytes.
Design
The design specification is located at docs/superpowers/specs/2026-11-01-vor-m1-governed-read-design.md.
This server cannot be deployed
Maintenance
Related MCP Connectors
Guarded MCP server for agent-readable business truth, provenance, readiness, and discovery.
Read-only Remote MCP for externally grounded AI agent trust receipts.
One governed MCP endpoint for 40+ business systems. Read-only, source-cited answers.
MCP facade over the Nebelus Construction API. ~48 tools give full agent build parity: create/update/probe agents, edit graphs, attach knowledge and vector stores, wire connectors, set governance policies and locked guardrails, enable grounding-trace, and read deployment wiring. Purpose-built for regulated industries: data residency is enforced per region (EU / GCC-KSA), with PII controls and an audit trail. Agents are created as drafts — no deploy tool is exposed over MCP by design; publishing happens in the Nebelus console.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceThis MCP server enables AI agents to read MQTT and Sparkplug B data via tools like list_topics, get_latest, and read_all, providing read-only access to latest sensor values.1MIT

RecoSearchofficial
AlicenseNot gradedqualityCmaintenanceA deterministic MCP server that governs read-only queries across multiple data sources, returning answers with full provenance (every row cited) or a typed refusal, ensuring LLM answers are traceable and contract-enforced.1Apache 2.0- AlicenseNot gradedqualityDmaintenanceA governed context layer for internal data exposed over MCP, enabling agents to query governed definitions, retrieve grounded data, and execute scoped actions with citations and auditing.Apache 2.0
- AlicenseBqualityBmaintenanceExposes a deterministic IoT edge runtime — Modbus/CAN/J1939 acquisition, local rules, alarms, and history — to AI assistants as typed, governed MCP tools. Reads are safe by default; device control stays deny-by-default, explicitly confirmed, and audited.233Apache 2.0