Skip to main content
Glama

dsh-sslmanager

SSL certificates for your coding agent. See what is about to expire, issue a replacement, push it to every server, and revoke a leaked one — from the chat, with every state-changing call gated by an approval prompt.

Backed by SetHttps: Let's Encrypt wildcard certificates over DNS-01, deployed to your own servers.

Website DeepSeek Harness License

index.js            native DSH plugin — registers 11 tools on ctx.tools
client.js           Web Client dock panel: certificates expiring soon
cordis.patch.yml    DSH bundle patch (the plugin row + config)
dev/                mock SSLManager API + harnesses, no network needed

Using Codex? The plugin for it lives in codex-sslmanager; this repository is the DSH plugin only.

Why this exists

Certificate expiry is the one failure in a normal web stack that is silent until it is total: nothing degrades, nothing warns, and then every browser refuses to connect at once.

An agent that already reads your repo and your logs is a good place to notice that. But noticing is not fixing — so this plugin also lets it write, to a CA and to live servers, and nothing else:

  • reads are free and safe

  • writes always ask a human first

  • no tool ever returns private key material or server credentials

Related MCP server: sslwebsites

What it looks like

you ▸ what's expiring this month?

     ssl_cert_expiring(days: 30)
     ▸ api.example.com    9 days left   deployed
       shop.example.com  21 days left   deployed
       legacy.example.com 34 days       not deployed

you ▸ renew api.example.com and ship it to the sg node

     ssl_cert_apply(domainName: "api.example.com")
     ⏸ issue a certificate for api.example.com — current one expires in 9 days
       [approve] [reject]

     ssl_cert_deploy(domainName: "api.example.com", remoteId: 3)
     ⏸ deploy api.example.com to edge-sg-01 (203.0.113.10) and reload
       [approve] [reject]
     ▸ uploaded, reloaded, live certificate matches the new serial

Install

DeepSeek Harness (native plugin)

# from the repository
dsh plugin --profile <name> add github:jenawant-rgb/dsh-sslmanager
# or from a local checkout
dsh plugin --profile <name> add /path/to/dsh-sslmanager
# then select the bundle in the profile manifest:
#   dsh.profile.bundles += "@sslmanager/dsh-sslmanager"

The plugin panel accepts the same github: spec.

The row config lives in cordis.patch.yml:

- insert:
    - id: sslmanager
      name: '@sslmanager/dsh-sslmanager'
      config:
        baseUrl: https://sethttps.com     # or http://127.0.0.1:8030 for a local server
        tokenRef: SSLMGR_TOKEN

Codex and other MCP clients

The MCP server lives in the Codex plugin repository so the two packages share nothing: https://github.com/jenawant-rgb/codex-sslmanager.

codex plugin marketplace add jenawant-rgb/codex-sslmanager
codex plugin add sslmanager@sslmanager

Configuration

Key

Default

Meaning

baseUrl

http://127.0.0.1:8030

SSLManager API root. Use https://sethttps.com for the hosted service

tokenRef

SSLMGR_TOKEN

Credential-store entry (or env var) holding the token

usernameEnv / passwordEnv

SSLMGR_USERNAME / SSLMGR_PASSWORD

Fallback login, only used when no token is present

Getting a token

Create a scoped personal access token on the console's 访问令牌 (/token) page, or mint one from the API. The login endpoint is OAuth2 password form encoded, not JSON:

# 1. log in once to get a short-lived token
LOGIN=$(curl -s -X POST https://sethttps.com/api/user/token \
  -d 'username=you@example.com' -d 'password=…' | jq -r .access_token)

# 2. create a scoped token for the agent
curl -s -X POST https://sethttps.com/api/token/ \
  -H "Authorization: Bearer $LOGIN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"dsh","scopes":["cert:read","cert:write","domain:read","deploy:read","deploy:write"],"expires_in_days":90}'

PATs are pinned to the routes and scopes the server allows: they cannot reach /api/user, /api/admin or /api/token, and a write tool without its scope fails with 403.

Resolution order, first hit wins:

  1. config.token — development only, never commit it

  2. the credential-store entry named by config.tokenRef (default SSLMGR_TOKEN)

  3. that same name as an environment variable

  4. username / password login against /api/user/token (read from SSLMGR_USERNAME / SSLMGR_PASSWORD)

A 401 invalidates the cached token and retries once.

Entering the token

The dock panel above the composer is also the setup form: click 设置 → 填入令牌 (or it opens by itself when no credential is stored), paste the ssm_… value and save. The browser posts it to the Harness host, which validates it against SSLManager and writes it to the credential store under SSLMGR_TOKEN; the value is never echoed back or added to the conversation.

Editing ~/.dsh/.credentials.yaml by hand still works:

refs:
  SSLMGR_TOKEN: ssm_…

The panel only appears after a restart, because Web Client modules are composed when the Harness boots. The tools are available immediately.

Tools

Read-only — safe to call at any time:

Tool

Purpose

ssl_cert_list

Certificates with domain, status, expiry, deployment state

ssl_cert_expiring

What expires within N days, soonest first

ssl_cert_get

One certificate's metadata and server-side file paths

ssl_cert_status

Current certificate for a domain (poll after apply)

ssl_domain_list

Tracked domains and their verify / cert / deploy status

ssl_remote_list

Deployment targets with host and certificate paths

ssl_probe

Live TLS probe of any host (issuer, expiry, SANs, self-signed)

State-changing — always behind an approval:

Tool

Effect

Endpoint

ssl_cert_apply

Issue a certificate (renewal is a fresh issuance)

POST /api/certificate/apply

ssl_cert_deploy

Push the current certificate over SFTP + trigger reload

POST /api/certificate/deploy

ssl_cert_revoke

Revoke at the CA — irreversible

POST /api/certificate/revoke

ssl_domain_check

Re-run DNS (_acme-challenge) verification

POST /api/domain/check

No tool returns key_content, cert_content or remote credentials; the projections in toCertificate() and ssl_remote_list drop them defensively.

Safety model

Every state-changing tool goes through authorize():

  1. Harness (approval UI available) — ctx.approval.request() with a one-line summary (Issue an SSL certificate for example.com — expires in 9 days). Only allowed-once proceeds; rejected, cancelled and unavailable abort before touching the API. Request and outcome land in the session audit log.

  2. MCP / headless (no approval UI) — the call is refused unless it carries confirm: true. A model can still set that flag, but the refusal message makes the deliberate step visible in the transcript.

ssl_cert_apply pre-checks that the domain exists and is verified, and fails with the list of known domains otherwise. ssl_cert_deploy checks the remote id against ssl_remote_list before asking for approval.

Web Client panel

client.js registers into conversation.input.dock: a compact strip above the composer showing how many certificates expire within 45 days, expanding into a list with per-certificate days left and deployment state. It refreshes every 10 minutes.

Data comes from an exact GET /api/sslmanager/expiring route registered by the host plugin. The handler calls connection.admit(request) first, so the endpoint uses the same browser-cookie authentication as the rest of the API bridge and is never publicly readable.

Local development

python3 dev/mock_sslmanager.py 8030 &   # fake API: certs, domains, remotes, writes
node dev/harness.mjs                     # all 11 tools, approval allow/reject/absent, leak checks
node dev/mcp-test.mjs                    # JSON-RPC handshake, read + confirm-gated write

The module intentionally imports nothing at runtime: a link:ed install resolves from the checkout directory, where Harness packages such as @deepseek-ai/dsh-tools are not visible. Tool definitions are plain registry definitions with standard JSON Schema.

Roadmap

  • Audit trail of who called what, independent of the Harness session log

  • Per-certificate severity in the client panel, not just a count

  • ssl_cert_deploy is synchronous and can outlast a default tool timeout on a slow SSH target — move it to a job with progress

  • The console page for tokens lives in the SSLManager front end (/token), not in this repository

Hosted service

https://sethttps.com

Docs — quickstart, DNS, Nginx, panels

https://sethttps.com/guide.html

The script that runs on your server (open source)

https://github.com/jenawant-rgb/sethttps-agent

Free tools, no account

SSL expiry check · CNAME check

License

MIT — see LICENSE.


中文说明

给编码助手用的 SSL 证书工具。 在对话里查看哪些证书快到期、签发、推送到服务器、吊销泄露的证书, 所有写操作都会先弹审批。

数据来自 SetHttps:Let's Encrypt 泛域名证书,一条 CNAME 过 DNS-01, 签发后自动分发到你自己的服务器,到期前自动续期。

  • 读操作(7 个工具)随时可用:证书列表、到期筛选、单张详情、DNS 验证状态、部署节点、实时 TLS 探测

  • 写操作(4 个工具)必须审批:签发、部署、吊销、重新验证

  • 不返回私钥、不返回服务器密码;Token 只能访问证书相关路由

安装与配置见上方英文部分。本地调试不需要联网:

python3 dev/mock_sslmanager.py 8030 &
node dev/harness.mjs

文档:https://sethttps.com/guide.html | 服务器端脚本(已开源):https://github.com/jenawant-rgb/sethttps-agent

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables live TLS/SSL certificate health checks for any hostname, providing expiry, hostname match, trust verdict, and a health score. Supports both free and paid deep tiers with protocol/cipher analysis.
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    MCP server for SSL certificate management, enabling agents to issue, renew, revoke, monitor, download, and install certificates, with expiry tracking and webhooks across nine server types.
    52 npm
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to check SSL/TLS certificate validity, expiry, issuer, chain details, and security grade for any domain via pay-per-call x402 micropayments.
    MIT