
rustsdcmcp
io.github.mechubsec由 GitHub 账号 mechubsec 发布v0.6.0更新于 Oct 30, 2026
Juniper Security Director Cloud MCP server: scoped, audited change control. Rust.
概览
社区版 MCP 服务器,把 HPE Juniper Security Director Cloud 暴露给助手,用于有范围限制、可审计的读取与受变更管控的 SRX 策略操作。
- 可以做什么
- 读取 SDC 清单与策略:列出和获取设备、防火墙策略、NAT 策略及通用 SDC 资源,并查看租户范围
- 查看变更与作业状态:预览和部署状态、按设备的预览与部署结果、变更集详情
- 通过双主体变更集流程准备、批准并应用策略部署
- 读取证书、许可证与模板,并把设备清单同步进 SDC
- 可作为本地 stdio 子进程运行(只读),或作为仅监听回环地址的 streamable-HTTP 服务运行并使用带范围的 bearer 令牌
- 适用场景
- 适合通过 Juniper Security Director Cloud 管理 SRX 设备群的运维人员,让助手查看设备与策略,或起草策略变更并由第二个主体批准后再应用。定位是实验或受控部署,而非日常桌面使用。
- 运行要求
- 需要本地运行环境:已发布的 linux/amd64 容器镜像、Debian 13 LXC 安装包,或自行用 Rust 构建(工具链固定为 1.99.0)。需要 SDC 租户 ID 和 SDC API 令牌,令牌通过 credential_env 指定的变量提供(示例中为 SDC_API_TOKEN);配置文件权限须为 0640 或更严格;需能通过 HTTPS 访问 SDC API 端点;写入还需 streamable-HTTP 传输和带范围的 bearer 令牌。
安装
在 SourceWeft 中
- 打开 控制台中的 rustsdcmcp,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
rustsdcmcp
Async Rust Model Context Protocol server for HPE Juniper Security Director 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.
rustsdcmcp exposes HPE Juniper Security Director Cloud (SDC) to MCP
clients as a bounded, auditable tool surface. SDC is the HPE Juniper SASE
portal for an SRX estate, so this server talks to that management plane rather
than to any single firewall. Where
rustjunosmcp talks NETCONF to
individual SRX devices, rustsdcmcp talks HTTPS REST to the portal that governs
them.
That distinction has a large blast radius: one SDC action can affect many managed SRX devices. Strict approval, credential-safe attribution, and bounded I/O therefore protect the management plane rather than merely decorate it.
Current status
rustsdcmcp exposes 80 MCP tools (v0.6.0 and main; v0.3.1 shipped 78; v0.2.0 shipped 74): 60 bounded read
tools and 20 change-control tools. The surface
covers the part of the SDC API that manages SRX devices and their policy; the
rest of the product's API is deliberately out of scope.
Every mutation is reachable only through prepare → independent approval → apply. A wildcard token scope deliberately grants no write tool, so each must be named explicitly when a token is minted.
Live validation against SDC has gone well beyond read-only. On 2026-08-07 a
full prepare → approve → apply policy deploy ran against the lab tenant and
reached a managed vSRX, which is how the co-management behaviour in #23 was
discovered: within hierarchies SDC owns, objects not reachable from a policy
SDC imported are deleted on deploy. Interfaces, routing, system, and the
management instance were untouched. The full boundary and the observed diff are
in docs/operations.md. JobStatus and
DeviceStatusEntry are validated against live preview and deploy responses.
On 2026-08-12 the certificate and licence readers, BulkSyncDevices, and the
template endpoints were exercised live. Device sync imports into SDC rather
than pushing to the device, but reconciles inventory only and does not clear
device_config_state: OUT_OF_BAND_CHANGED.
Read-path security properties were last verified live on 2026-08-07 against
commit ea81805d2b4b97df9bdd3f70423e047524896a3d with mecmcp v0.5.0. The
transport and scope preflight were replaced afterwards in e28d0cc and
369f9bb, so that result no longer speaks for current main; no lab SDC
tenant was available to repeat it live. On 2026-10-06, against commit
2036523 with mecmcp v0.26.0, the automated integration suite was re-run
instead — cargo test --workspace, 258 passed, 0 failed — which covers:
requests with a missing bearer are refused
(crates/rustsdcmcp/tests/http_boundary.rs::router_requires_bearer),
out-of-scope tenants are refused
(crates/rustsdcmcp/tests/http_boundary.rs::out_of_scope_tenant_is_refused),
exact tool and tenant scope enforcement with read/write tool disjointness
(crates/rustsdcmcp/src/server.rs scope unit tests,
crates/rustsdcmcp/tests/tool_contract.rs), and secret-key redaction of
responses (crates/rustsdcmcp-core/src/redact.rs unit tests). The remaining
properties from the 2026-08-07 live audit have not been re-verified on
current main; this run is not a substitute for the live-tenant exercise and
does not re-establish one.
Observed response shapes and the remaining endpoint questions are tracked in
docs/sdc-api/README.md.
Download
The current release, v0.6.0,
attaches a checksummed, cosign-signed LXC install tarball
(rustsdcmcp_0.6.0_amd64.tar.gz) as a release asset. Download and verify it,
or build from approved source below.
A linux/amd64 container image is published for that tag to
ghcr.io/mechubsec/rustsdcmcp:0.6.0 and is publicly pullable with no
authentication.
Build from approved source
rust-toolchain.toml pins the build toolchain at 1.99.0; the declared MSRV in
Cargo.toml is 1.89. Operators must bind their checkout to the commit they
intend to ship before building, testing, or packaging — the release tag is the
usual choice:
In that configuration, credential_env names the external process variable;
the credential itself never belongs in JSON. For a local commit-addressed
package, verify the newly built archive and its embedded BUILD-INFO from the
approved commit directory—never glob across dist/ because the checksum
records only the archive basename:
Local stdio client
--transport stdio (the default) runs the server as a child process of the
MCP client, with no listening socket and no bearer token.
examples/mcp.json.example is a .mcp.json
entry for that. Copy examples/sdc.example.json to the --device-mapping
path, fill in the tenant, and chmod 0600 it: the server refuses a config file
more permissive than 0640. --state-file overrides the config's
/var/lib/rustsdcmcp/changeset-state.json, which a desktop user cannot
normally write.
The credential reaches the server through the variable that credential_env
names (SDC_API_TOKEN in the example). ${SDC_API_TOKEN} is expanded from the
client's environment, so the token stays out of the JSON file. A client that
does not expand ${...} needs the variable exported in the environment it is
launched from.
A stdio caller is unauthenticated, so every write tool (prepare, approve, apply) refuses it: stdio is a read-only surface. Change-controlled writes need the streamable-HTTP transport with a scoped bearer token.
Tool listing mode
--tool-mode full|compact (env MCP_TOOL_MODE, default full) controls what
tools/list advertises. compact lists only list_sdc_resources,
get_sdc_resource, get_sdc_tenant_scope and the change-set tools
(get_sdc_change_set, get_sdc_change_set_details, approve_sdc_change_set,
apply_sdc_change_set) to keep the client's tool context small. It is listing
only: it composes with token scopes and never widens them, every tool stays
callable, and the token's tool and tenant scopes still authorize each call.
Docker quick start
For running the published container image, see HOW-TO-SETUP-DOCKER.md.
Debian 13 LXC quick start
For building an LXC from scratch, see HOW-TO-SETUP-LXC.md.
Prerequisites:
- Debian 13 AMD64; an unprivileged LXC is recommended.
- 1 vCPU, 512 MiB RAM, 512 MiB swap, and 4 GiB disk for the minimum profile.
- Working DNS and time synchronization, plus outbound HTTPS to
api.sdcloud.juniperclouds.net. - Root or equivalent operator access inside the LXC.
Download the signed v0.6.0 release tarball (or build one from approved
source — see Build from approved source above)
and install the verified package:
Create the configuration and credential file without exposing a credential:
sdc.json must retain the HTTPS SDC endpoint, use the desired local tenant
alias, and set expected_tenant_id to the operator-obtained SDC tenant ID. The
credentials file contains one shell-compatible assignment using the name from
credential_env, for example SDC_API_TOKEN=...; never put a real value in
the README or JSON.
Create the initial exact 14-tool read-only grant. The redirect destination must
already be mode 0600; the output is a one-time bearer token.
Start the service and access it through an authenticated SSH tunnel:
The expected listener is only 127.0.0.1:30032. While the tunnel is active,
the local MCP client uses http://127.0.0.1:30032/mcp. Each installation
supplies its own SSH host; the server is never exposed directly.
Security commitments
- External credentials use restrictive file modes and never belong in JSON.
- Startup verifies the configured identity against
expected_tenant_id. - Bearer tokens carry exact tool and tenant scopes.
- Request, response, and page sizes are bounded.
- Audit attribution is credential-safe and target values receive HMAC redaction.
- Mutations require two-principal prepare → approve → apply change control.
- There is no direct deploy tool and no unauthenticated write path.
- A wildcard token scope grants no write tool.
--tools '*'yields the read surface only; every write tool must be named explicitly when minting a token.
Detailed deployment, recovery, audit-retention, and write-workflow guidance is
in docs/operations.md.
--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: nullalongsideapproval_waiver: "lab-mode", and carries a waiver digest over(change_set_id, plan_digest, owner, approved_at). 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. Dropping the
--audit-* arguments would turn off HMAC target redaction and structured
journald auditing as a side effect of enabling lab mode:
Check it against packaging/systemd/rustsdcmcp.service before applying it — the
shipped arguments are the authority, and this snippet is a copy that can age.
Confirm it took effect. The two startup records use different spellings —
--lab-mode in the warning and lab_mode in the resolved-configuration line —
so match both, and read the journal with enough privilege to see a system unit:
Silence means it is off. An unprivileged journalctl can also print nothing
here for lack of access rather than because the flag is unset, which is why the
command uses sudo.
A waived change set then reports "state": "approved" with "approver": null
and "approval_waiver": "lab-mode" straight out of prepare_sdc_policy_deploy,
and apply_sdc_change_set needs no separate approval call.
For a one-off run rather than a service, pass --lab-mode on the command line
the same way.
Precedence
--lab-mode is part of mecmcp's shared change-set CLI standard, alongside
--state-file and --approval-timeout-secs. For those other two, an
explicitly supplied flag wins and sdc.json supplies the value otherwise
(changeset_state_file, approval_ttl_secs).
--lab-mode is CLI-only. There is no sdc.json field for it, deliberately:
a relaxed security control should have to be typed into the unit an operator can
see, not inherited from a configuration file edited months ago. Whether the
shared standard permits a product-config fallback is an open upstream question
(mecmcp#267); this server takes the conservative reading.
Deployment maturity
The Debian 13 package has been installed and run end to end from the
commit-addressed archive built by CI for
ea81805d2b4b97df9bdd3f70423e047524896a3d. It starts under the packaged
rustsdcmcp.service unit as a non-root account, binds a loopback-only
endpoint, enforces the bearer boundary, and passes the startup tenant-scope
check against live SDC.
One packaging limit is worth stating plainly: the unit's IPAddressAllow and
IPAddressDeny lines take effect only where the host lets systemd attach its
cgroup BPF program, which is runtime-dependent. On the validated deployment the
installer probe reported NOT ENFORCED, so egress had to be enforced outside
the unit; every other sandbox directive still applied. Follow the probe's
result on your own host rather than assuming either way. Deployment, recovery,
audit-retention, and the per-runtime egress mechanism are in
docs/operations.md.
Specific hosts, addresses, and container identifiers are deliberately not published here; each operator supplies their own.
Roadmap
See ROADMAP.md for current coverage, planned expansion, and features blocked on upstream API support. Feature requests are welcome as GitHub issues.
Relationship to mecmcp
mecmcp is the vendor-neutral Rust
foundation shared by the mechub MCP server family. This repository consumes it,
rather than forking it. main pins all eight shared crates — mecmcp-audit,
mecmcp-auth, mecmcp-changeset, mecmcp-redact, mecmcp-runtime,
mecmcp-secret, mecmcp-server, and mecmcp-transport — to v0.31.0.
The compatibility blocker is cleared. Earlier revisions of this section
said a release was blocked until 59 temporary compatibility declarations were
replaced by one coherent upstream release. That happened: the local compat/
layer was deleted in #36 on the move to mecmcp 0.7.2, and the compatibility
ledger itself was removed in 369f9bb on the move to 0.8.0. There are no
temporary compatibility symbols left, and no ledger to track.
API provenance
The API surface is pinned from Juniper's OpenAPI 3 export, vendored in
docs/sdc-api/. It is the authoritative inventory of
the supported SDC API surface and its remaining open questions.
Primary references:
- Security Director Cloud API Reference
- API Security Overview
- Security Director Cloud documentation portal
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
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. This is implemented: the server wires an
EvidenceService/EvidenceHttpTransport pair at startup when evidence
forwarding is configured (crates/rustsdcmcp/src/main.rs), landed as the
SSDF evidence pipeline 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.
来源:README.md,提交 3bb9e57
工具
0版本历史
4- v0.6.0最新Oct 30, 2026
- v0.5.1Oct 29, 2026
- v0.4.1Oct 22, 2026
- v0.3.1Oct 16, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分