Jabali Panel

io.github.shukiv由 GitHub 帳號 shukiv 發布v0.6.1更新於 Nov 1, 2026

Manage domains, DNS, mail, databases and backups on a Jabali Panel hosting server.

概覽

AI 產生的概覽

本機 MCP 伺服器,讓助理透過 Jabali Panel 的 REST API 管理主機服務上的網域、DNS、郵件、應用程式、資料庫與備份。

可以做什麼
  • 列出並檢視網域、DNS 記錄、信箱、轉寄、應用程式、資料庫、備份、排程工作、SSH 金鑰、PHP 設定、SSL 狀態、日誌與磁碟用量
  • 執行整合式網域診斷,彙整設定、SSL、DNS、近期錯誤與頻寬,並可查詢官方面板文件
  • 建立與更新網域、DNS 記錄、信箱、轉寄、備份、應用程式、資料庫、排程工作、SSH 金鑰與 PHP 設定(僅寫入模式)
  • 刪除、還原、撤銷或輪替資源,皆先回傳預覽,需帶 confirm 再次呼叫才執行
  • 可選擇開放使用者、伺服器設定與面板更新的管理工具,並可在多面板模式下指定某一台面板
適用情境
適合執行 Jabali Panel 主機服務、希望用自然語言讓助理查看或修改主機設定而不必手動操作面板的人。建議先以唯讀模式做診斷與巡檢,確有需要變更時再開啟寫入模式。
執行需求
本機二進位程式(預先編譯版本、go install 或以 Go 1.25+ 從原始碼建置),由 MCP 用戶端透過 stdio 啟動。需要可連線的面板 API 位址(JABALI_PANEL_URL)與 jat_ API 權杖(JABALI_API_TOKEN),或由 init 指令產生的 panels.json。選用:JABALI_CA_FILE、JABALI_MCP_ALLOW_WRITE、JABALI_MCP_DRY_RUN、JABALI_MCP_ADMIN、JABALI_PANELS_FILE。
安裝前請注意
它直接操作主機控制面:寫入工具預設關閉,需 JABALI_MCP_ALLOW_WRITE=1;破壞性工具需 confirm: true,初期建議開啟 dry-run。請使用非管理員的租戶權杖;JABALI_MCP_ADMIN=1 會開放整機層級操作並需要管理員權杖。preview_file 可能把 wp-config.php 等機密讀入對話,建立資料庫使用者與輪替密碼會一次性回傳明文密鑰。權杖透過環境變數傳入。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Jabali Panel,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

jabali-mcp

A Model Context Protocol server for Jabali Panel.

Install  |  Set up  |  Tools  |  Safety  |  Generation

[Working MVP] [Go 1.25] [MCP stdio] [AGPL-3.0]

Lets an AI assistant drive panel operations — domains, DNS, mail, applications, databases, backups — through natural language. It's a thin, generated wrapper over the panel's existing REST API: it reimplements no auth, validation, or scoping, it rides them.

Status: working MVP. Read tools + gated write/destructive tools + a fleet registry, generated from the panel's OpenAPI spec (a golden test fails if the checked-in code drifts from the spec).

Install

Prerequisites: Go 1.25+ and a reachable Jabali Panel with an API token (see Set up). The server speaks MCP over stdio — an MCP client (Claude Code, Claude Desktop, …) launches it; you don't run it as a daemon.

Prebuilt binaries

Grab the binary for your platform from the latest release (linux/darwin × amd64/arm64, with SHA256SUMS), then:

sh
chmod +x jabali-mcp_*_linux_amd64sudo install -m 0755 jabali-mcp_*_linux_amd64 /usr/local/bin/jabali-mcp

With go install

sh
go install github.com/shukiv/jabali-mcp/cmd/jabali-mcp@latest

The binary lands in $(go env GOBIN) (or $(go env GOPATH)/bin).

From source

sh
git clone https://github.com/shukiv/jabali-mcp.gitcd jabali-mcpmake build            # -> ./jabali-mcp  (stamps the version from git describe)

Update

sh
jabali-mcp update --check        # report the latest release, install nothingjabali-mcp update                # re-installs the latest (go install …@latest)jabali-mcp update --ref v1.2.3   # pin a tag/commitjabali-mcp update --dry-run      # print the command only

Self-update runs go install, so it needs Go on the PATH. Restart your MCP client afterward to pick up the new binary. (Installed from a checkout instead? git pull && make build. Installed a prebuilt binary? Download the new release.)

Verify

sh
JABALI_PANEL_URL=https://panel.example:8443/api/v1 \JABALI_API_TOKEN=jat_… \jabali-mcp < /dev/null# -> jabali-mcp <version> — read-only; panels: [default]

It reads config from the environment, prints a one-line status to stderr, then serves MCP on stdin/stdout (it exits on EOF, which is why the < /dev/null smoke test returns immediately).

Set up

Quickest: the guided walkthrough

sh
jabali-mcp init

It prompts for each panel (name, URL, token), verifies the token against the panel, and writes a 0600 panels.json to your config dir (~/.config/jabali-mcp/panels.json). Add as many panels as you like — one for a single instance, several for a fleet. Because that path is the default, the server finds it with no env vars, so registering with a client is just:

sh
claude mcp add jabali -- jabali-mcp        # no --env needed after init

Re-run init any time to reconfigure. The manual steps below are the same thing by hand.

Manual

1. Mint an API token. In the panel, go to the tenant shell → API Tokens and create one. The plaintext jat_… is shown once — copy it. Use a non-admin (tenant) token so the server is confined to that one account.

2. Point the server at your panel with these environment variables:

VariableRequiredMeaning
JABALI_PANEL_URL✓e.g. https://panel.example:8443/api/v1
JABALI_API_TOKEN✓the jat_… bearer token
JABALI_PANEL_NAMElogical name (default default)
JABALI_CA_FILEPEM bundle to trust a self-hosted panel CA
JABALI_MCP_ALLOW_WRITE1 to enable mutating tools (default: read-only)
JABALI_MCP_DRY_RUN1 to force every write to preview instead of act
JABALI_MCP_ADMIN1 to also expose the /admin/* tools (needs an admin token)
JABALI_PANELS_FILEJSON array of panels for fleet mode (overrides the single-panel vars)

3. Register it with your MCP client. In every example below jabali-mcp is assumed on your PATH (else use its full path), and the two required env vars are shown inline. It's a stdio MCP server, so any MCP-capable client can launch it.

Claude Code (CLI — writes .mcp.json / your Claude config):

sh
claude mcp add jabali \  --env JABALI_PANEL_URL=https://panel.example:8443/api/v1 \  --env JABALI_API_TOKEN=jat_… \  -- jabali-mcp

Claude Desktop — claude_desktop_config.json:

json
{  "mcpServers": {    "jabali": {      "command": "jabali-mcp",      "env": {        "JABALI_PANEL_URL": "https://panel.example:8443/api/v1",        "JABALI_API_TOKEN": "jat_…"      }    }  }}

OpenAI Codex (CLI — writes ~/.codex/config.toml):

sh
codex mcp add jabali \  --env JABALI_PANEL_URL=https://panel.example:8443/api/v1 \  --env JABALI_API_TOKEN=jat_… \  -- jabali-mcp

or edit ~/.codex/config.toml by hand — note it's TOML, and the key is mcp_servers (underscore), not the JSON mcpServers:

toml
[mcp_servers.jabali]command = "jabali-mcp"
[mcp_servers.jabali.env]JABALI_PANEL_URL = "https://panel.example:8443/api/v1"JABALI_API_TOKEN = "jat_…"

OpenCode — opencode.json:

json
{  "$schema": "https://opencode.ai/config.json",  "mcp": {    "jabali": {      "type": "local",      "command": ["jabali-mcp"],      "environment": {        "JABALI_PANEL_URL": "https://panel.example:8443/api/v1",        "JABALI_API_TOKEN": "jat_…"      },      "enabled": true    }  }}

Kimi Code CLI (writes ~/.kimi/mcp.json):

sh
kimi mcp add --transport stdio jabali \  -e JABALI_PANEL_URL=https://panel.example:8443/api/v1 \  -e JABALI_API_TOKEN=jat_… \  -- jabali-mcp

Cursor, Windsurf, Cline, Gemini CLI, and other clients that use the standard mcpServers JSON take the same entry as Claude Desktop above — a { "command": "jabali-mcp", "env": { … } } block under mcpServers in that client's config file.

Start read-only. When you want mutations, add JABALI_MCP_ALLOW_WRITE=1 to the env (and, at first, JABALI_MCP_DRY_RUN=1 to watch what it would do).

Run it on a remote box over SSH

Because it speaks stdio, any of the above can launch it on a remote host over SSH instead of locally — the tool stream tunnels through the SSH pipe. Set the client's command to ssh and pass the remote invocation as its argument, e.g. for Claude Desktop:

json
{  "mcpServers": {    "jabali-prod": {      "command": "ssh",      "args": ["operator@box",        "JABALI_PANEL_URL=https://localhost:8443/api/v1 JABALI_API_TOKEN=jat_… jabali-mcp"]    }  }}

On the box the panel API is reachable at localhost, and the token still scopes everything to its user. Nothing to install client-side beyond an SSH key.

Fleet (multiple panels)

The easiest path is jabali-mcp init — add several panels when it asks "Add another panel?". It writes them to the default panels.json, which the server loads automatically.

Equivalently, point JABALI_PANELS_FILE at a JSON array (this overrides the single-panel vars), or write that array yourself:

json
[  { "name": "prod-a", "url": "https://a:8443/api/v1", "token": "jat_…" },  { "name": "prod-b", "url": "https://b:8443/api/v1", "token": "jat_…" }]

Config resolution order: JABALI_PANELS_FILE → single-panel env (JABALI_PANEL_URL + JABALI_API_TOKEN) → the default panels.json. In a fleet, every tool takes an optional panel argument to pick one; omit it for the first (default) panel.

Admin tools (same binary, separate opt-in)

The admin operator surface (list/create users, read/update server settings, run panel updates and read their status) lives in the same binary but a separate registration group, exposed only with JABALI_MCP_ADMIN=1. It fronts whole-box operations — a far larger blast radius than the tenant tools — so it is deliberately opt-in and requires an admin token (the panel's RequireAdmin rejects a non-admin token with 403 regardless of the flag). Admin write tools still need ALLOW_WRITE, and admin_run_updates is confirm-gated. admin_renew_ssl and admin_retry_ssl also live here: their paths look tenant-scoped, but the panel registers them behind RequireAdmin. Give the admin server its own admin token; use tenant tokens for everything else.

Auth model — inherits the panel's tenant isolation

Tools authenticate with the per-user Bearer token. The token acts as its owning user and the panel enforces ownership on every endpoint, so the server can only ever reach the resources that token's user owns — a tenant token is confined to that tenant. That is why a non-admin token is the safe default.

Safety

This fronts a hosting control plane, so mutation is fenced in four layers:

  1. Read-only by default. Write tools register only with JABALI_MCP_ALLOW_WRITE=1.
  2. Destructive tools require confirm: true. Every delete_* / revoke_* / rotate_*_password tool (plus restore_backup, disable_ssl) returns a preview and acts only when re-called with confirm: true. A model cannot destroy state in one step — the guard against a prompt-injected tool call.
  3. Tool hints. Read tools carry readOnlyHint; destructive tools carry destructiveHint so clients can surface the risk.
  4. Dry-run. Any write tool accepts dry_run: true to return the exact request it would send without acting; JABALI_MCP_DRY_RUN=1 forces that globally.

TLS verification is always on. To trust a self-hosted panel's private CA, point JABALI_CA_FILE at its bundle — that adds the CA, it never disables verification.

Tools

Full per-tool reference with arguments and constraints: docs/TOOLS.md (generated — make docs).

Read (always on): list_domains, get_domain, list_dns_records, list_mailboxes, list_forwarders, list_applications, list_databases, list_backups, list_api_tokens, list_mail_logs, tail_web_log, get_ssl_status, get_domain_whois, get_domain_bandwidth, whoami, get_disk_usage, list_activity, list_cron_jobs, get_cron_job, get_cron_log, list_app_catalog, get_application, get_database, list_database_users, get_mailbox, get_autoresponder, get_backup_manifest, list_ssh_keys, get_php_settings, list_php_versions, list_files, preview_file — plus the composite diagnose_domain (config + SSL + DNS + recent errors + bandwidth in one answer; a failed probe is reported without failing the rest) and report_issue (draft a bug report / feature request for the jabali-panel or jabali-mcp GitHub repo as a prefilled link; in write mode it can also file it directly via gh, gated by confirm: true) and search_docs (look up the official panel documentation from jabali-panel.com mid-task — anonymous, origin-restricted fetches; override the source with JABALI_DOCS_URL).

preview_file reads file contents (up to 1 MiB) into the conversation — that can include secrets such as wp-config.php. create_database_user and the rotate_*_password tools return the plaintext secret once, by panel design.

Write (needs JABALI_MCP_ALLOW_WRITE=1): create_domain, update_domain, create_dns_record, update_dns_record, create_mailbox, create_forwarder, create_backup, install_application, create_database, enable_ssl, create_cron_job, update_cron_job, run_cron_job, create_database_user, grant_database_access, update_mailbox, set_autoresponder, add_ssh_key, update_php_settings — plus the confirm-gated destructive set: delete_domain, delete_dns_record, delete_mailbox, restore_backup, disable_ssl, delete_cron_job, delete_application, delete_database, delete_database_user, revoke_database_access, rotate_database_password, delete_autoresponder, rotate_mailbox_password, delete_backup, delete_ssh_key.

Tool generation

Tools are generated, not hand-written, so the surface can't drift from the API:

  • openapi/openapi.yaml — vendored copy of the panel's spec.
  • openapi/tools.yaml — curation: which operations are exposed, their tool names, read/write group, and destructive/paginated flags. An operation absent here is not exposed (that keeps admin/* and nic/update out).
  • internal/gen joins the two and emits internal/tools/generated.go; run it with make gen or go generate ./....
  • A curation entry naming an operation the spec lacks is a hard error (drift guard), and TestGeneratedIsUpToDate fails if the committed file is stale.
  • openapi/panel-routes.txt pins the routes the panel really serves, read from the panel's embedded spec (panel-api/internal/api/openapi.yaml, which the panel's own tests hold to its registered routes). TestCuratedOpsArePanelRoutes fails for any curated operation missing from it: that tool would 404. The vendored spec is a hand-edited copy and cannot catch this on its own.

To refresh after the panel API changes: run make panel-routes (reads origin/main of ../jabali2; override with PANEL_REPO= / PANEL_REF=), merge the changed operations into openapi.yaml by hand (a wholesale copy loses the request bodies written here), adjust tools.yaml, run make gen, review the diff.

Development

sh
make build     # build the binarymake gen       # regenerate internal/tools/generated*.go + docs/TOOLS.mdmake docs      # regenerate docs/TOOLS.md onlymake test      # go test -race ./...make vet       # go vet ./...
# zero-mutation live smoke against your configured panel (run before a release):make smoke

Layout

cmd/jabali-mcp/     entry point (stdio MCP server)cmd/gen-tools/      CLI wrapper over internal/geninternal/client/    Bearer-token HTTP client + fleet registryinternal/tools/     tools.go (helpers + gate) + generated.go (the tools)                    + composite.go (hand-written diagnose_domain)internal/gen/       openapi.yaml + tools.yaml -> generated.go + docs/TOOLS.mdopenapi/            vendored spec + curationscripts/smoke/      zero-mutation live smoke client (pre-release check)docs/TOOLS.md       generated tool reference (make docs)docs/DESIGN.md      architecture, security model, roadmapHANDOVER.md         full project handover: decisions, traps, release process

Roadmap

  • M1 — read-only MVP ✅ Bearer client, MCP stdio server, read tools, tests.
  • M2 — gated mutations ✅ write tools behind an opt-in flag; destructive ops confirm-gated.
  • M3 — fleet ✅ multi-panel registry + panel tool argument.
  • Generator ✅ tools generated from the spec + curation, golden-tested.
  • Dry-run ✅ per-call dry_run + global JABALI_MCP_DRY_RUN.
  • Input validation ✅ generated per-tool checks for the spec's value constraints (enum, minLength, min/max) — fail fast before any request.
  • Admin tools ✅ /admin/* surface behind JABALI_MCP_ADMIN=1 + an admin token, same binary.
  • Logs ✅ list_mail_logs + tail_web_log (panel gained GET /logs/tail).
  • Next: richer InputSchema (constraints visible to clients), composite diagnostics (diagnose_domain), CLI mode.

License

GNU Affero General Public License v3.0 — see LICENSE. Same license as Jabali Panel.

來源:README.md,提交 ce869cd

工具

0
SourceWeft 曾在隔離沙箱中以無憑證方式啟動該軟體包一次,以列出其工具,但未能完成:該軟體包類型無法在沙箱中執行。

版本歷史

1
  1. v0.6.1最新Nov 1, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分