
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 分