
rustmistmcp
io.github.mechubsec由 GitHub 账号 mechubsec 发布v0.5.0更新于 Oct 30, 2026
HPE Juniper Mist MCP server: scoped, audited, two-person change control. Rust.
概览
社区版 MCP 服务器,把 HPE Juniper Mist 云暴露给助手,用于在限定范围与审计下读取组织、站点、设备、WLAN、客户端和 WAN 边缘数据。
- 可以做什么
- 读取组织、站点、设备、WLAN、客户端、SLE 指标、事件与诊断信息
- 查看 WAN 边缘网关、应用、BGP 邻居、隧道、对等路径与服务路径事件
- 浏览和搜索操作目录、获取操作结构定义,并调用只读或特权只读调度工具
- 把 WAN 边缘配置变更暂存为带摘要绑定的计划,查看计划、取得第二人审批后应用并校验
- 查看变更集,其中含密钥的字段在到达模型前已被脱敏
- 适用场景
- 适合希望让助手查看 Juniper Mist 环境(站点健康、资产清单、客户端连通性、WAN 边缘与 SD-WAN 遥测)并保持响应有界、留有审计记录的运维人员。也适用于要求 WAN 边缘配置变更必须经过计划、审批、应用流程而非直接写入的场景。
- 运行要求
- 以本地 stdio 进程运行,例如通过 Docker 使用已发布的 OCI 镜像。需要一个 Mist API 令牌,放在由 mist.json 引用的运维自管凭据文件中,并配置组织所在区域的 API 端点与 allowed_orgs 列表。可选设置包括超时、429 重试、站点刷新间隔和工具列表模式。
安装
在 SourceWeft 中
- 打开 控制台中的 rustmistmcp,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
rustmistmcp
Async Rust Model Context Protocol server for the HPE Juniper Mist cloud
a mechub project — sovereign network-security automation
Unofficial / community project. This is an independent community project and does not claim affiliation with or endorsement by Hewlett Packard Enterprise or Juniper Networks. Product names and trademarks are used only to identify the systems with which the software interoperates.
rustmistmcp exposes the Juniper Mist cloud — orgs, sites, APs, switches,
gateways, WLANs, clients, SLE, and Marvis — to MCP clients as a bounded,
auditable tool surface.
Where rustjunosmcp talks
NETCONF to individual SRX devices and
rustpanosmcp talks XML-API to
individual PAN-OS firewalls, this server talks to a multi-tenant cloud control
plane. One org-scoped call can reach every site and every access point in an
estate, so scoping, bounded responses, and change control are not garnish here;
they are the design.
The functional target is the Mist half of
nowireless4u/hpe-networking-mcp
— site health and SLE, device inventory and stats, WLAN/SSID management, client
connectivity, events and alarms, audit logs, RRM and rogue detection, firmware,
NAC/policy, guest access, webhooks, floor plans, and Marvis — reimplemented in
Rust on the mecmcp foundation rather than as a Python spec-driven registry.
That project registers on the order of a thousand generated tools; this one
deliberately will not. A curated, scoped, individually-documented surface is the
whole point of doing it again.
Relationship to mecmcp
mecmcp is the vendor-neutral Rust
foundation shared by the mechub MCP server family. This repository is a
consumer of that foundation, not a fork of it:
Everything that is not specific to the Mist API is upstream. If you find
yourself writing generic auth or transport code here, it belongs in mecmcp.
There is currently no temporary exception: the one the ledger at
docs/UPSTREAM_COMPATIBILITY.md recorded — a
Mist-typed token lifecycle adapter — was deleted when its removal condition was
met. Any new exception must be recorded there with an objective removal
condition.
The API
Mist publishes a versioned REST API under /api/v1, served from per-region
cloud endpoints. The org's home region determines the host:
Additional regional clouds exist; the authoritative list is Juniper's API Endpoints and Global Regions table, and the region must be operator-configured rather than guessed.
The Mist vendor API supports API tokens and external OAuth 2.0. API tokens are
sent as Authorization: Token <token>, may be minted per user or organization,
and inherit the privileges of the account that created them. rustmistmcp v1 intentionally implements API-token authentication only; it does not accept OAuth
credentials. HTTP Basic authentication with Juniper Mist login credentials is
deprecated as of September 2026 and will not be implemented here.
Primary references:
The concrete endpoint map, pagination, and rate-limit semantics are being vetted directly against the live API reference before any client code lands — this README will not restate a surface it has not verified.
Status
Foundation built; read-only live-tenant acceptance passed. The workspace has
an audited operation catalog, strict profile metadata, authorization models, and
a catalog-bound MistClient contract that validates Mist operation inputs and
binds opaque cursors to a configured origin. mecmcp#90 has closed, so
HttpMistClient — the concrete HTTPS implementation over mecmcp-http — is
built by MistHandler::from_config on the production path.
A lab deployment has reached a real Mist org. On 2026-08-10, through a
loopback-bound endpoint and a grant-scoped bearer token, get_mist_self
(getSelf), get_mist_org (getOrg), and list_mist_sites (listOrgSites)
each returned tenant data with result: ok in 92–325 ms. That was issue #11's
gate, and it closed.
What is not done, and must not be described as done:
- That run is not full packaging acceptance. It was loopback-only with no
TLS, one org, one token, three read tools. The checklist in
docs/PACKAGING_ACCEPTANCE.md— TLS hostname and chain, anonymous and bad-bearer rejection, exact Host/Origin enforcement — is not complete. - No
/api/v1/selfstartup identity probe. Theget_mist_selftool works against a live tenant; nothing probes/selfduring startup, andLIVE_MIST_BLOCKERstill names that gap. - Mutations exist only for batch-1 WAN edge objects. Batch-1 covers create
and update for networks, services, service policies, gateway templates, and
device profiles, reachable only through the plan → digest → approve → apply
lifecycle. Delete operations and
mist_configureddevice-profile assignment/unassignment remain out of reach. No live-tenant apply has been performed.
A handler constructed without a credential uses BlockedMistClient, which
performs no I/O; LIVE_MIST_BLOCKER is the message it refuses with.
Outbound Mist timeouts and 429 retries
The retry wait honors Retry-After but never exceeds --mist-max-retry-wait-secs.
Out-of-range values are rejected at startup. A 429 retry wait holds a Mist
concurrency permit, so long waits reduce throughput.
Site discovery
Site-scoped tools refuse any site the handler does not already know (see
"The API"). At startup, the server calls listOrgSites for every allowlisted
org to populate that map before it begins serving. --site-refresh-interval-secs
(default 300) controls a background task that repeats this walk on an
interval, so a site added or removed on the Mist side is picked up without a
restart; 0 disables the background task and discovers once at startup only.
This refresh is idle polling against the operator-configured Mist origin —
listOrgSites requests every site-refresh-interval-secs, independent of
tool traffic, over the same catalog-validated MistClient every other read
uses. It bypasses the per-tool audit trail, since it is a read that updates
internal server state rather than a client-initiated call. A request failure
or hitting the tracked-site ceiling for one org during a refresh keeps that
org's previously known sites rather than dropping them; it does not affect
other orgs' sites.
Shared TokenSecret, cancellation, and changeset primitives are reused, not
rebuilt. Mist header names, catalog policy, request/response schemas, terminal
states, retry classification, and deployment remain in this repository.
Tool listing mode
--tool-mode full|compact (env MCP_TOOL_MODE, default full) controls what
tools/list advertises. compact lists only the catalog dispatchers the caller may see
(search_mist_operations, get_mist_operation_schema, invoke_mist_read,
invoke_mist_privileged_read) to keep the client's tool context small. The
list is still scope-filtered: stdio callers and wildcard-scope tokens see
three, and invoke_mist_privileged_read appears only for a token that
explicitly allows it. It is listing only: every tool stays callable, and token
tool/org/site scopes still authorize each call.
stdio transport
--transport stdio runs the server as a child process of a local MCP client
(Claude Desktop, Claude Code, and similar), speaking MCP over stdin/stdout with
no listening socket. Use it for single-operator, same-machine setups; use
streamable-http for anything shared or remote.
- No bearer-token layer.
--tokens-fileis not read on stdio. The process boundary is the trust boundary: whoever can launch the process is the one caller, recorded in audit and change sets as the principalstdio. Tool, org and site scopes from the token store do not apply; theallowed_orgslist inmist.jsonstill does. Because the planner and approver would both bestdio, self-approval is refused, so a stdio client can plan WAN edge changes but cannot apply them (seedocs/THREAT_MODEL.mdbefore combining stdio with--lab-mode). - Restricted tools are hidden, not blocked.
plan_mist_change,invoke_mist_privileged_read,get_mist_self,search_mist_audit_logsand the rest ofRESTRICTED_TOOLS(crates/rustmistmcp/src/server/mod.rs) are omitted fromtools/liston stdio but remain callable by name. - Never combine stdio,
--lab-mode, and a production-reaching Mist token. Under--lab-modea single stdio agent can plan and apply a WAN edge change against the real org (docs/THREAT_MODEL.md). - Native stdio audit is unredacted unless
--audit-redactand--audit-hmac-key-fileare given; the OCI image's entrypoint supplies both. - The Mist API token still comes from the credential file (or env-var name)
configured in
mist.json, never from the client config. examples/mcp.json.examplehas two client entries: the native binary and the OCI image (arguments matchserver.json). Replace the placeholder paths.- For clients with a small tool budget, add
"--tool-mode", "compact"toargs(see "Tool listing mode").
Pre-release packaging and deployment boundary
The checked-in Docker, archive, systemd, and LXC assets are pre-release
packaging only. A lab LXC built from them has served live read-only tenant
traffic (issue #11), which is not the same as packaging acceptance: that run
used no TLS and no off-loopback bind, so the TLS, Host/Origin, and bad-bearer
rows of docs/PACKAGING_ACCEPTANCE.md remain unproven. The /api/v1/self
startup probe is unimplemented, and mutations exist only for batch-1 WAN edge
objects behind the change-set lifecycle; no live-tenant apply has been performed.
No v1 release label may be claimed until that checklist is complete.
The OCI image is a multi-stage build with a digest-pinned Rust builder and a
digest-pinned distroless Debian 13 runtime. It runs only
/usr/local/bin/rustmistmcp as UID/GID 65532; the runtime image has no shell,
package manager, or runtime fetcher. Its CA data comes from the distroless base.
Use an immutable image digest, never a mutable tag. The supplied compose example
is read-only, drops every capability, uses no-new-privileges, bounds PIDs and
/tmp, mounts /etc/rustmistmcp read-only, and mounts
/var/lib/rustmistmcp read-write. Do not place Mist or bearer secrets in image
layers, compose environment, or command arguments.
The checked-in service and OCI command use the shared CLI's exact loopback HTTP
contract: /etc/rustmistmcp/mist.json, the bearer store, port 30030, JSON
audit with HMAC redaction, and direct journald delivery for systemd. OCI audit
goes to JSON stderr and does not mount the host journal socket. There is no
mutation-state flag or live-Mist readiness check. --version reports this
binary's name and version now that mecmcp#159 has closed, so release identity
is verified with --version, --help, BUILD-INFO, and artifact/deployed
SHA-256 values.
The compose example is Linux-only: host networking makes the container's
127.0.0.1:30030 listener reachable from the same host without exposing it on
an external interface. Before starting it, make the bind-mounted state and
secret files accessible to numeric UID/GID 65532:
Populate the Mist API token before handing ownership to UID/GID 65532, and
before up: once ownership moves, an unprivileged operator can no longer
write it, and the credential loader rejects an empty token at startup. Do
this without placing the value in an environment variable, command argument,
image layer, or Compose file.
Grant-bearing MCP bearer-token add/list/revoke/rotate is the shared
token_cmd::run_with_grant; the private Mist-typed adapter that once bridged it
is deleted. New tokens created by token add remain grantless; the shared
command preserves existing validated MistGrant values. This bearer-token store
is separate from the Mist API token used by the outbound client.
Docker container guide
See docs/HOW-TO-SETUP-DOCKER.md for step-by-step instructions on running rustmistmcp in Docker, including the audit configuration requirement and two-person vs lab mode setup.
LXC operator prerequisites
See docs/HOW-TO-SETUP-LXC.md for a step-by-step build guide.
Security review documents
docs/THREAT_MODEL.md— trust boundaries, security principals, blast radius of a compromised token or agent against a real Mist org, and mitigations in place vs. planned.docs/TOKEN_ROLE_GUIDANCE.md— why the outbound Mist API token should be a dedicated, least-privilege organization token rather than a personal or super-admin token.
Deploy only in a dedicated Debian 13 unprivileged LXC with nesting=1.
nesting=1 is required for the target systemd version to report healthy mounts.
The guest cannot prove the host-side unprivileged and nesting settings. Verify
them in authorized host inventory, then explicitly attest them to the installer
with RUSTMISTMCP_LXC_HOST_PROOF=unprivileged=1,nesting=1; it also refuses
non-Debian-13 and non-LXC hosts.
Do not contact Proxmox or a Mist tenant as part of package construction. The lab
acceptance gate, if separately authorized, must first prove that VMID 613 and
its address are unused and must target only a newly provisioned 613 LXC; never
operate VMID 612 or snapshot an unrelated guest.
The archive installer validates its checksum and full archive layout before any
mutation, refuses to clobber live configuration, secrets, state, or a customized
unit (unless RUSTMISTMCP_FORCE_UNIT=1 is set), and does not enable the service.
Use packaging/lxc/install.sh --validate-only ARCHIVE ARCHIVE.sha256 without
root for a non-mutating preflight.
It installs non-live examples as /etc/rustmistmcp/mist.example.json and
/etc/rustmistmcp/tokens.example.json. Configure live files manually:
Persistent journald is bounded to 512 MiB. Configure remote journal/SIEM
forwarding before real traffic. File-audit startup is fail-closed
(mecmcp#158): an unopenable --audit-log-file fails startup rather than
degrading silently, and journald remains the delivery baseline. Graceful HTTP
shutdown (mecmcp#156) is wired — SIGTERM and SIGINT cancel the listener, which
waits up to 10 seconds for in-flight requests — but that is the configured
behaviour, not a drain verified under load. Any external bind requires TLS plus exact allowed Host and Origin
configuration; the default deployment posture is loopback only.
For each release candidate, build from a clean tree with
scripts/build-release.sh; it writes a deterministic
rustmistmcp-v<VERSION>-<TARGET_TRIPLE>.tar.gz, sidecar SHA-256, and
BUILD-INFO. Measure the produced binary's glibc floor before deployment:
Release CI produces checksums, an SBOM, provenance, linux/amd64 OCI
images, and an immutable digest record. Refresh the upstream reference/spec once
at RC, regenerate the catalog, review the delta, and require zero parity gaps
before any separate deployment acceptance.
Next, in order:
- Implement the
/api/v1/selfstartup identity probe. The outboundHttpMistClientit needs already landed withmecmcp#90, and theget_mist_selftool proves the call itself works against a live org. - Finish the rest of
docs/PACKAGING_ACCEPTANCE.md— TLS, off-loopback Host/Origin enforcement, anonymous and bad-bearer rejection — none of which the loopback read-only run in issue #11 exercised. - Add mutations only behind
mecmcp-changeset, never as direct writes. Designed in issue #14; theexecutesplit landed asexecute_class.rs.
Design commitments
- Curated, not generated. Tools are chosen and documented by hand. A thousand auto-registered endpoints is a search problem handed to the model, not a capability.
- Read before write. Every mutating tool is reachable only through a plan → digest → approve → apply lifecycle. No tool writes to an org on a single unattested call.
- Scoped tokens. Bearer tokens carry explicit tool, org, and site scopes; an unscoped token is a configuration error, not a convenience.
- Bounded I/O. Request and response sizes are capped. A cloud control plane will happily hand back an estate-sized payload; the server will not.
- Auditable by construction. Attribution and redaction come from
mecmcp-audit, so every call is traceable to a caller without leaking credentials into logs. - No secrets in the repo. Mist API tokens live in operator-managed files outside version control. v1 does not accept OAuth client secrets.
- Device secrets redacted before the model sees them. WLAN PSKs, RADIUS/SNMP
shared secrets, and API keys/tokens returned by Mist are stripped via
mecmcp-redactat every model-facing read, change-set preview, and plan response. This is a denylist match on known credential-shaped fields, not a cryptographic guarantee -- it is best-effort against shapes the denylist does not yet cover, not a safe place to store secrets in a freeform field.
WAN edge tools
The server exposes a curated read surface covering organizations, sites, devices,
WLANs, clients, SLE, events, and diagnostics. The WAN edge subset listed below
targets SRX/SSR gateways and their overlay connectivity. See KNOWN_TOOLS in
crates/rustmistmcp/src/server/mod.rs for the full tool registry.
Audit forwarding to the event store
The audit trail does not stay on this host. This server follows the family standard — AUDIT-FORWARDING-STANDARD.md.
An audit record that only exists on the machine that produced it is not an audit trail: it is a log file on a box whose operator is the party the record is about.
Emission (in effect now)
JSON is mandatory. The text format is for reading in a terminal and is not a
parse target. The file is the operator-facing artifact and must be rotated — the
server never truncates it.
Transport (specified, not yet implemented)
Records are written directly into SSDF's ssdf.audit as hash-chained rows,
per SSDF's merged evidence contract, so that deleting or editing a row is
detectable. Tracked in mecmcp#292.
A cheaper syslog path was designed and rejected: it works, but the records are
unchained, and every other link here is tamper-evident by construction — plan
digests bind approvals, approvals name a distinct principal, and
token_verified_fields separates vouched-for provenance from asserted. An
unchained final hop would discard that guarantee exactly where an auditor needs
it. The reasoning is recorded in the standard.
Reading the result
token_verified_fields names the provenance fields the token vouched for.
The rest of that group — client_name, model_id, session_id — is
client-asserted and authenticated by nothing. Do not read them as equivalent.
request_id correlates the transport event, the handler event, and (on Junos)
the device commit comment.
License
Licensed under MIT.
--lab-mode
--lab-mode waives the second principal, for a single-operator lab where two-person control is theatre rather than a control. It is off by default and should stay off anywhere the estate matters.
What it does and does not change:
- The waiver is applied automatically when the change set is created. There is no waive tool, and the flow stays prepare → apply, identical to production.
- Planning, the plan digest, drift detection, and apply-time revalidation all still run. Lab mode removes the second reviewer, not the change record.
- No approver is ever fabricated. A waived change set records
approver: nullin the approval record alongsidewaived: { reason: "lab-mode" }. It is cryptographically distinguishable from a genuine two-person approval and cannot be relabelled afterwards — which matters if anyone later has to prove which changes had real separation of duties. - The server warns loudly at startup whenever it is enabled.
If you want solo write-testing without waiving the control, mint two tokens with different names and use one to prepare and the other to approve: the principal is the token name, and self-approval is refused. That gives one person the complete lifecycle with the control intact, and is the better choice wherever the ceremony has any value.
Enabling it
Add the flag to the service unit. On a package install, use a drop-in rather than editing the shipped unit, so an upgrade does not silently drop it:
Replacing ExecStart means restating it in full, so copy the shipped command and append the flag rather than writing a shorter one:
Confirm it took effect by checking the audit log for the startup warning:
You should see: lab mode enabled: change sets are approved on creation with no second principal. Records carry approval_waiver=lab-mode. Do not run this against production devices.
来源:README.md,提交 6fc2466
工具
0版本历史
2- v0.5.0最新Oct 30, 2026
- v0.4.0Oct 13, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分