OpenDeck

io.github.kastro5由 GitHub 账号 kastro5 发布v0.5.0更新于 Nov 7, 2026

Configure OpenDeck stream controllers (Stream Deck and others) in natural language.

概览

AI 生成的概览

用自然语言配置 OpenDeck 流控台(Stream Deck 等):读取设备与配置,暂存按键、配置文件和插件改动,预览后带备份应用。

可以做什么
  • 查看设备、配置文件、按键、动作与插件,并渲染控台画面
  • 放置、修改、清除、移动或复制按键、旋钮和触摸点,构建多动作/切换动作与文件夹
  • 创建、复制、重命名或删除配置文件,并设置按应用自动切换
  • 搜索、安装、更新或移除插件,读取或修改插件设置与日志
  • 用文字、表情、品牌标志或符号生成按键图标
  • 查找 Home Assistant 实体并调用其服务
适用场景
适用于在 Windows 桌面上运行 OpenDeck,并希望由助手来搭建或整理控台布局、配置文件、文件夹和应用切换规则,或管理插件与 Home Assistant 按键,而不必在 OpenDeck 界面里逐项点击。
运行要求
需在与 OpenDeck(2.14.x)相同的已登录桌面会话中本地运行,通过 uvx 从 PyPI 安装,需要 uv。OpenDeck 目录会自动查找,可用 OPENDECK_CONFIG_DIR、OPENDECK_EXE 等变量覆盖。联网用于插件目录、插件下载、字体和图标集。Home Assistant 工具复用 Home Assistant 插件中已保存的登录信息。远程 HTTP 使用需要令牌。
安装前请注意
应用和恢复会重启 OpenDeck,并丢失设置面板中未保存的修改。Run Command 与 Simulate Input 按键会在电脑上执行操作,安装插件会运行第三方代码,二者都需明确确认。Home Assistant 服务调用会作用于真实家居。备份包含插件设置(含密钥)。HTTP 令牌等于控台的控制权,应仅在私有网络中使用。

安装

在 SourceWeft 中

  1. 打开 控制台中的 OpenDeck,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

opendeck-mcp

Set up your OpenDeck stream controller by asking an AI agent:

"Put a Multi Action on the top-left key that mutes my mic and opens Discord, make a 'Gaming' profile from my default one, and switch to it whenever Steam is focused."

opendeck-mcp is an MCP server. It lets Claude Code (or any MCP client) read your decks, profiles and plugins, stage changes, show you a diff, and then apply them, with a backup you can undo. It works with any device OpenDeck drives: Elgato Stream Decks and plugin-provided devices such as the Ulanzi D200H/D200X.

Contents

What it can do

  • See everything: devices with their grid size, dials and touchpoints; profiles; every key's action, title and settings; and installed plugins with their actions.
  • Edit keys: place, update (title, font, colour, image, settings), clear, move, swap or copy keys, dials and touchpoints, across profiles and devices.
  • Multi and Toggle Actions: add and remove the actions inside them, and set the delays between them.
  • Profiles: create, duplicate, rename (references to the old name are updated too) and delete profiles, including Folder/Name profiles, and choose which one each device starts on.
  • App switching: switch a device to a profile automatically when an app is focused.
  • Plugins:
    • search the same catalogue as OpenDeck's Plugin Manager, plus the Elgato plugin archive;
    • install, update and remove plugins;
    • read and write plugin settings, with secrets redacted;
    • read plugin logs.
  • Instant edits: title, image and settings tweaks to a key on the profile a device is showing apply at once, with no restart; undo_live takes them back.
  • Icons and folders: make key images from text, emoji, ~3,400 brand logos or ~7,400 symbols, and folder keys that open a sub-profile with a Back key.
  • Pictures: render_profile shows the deck as OpenDeck draws it, with staged changes outlined or before and after side by side, so you can check a layout before applying it.
  • Home Assistant: find entities by name, area or domain, and get ready-made settings for a key that controls one, using the login already saved in the Home Assistant plugin.
  • Undo: every apply takes a backup, and restore_backup puts things back.

Install

You need OpenDeck 2.14, uv and Claude Code (or another MCP client, see below). uv fetches a suitable Python by itself.

sh
claude mcp add opendeck --scope user -- uvx [email protected]

Then restart Claude Code and ask it something like "what's on my OpenDeck?".

It's on PyPI and in the MCP Registry as io.github.kastro5/opendeck-mcp. To run straight from GitHub instead: uvx --from git+https://github.com/kastro5/[email protected] opendeck-mcp.

OpenDeck's folders are found automatically. If yours live somewhere unusual, override them with environment variables (claude mcp add … -e NAME=value):

VariableDefault (Windows)
OPENDECK_CONFIG_DIR%APPDATA%\opendeck
OPENDECK_EXE%LOCALAPPDATA%\OpenDeck\opendeck.exe
OPENDECK_LOG_DIR%LOCALAPPDATA%\opendeck\logs
OPENDECK_MCP_DATA_DIR%LOCALAPPDATA%\opendeck-mcp (the server's own plan, backups and cache)
OPENDECK_MCP_HA_VERIFY_TLS1; set 0 for a Home Assistant on https with a self-signed certificate
OPENDECK_MCP_TOKENthe HTTP token (default: generated once, see below)

Upgrading

The version is pinned in the command, so replace the registration with the new tag:

sh
claude mcp remove opendeck --scope userclaude mcp add opendeck --scope user -- uvx [email protected]

The first apply after an upgrade also updates the companion bridge plugin (see How it works), in the same restart.

Other MCP clients

Any client that can start a stdio server works. The usual JSON configuration (Claude Desktop, Cursor, VS Code and others) is:

json
{  "mcpServers": {    "opendeck": {      "command": "uvx",      "args": ["[email protected]"]    }  }}

From another computer

The server has to run on the PC that runs OpenDeck, inside your logged-in desktop session: it restarts OpenDeck and talks to it through its command line, which doesn't work from a service or an SSH session. To use it from another machine (a laptop, a dev VM), serve it over HTTP there and connect to it. Tailscale or another private network is the recommended way in; every request also needs a token.

On the OpenDeck PC (Windows):

sh
uvx [email protected] install-autostart --host <tailscale-ip>uvx [email protected] token --host <tailscale-ip>

The first command puts a small script in your Startup folder that starts the server, without a window, at every logon, and starts it now. The second prints the command to run on the other machine:

sh
claude mcp add --transport http opendeck http://<tailscale-ip>:8765/mcp --header "Authorization: Bearer <token>"
  • tailscale ip -4 shows the address. The server refuses 0.0.0.0 (every network) unless you add --allow-all-interfaces.
  • To connect by name (e.g. a MagicDNS name), add --allowed-host <name>; other Host headers are rejected.
  • opendeck-mcp token --reset makes a new token, and opendeck-mcp uninstall-autostart removes the autostart and stops the server.
  • Windows Firewall must allow inbound TCP 8765 on that network; it asks the first time if it isn't already allowed.
  • On Linux or macOS, run opendeck-mcp serve --host <ip> from a systemd user service or LaunchAgent.

As an OpenDeck plugin

The same server also comes as an OpenDeck plugin, which needs neither uv nor a terminal: OpenDeck starts and stops it, and it serves MCP over HTTP. Windows and Linux; macOS isn't built.

  1. Install OpenDeck MCP from OpenDeck's plugin store once it's listed there, or download io.github.kastro5.opendeck-mcp.sdPlugin.zip from the latest release, extract it into OpenDeck's plugins folder (%APPDATA%\opendeck\plugins on Windows) and restart OpenDeck. Upgrading from before 0.5.0: the plugin's ID changed from dev.kastro5.opendeck-mcp to io.github.kastro5.opendeck-mcp, so remove the old one in the Plugins tab; its settings carry over.
  2. In OpenDeck's Plugins tab, click the gear next to OpenDeck MCP. A page opens in your browser with the claude mcp add … command (token included) and a Copy button. Run it, then restart Claude Code.

By default it listens on 127.0.0.1:8765, for clients on the same PC. To reach it from another machine, pick a network address on the same page, ideally the Tailscale one; the listener restarts at once and the page shows the new command. The page also makes a new token. It closes itself after 10 minutes; the gear opens a fresh one.

Differences from the uvx server:

  • Applying goes through a helper. Applying restarts OpenDeck, and the plugin with it, so apply_changes and restore_backup hand the work to a short-lived helper and return straight away. The result arrives with your next tool call, about 10 seconds later.
  • No bridge plugin. The plugin records device geometry itself.
  • Same token and data folder as opendeck-mcp serve. Don't run both on the same address and port: the second one can't listen, and the gear page (and get_overview) says so.
  • It can't update or remove itself; do that from OpenDeck's Plugins tab.
  • The Linux build is compiled and smoke-tested in CI but hasn't been tried on a real deck.
  • Not for the Flatpak build of OpenDeck: applying needs to restart OpenDeck from outside its sandbox, so the plugin refuses to apply there.
  • The executable isn't code-signed, so antivirus software may ask about it the first time.

Using it

Just describe what you want. Under the hood, the agent:

  1. calls get_overview and show_profile to see your devices and keys;
  2. uses list_actions / describe_action to find the right action and learn its settings;
  3. stages edits with set_key, add_child, manage_profile and so on;
  4. calls preview_changes (and render_profile for a picture), shows you the result, and waits for your OK;
  5. calls apply_changes, which restarts OpenDeck for a few seconds and reports the backup id.

Small tweaks skip all that. Changing an existing key's title, image or settings on the profile a connected device is showing happens instantly, without a restart, and undo_live reverses it. Title style, the shown state, other profiles and every structural change still go through staging.

For example, "make a Fusion 360 profile with keys for my most-used sketch and solid tools, put the rest in a folder, and switch to it whenever Fusion is in front" builds a profile of Simulate Input keys sending Fusion's shortcuts, with icons from make_icon, a "More" folder and the app rule.

Keys are addressed the way show_profile draws them:

     c1              c2              c3              c4              c5r1    Multi Action    "GitHub"        Toggle Action   ·               ·r2    ·               Entity (custo…  ·               Switch Profile  ·r3    Device Bright…  ·               "rew"           ·               (wide →)
SlotMeaning
r1c1row 1, column 1
key13raw position 13 (0-based)
dial1first dial
touch1first touchpoint
r1c1/child2second action inside a Multi or Toggle Action

How it works

OpenDeck has no API for changing its layout. It keeps profiles in memory and overwrites any file edited while it runs. So opendeck-mcp works on the files, with OpenDeck stopped:

  1. Staging. Each edit is recorded as an operation in a plan. Nothing is written yet. show_profile shows staged edits marked with *.
  2. Applying.
    • First, OpenDeck is asked to save its in-memory state. This sends a profile switch through its command line, which makes it write the selected profile.
    • Then OpenDeck and its plugin processes are stopped.
    • The plan is replayed onto the freshly read files. If something you staged was changed in OpenDeck's UI in the meantime, apply reports a conflict and doesn't write anything.
    • The files are backed up, written atomically, read back and re-validated. If anything fails, the backup is restored automatically.
    • Finally, OpenDeck is started again, detached and hidden.
  3. Faithful files. Action data is rebuilt from plugin manifests exactly as OpenDeck builds it, and JSON is written byte-for-byte in OpenDeck's format. A profile OpenDeck can't read gets replaced by an empty one, so every write is validated twice.
  4. Device geometry. OpenDeck doesn't store a device's rows × columns anywhere, so the first apply also installs a tiny companion plugin, OpenDeck MCP Bridge (no actions, about 60 lines of JavaScript). It records the geometry OpenDeck reports to plugins into its own settings file, where the server reads it. It's versioned with the server, so a new release updates it on its next apply.
  5. Images. New key images are stored as data: URLs. OpenDeck accepts these and converts them to files itself on its next save.

Instant edits

Titles and images are sent to the running OpenDeck through its command line (--process-message), as setTitle and setImage events. Settings go over OpenDeck's local plugin websocket, posing as the key's settings panel, because that is the only path on which OpenDeck tells the plugin its settings changed. OpenDeck is then asked to save, and the file is checked. Before each edit the old titles, images (as bytes) and settings are written to live_journal.jsonl in the server's data folder, which undo_live replays.

Safety

  • Nothing changes until you confirm. Staging tools never touch OpenDeck. apply_changes, restore_backup and plugin installs all need a second call with confirm=true.
  • Backups. Every apply first copies profiles/, images/, applications.json and anything else it touches into %LOCALAPPDATA%\opendeck-mcp\backups. It keeps the last 30 backups (always at least 5). Restoring also backs up the current state first. Backups contain your plugin settings, including secrets, so they stay on your machine.
  • Secrets are redacted. Anything that looks like a credential (token, password, API key, JWT, Bearer value, …) is shown as «redacted» in settings, diffs, examples and logs. Passing «redacted» back keeps the stored value.
  • Risky keys are flagged. Run Command keys run commands, Simulate Input keys type into the focused window, and Open URL keys with non-web URIs can launch programs. Each is marked ⚠ when staged and in the preview.
  • Plugins are third-party code. stage_plugin first downloads and inspects the plugin: author, version, sha256, how it runs, which platforms it supports, and the catalogue's AI-assisted flag. It only stages the install after you agree. Built-in plugins can't be removed.
  • Home Assistant. The Home Assistant tools reuse the server URL and access token saved by the Home Assistant plugin. The token is only sent to that server, never shown. ha_call_service acts on your real home, so it needs a second call with confirm=true.
  • Instant edits aren't backed up. They don't go through apply, so instead the previous titles, images and settings are kept in a journal (the last 200 edits) that undo_live replays.
  • The HTTP token is a key to your deck. Anyone with it who can reach the port can change keys, install plugins and, through Run Command keys, run programs. Keep the server on a private address, and opendeck-mcp token --reset if the token leaks.
  • Version check. Apply refuses to run on OpenDeck versions other than 2.14.x unless you allow it explicitly.

Network and files

  • Internet: only the plugin catalogues and plugin downloads (find_plugins, stage_plugin), and the title fonts for render_profile and the icon sets for make_icon, fetched once each from jsDelivr and cached. Nothing else, and no telemetry.
  • Local network: your Home Assistant, only when the Home Assistant tools are used.
  • Files in %LOCALAPPDATA%\opendeck-mcp: plan.json (staged changes), backups/, live_journal.jsonl, icons/ (made by make_icon), cache/ (catalogues, fonts, icon sets), device_overrides.json, and for HTTP http_token and http.log. Delete the folder to reset everything.

Tools

KindTools
Readget_overview, show_profile, render_profile, list_actions, describe_action, get_plugin_settings, read_logs, get_app_rules, find_plugins, find_icons, preview_changes, list_backups
Stageset_key, update_key, clear_key, move_key, add_child, remove_child, set_multi_delays, make_folder, manage_profile, set_app_rule, set_plugin_settings, stage_plugin, discard_changes, set_device_layout
Iconsmake_icon (saves a PNG to pass as image)
Applyapply_changes, restore_backup, undo_live
Home Assistantha_search, ha_describe_entity, ha_call_service

Limitations

  • Apply restarts OpenDeck (about 5 seconds). Unsaved edits in an open settings panel are lost, and plugins restart.
  • Some settings need examples. Settings are known in detail for OpenDeck's own actions and the Starter Pack. For other plugins, the agent works from hints on the plugin's settings page and from your existing keys. If those aren't enough, place the action and finish setting it up in OpenDeck's UI.
  • App rule names. App rules match the name OpenDeck gives the focused app: on Windows the executable's description (e.g. Autodesk Fusion, Visual Studio Code), otherwise its file name. get_app_rules lists the exact names of the apps you have open.
  • Tested platform. Tested on Windows 11 with OpenDeck 2.14.1, a Ulanzi D200H and Home Assistant. The macOS and Linux paths and process handling are written but untested.
  • Limited live control. Title, image and settings edits apply instantly; everything else needs a restart. It doesn't press keys or switch profiles live.
  • Pictures are close, not exact. render_profile can't see images a plugin draws while running (a clock, a live Home Assistant state) unless OpenDeck has saved them, and OpenDeck's own Multi/Toggle Action icons are drawn as look-alikes.
  • An open settings panel goes quiet. After an instant settings edit, a settings panel already open in OpenDeck's window for that key stops updating until it's reopened.

Troubleshooting

  • "OpenDeck's executable wasn't found" / "config folder wasn't found": set OPENDECK_EXE / OPENDECK_CONFIG_DIR (see Install).
  • Apply refuses: untested OpenDeck version. Check the changelog for a release that supports yours; apply_changes(allow_untested_version=true) overrides it at your own risk, with a backup.
  • Apply reports a conflict. A key you staged was changed in OpenDeck meanwhile. Look at preview_changes, then discard and re-stage it, or apply with on_conflict="skip".
  • A device shows "geometry unknown". It's learned by the bridge plugin, installed with the first apply. Until then set_device_layout sets rows and columns by hand.
  • Undo an apply: list_backups, then restore_backup.
  • Plugin: the gear page says "not serving". Another program holds the port, usually opendeck-mcp serve on the same address. Pick another port on the page, or stop the other server (opendeck-mcp uninstall-autostart). The plugin's log is logs\plugins\io.github.kastro5.opendeck-mcp.sdPlugin.log in OpenDeck's log folder.
  • HTTP client gets 401 / 421. 401: wrong or missing token (opendeck-mcp token). 421: the client used a host name the server doesn't know; add it with --allowed-host. The server logs to http.log in its data folder.

Development

sh
git clone https://github.com/kastro5/opendeck-mcp && cd opendeck-mcpuv syncuv run pytest                 # unit tests, against a scrubbed fixture configuv run pytest -m live         # also check snapshots against your real OpenDeck install (read-only)claude mcp add opendeck-dev -- uv --directory /path/to/opendeck-mcp run opendeck-mcp

Test fixtures are real OpenDeck profiles with every setting value replaced (scripts/scrub_fixture.py), plus trimmed plugin manifests with empty icon files.

License

MIT. Not affiliated with OpenDeck or Elgato.

Icons and fonts are downloaded at run time, not bundled: Material Design Icons (Apache 2.0), Simple Icons (CC0; brand logos remain their owners' trademarks), Twemoji (graphics CC-BY 4.0, © Twitter/X and contributors), and OpenDeck's title fonts from Google Fonts (OFL).

来源:README.md,提交 66a2220

工具

33

get_overview

Start here. Lists devices (grid size, dials, touchpoints, connected), each device's profiles and which is selected, installed plugins, whether OpenDeck is running, and how many changes are staged.

无需输入参数。

show_profile

Render a profile: a grid sketch plus every occupied slot with its action, title and state. Includes staged (not yet applied) changes, marked with *. Slot labels shown are the ones the editing tools accept.

输入参数device必填profileshow_childrenshow_settings

list_actions

List actions that can be placed on keys or dials: name, plugin, uuid, controllers, states. Includes OpenDeck's Multi Action and Toggle Action, and plugins staged for install.

输入参数queryplugincontroller

describe_action

Explain one action's settings before placing it: a curated schema for OpenDeck and Starter Pack actions, otherwise hints read from the plugin's settings page, plus real settings from the user's existing keys (secrets redacted).

输入参数action必填

get_plugin_settings

Show a plugin's global (plugin-wide) settings with secret values redacted.

输入参数plugin必填

read_logs

Tail OpenDeck's log or a plugin's log (tokens redacted). Useful after apply_changes.

输入参数greplinesplugin

get_app_rules

Show automatic profile switching: which profile each device switches to when an app is focused.

无需输入参数。

set_key

Place an action on a key or dial, replacing whatever is there. For dials use dial<N> with an action that supports Encoder. For a Multi/Toggle Action, set it here, then add_child. Staged only.

输入参数slot必填imagetitleaction必填device必填profilesettingstitle_style

update_key

Change an existing key without replacing its action: title, title style, image, settings, or which state it shows. Title text, image and settings changes on the profile a connected device is showing apply instantly, with no restart (undo with undo_live). Anything else (title style, current state, another profile, a device with staged changes) is staged for apply_changes; the result says which happened. A live settings change reaches the plugin as if edited in OpenDeck's own panel; if that key's settings panel is open in OpenDeck, reopen it to see the change.

输入参数modeslot必填imagestatetitledevice必填profiletitle_stylecurrent_statesettings_mergeremove_settingssettings_replace

undo_live

Undo the latest instant (live) edits made by update_key, newest first: titles, images and settings go back to what they were. Staged changes and applied plans are undone with discard_changes and restore_backup instead.

输入参数count

make_folder

Make a folder: a new profile opened by a key on this one, with a Back key inside. OpenDeck allows one folder level, so it's created as '<this profile's folder>/<name>'. Staged only.

输入参数name必填slot必填imagedevice必填profileback_slotback_image

clear_key

Remove the action from a key or dial. Staged only.

输入参数slot必填device必填profile

move_key

Move, swap or copy a key (with its settings, title, image and children), within a profile or to another profile/device. Staged only.

输入参数modedevice必填profileto_slot必填from_slot必填to_deviceto_profile

add_child

Add an action inside a Multi Action (runs all children in order) or Toggle Action (cycles through them, one per press). Put the Multi/Toggle Action on the key with set_key first. Staged only.

输入参数slot必填imagetitleaction必填device必填profiledelay_mspositionsettingstitle_style

remove_child

Remove one action from inside a Multi/Toggle Action. Staged only.

输入参数slot必填child必填device必填profile

set_multi_delays

Set the pauses between the children of a Multi Action. Staged only.

输入参数slot必填device必填profiledelays_ms必填

manage_profile

Create, duplicate, rename or delete a profile, or make one the device's selected profile. Renaming also updates app rules and Switch Profile keys that point at it. Staged only.

输入参数device必填profile必填new_namecopy_fromoperation必填

set_app_rule

Switch a device to a profile automatically when an app is focused. Staged only.

输入参数app必填device必填profile必填

set_plugin_settings

Change a plugin's global (plugin-wide) settings, e.g. a server URL. Staged only.

输入参数plugin必填values必填remove_keys

set_device_layout

Tell opendeck-mcp a device's key grid size when it can't detect it (stored locally; doesn't touch OpenDeck). Usually unnecessary: the bridge plugin records it automatically.

输入参数rows必填device必填columns必填

preview_changes

Show everything staged: per device/profile/slot changes, warnings (commands that will run, plugins that will be installed), and conflicts with edits made in OpenDeck since staging.

输入参数detail

discard_changes

Drop staged changes without applying them.

输入参数which

render_profile

A picture of the deck as OpenDeck draws it: icons, titles, colours, dials, with staged changes outlined. Use it to check a layout before applying, or to show the user.

输入参数device必填stagedcompareprofile

make_icon

Make a key image: text, an emoji, a brand logo or a generic symbol on a coloured square. Returns a preview and a file path to pass as `image` to set_key / update_key / add_child.

输入参数fonticon必填scalestylecolourbackground

find_icons

Find icon names for make_icon.

输入参数limitquery必填icon_set

ha_describe_entity

One Home Assistant entity: state, attributes, area, the services its domain offers, and ready-made settings for a Home Assistant key that controls it.

输入参数entity_id必填

ha_call_service

Call a Home Assistant service right now, e.g. to test what a key will do. Acts on the real home: call with confirm=false first and get the user's OK.

输入参数dataconfirmservice必填entity_id

find_plugins

Search for plugins to install, with author, repository and installed/available versions.

输入参数limitquerysource

stage_plugin

Install, update or remove a plugin. Installing runs third-party code on the user's computer: call first with confirm=false, show the user what was found (author, version, checksum, AI-assisted flag), and only stage it with confirm=true after they agree. Removal clears the plugin's keys everywhere.

输入参数urlsourceconfirmoperation必填plugin_id必填

apply_changes

The only tool that changes OpenDeck. Stops OpenDeck, backs up, writes all staged changes, verifies them and restarts OpenDeck. Call with confirm=false first and show the user the result.

输入参数confirmon_conflictshow_windowallow_untested_version

list_backups

Backups taken by apply_changes and restore_backup, newest first.

输入参数limit

restore_backup

Undo an apply: put the files it changed back as they were (restarts OpenDeck). Call with confirm=false first to see what would be restored.

输入参数confirmbackup_id必填show_window

版本历史

3
  1. v0.5.0最新Nov 6, 2026
  2. v0.4.1Oct 19, 2026
  3. v0.4.0Oct 15, 2026

评分

已满足适用检查项的 90%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分
  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分