Credential Broker

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

Local-first credential broker: agents use gated APIs through scoped, audited requests, never keys.

已验证STDIO仅桌面开发者工具安全与监控

概览

AI 生成的概览

本地 MCP 服务器,让 AI 代理通过受策略约束、可审计的请求调用受控 API,而 API 密钥始终保存在操作系统钥匙串中。

可以做什么
  • 查看身份与授权:显示已认证的代理、其按凭据划分的操作授权,以及已授权的凭据(不含密钥值)。
  • 预演请求:说明某个请求是否会被允许、由哪条规则决定,以及是否需要或已满足审批。
  • 调用 API:通过已授权的凭据执行 GET 或 HEAD 读取,以及 POST、PUT、PATCH 或 DELETE 变更,密钥在最后一刻注入,响应会被脱敏。
  • 申请密钥:可选地通过打开预填好的密钥管理器向操作者申请凭据,代理看不到页面和令牌。
适用场景
当代理需要调用需要认证的第三方 API,但不应持有密钥,并且你希望按操作授权、对写操作要求审批、保留不含内容的审计记录时使用。适合由你掌控策略文件和操作系统钥匙串的单机本地环境。
运行要求
通过 npx 以 stdio 在本地运行,需要 PATH 中有 Node 22 或 24。密钥存放在操作系统钥匙串(Windows 凭据管理器、macOS 登录钥匙串或 Linux 的 Secret Service),也可通过各凭据的 env_var 提供。必须设置 BROKER_AGENT_ID 并在策略文件中预先配置;策略、审计和审批文件由 BROKER_POLICY_FILE、BROKER_AUDIT_FILE 和 BROKER_APPROVALS_FILE 指定。
安装前请注意
它处理真实的 API 密钥和与钱包相关的机密:密钥管理器可从环境变量、MCP 客户端配置和 .env 文件导入密钥,钱包密钥会被标记但仍会被读取。变更操作(POST、PUT、PATCH、DELETE)会修改上游数据,可能需要审批。除非使用安全启动配置,BROKER_AGENT_ID 只是启动方的声明;任何能写入策略目录的人都能暂停、恢复或修改授权。仍为 0.x 早期版本,策略格式可能变化。

安装

在 SourceWeft 中

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

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

其他 MCP 客户端

参照 仓库 中的启动说明。

README

[图片]

Credential Broker MCP

A local-first MCP server that lets AI agents use gated APIs without ever holding the keys.

The agent asks the broker to make a request. The broker canonicalises the URL, checks a declarative per-operation policy, verifies any required approval at execution time, injects the secret at the last moment, calls the upstream, redacts and filters the response, and writes a content-free audit record. The secret lives with the broker process and is never relayed to the agent in any representation the broker creates: raw, Base64, base64url, percent-encoded, form-encoded, or Unicode-normalised. An upstream that transforms a secret with a one-way function of its own defeats string matching; scoped operations and metadata-only responses are the defence there, and SECURITY.md states this boundary honestly.

[npm] [provenance] [licence]

Early release (0.x). Published to npm with provenance from GitHub Actions. Expect the policy format and tools to change before 1.0.

Five-minute quickstart

Needs Node 22 or 24. Keys are stored in the OS keychain: Windows Credential Manager, the macOS login keychain, or the Secret Service on Linux (GNOME Keyring or KWallet through secret-tool). Without one, set each credential's env_var instead.

  1. Open the key manager. It prints a local link and opens it in your browser.

    bash
    npx -y -p @sarutobi-sasuke/credential-broker-mcp credential-broker-keys

    Run through npx, the policy, audit log and approvals live in ~/.credential-broker (%USERPROFILE%\.credential-broker on Windows), so they survive npm cache clean-ups and upgrades. Set BROKER_HOME, or BROKER_POLICY_FILE, BROKER_AUDIT_FILE and BROKER_APPROVALS_FILE, to put them somewhere else. From a clone of this repo, run npm ci then npm run keys; the files then stay in the checkout.

  2. Add one key. Open New key. Use the short name github, base URL https://api.github.com, paste a token, tick the agent that may use it (or add an identity such as codex), then press Add key. The key goes into your OS keychain and the policy file gets a read-only grant. Press Test on the card to prove the key works.

  3. Connect your MCP client. Go to Settings → Connect an MCP client, select Codex or Claude Code, then pick the agent. For Codex, paste the copied TOML into ~/.codex/config.toml or update the existing credential-broker entry. For Claude Code, run the copied command. Restart your client. Both options use local stdio and require Node on PATH. The Codex configuration also applies to local sessions in the ChatGPT desktop app on the same host. If you use environment-backed credentials, list the variable names in env_vars under the Codex server table. See the Codex MCP configuration guide.

  4. Make a granted call and a denied call. In your client:

    Use broker_explain_request for a GET to https://api.github.com/repos/octocat/hello-world with credential github.

    It answers allowed and names the deciding rule. Now ask the same with DELETE: denied, no grant. Then ask for broker_read on the GET and you get the response body with the token redacted wherever it might appear. The audit log (data/audit.jsonl) now holds the who, what and outcome, never the content.

  5. Pause and resume. Press Pause all access in the page header and type PAUSE. The agent's next call is refused with a message not to retry. Press Resume all access and type RESUME. From a terminal: npm run pause -- on and npm run pause -- off.

ChatGPT web

The broker's native connection is local stdio. For a private ChatGPT integration, an eligible workspace can connect through OpenAI Secure MCP Tunnel, with the tunnel client launching the broker under a dedicated policy identity. Run the tunnel client under the OS account that owns the keys and keep the key manager on loopback. This connection needs its own workspace setup and verification. Public distribution as a local ChatGPT desktop plugin is limited to approved partners.

Why

Giving an agent an API key gives it everything the key can do, for as long as the key lives, invisibly. Most agent tasks need a fraction of that: read these repos, query this endpoint, GET but never DELETE. This broker turns "here is my key" into "here is a scoped, observable capability":

  • Possession vs use. Agents exercise credentials; they never possess them.
  • Deny-by-default. Authority is an enumerated list of named operations per credential. An absent grant is a denial, not an oversight. Deny rules always beat grants.
  • Nothing widens sideways. A method, path, query parameter, body rule, or approval attached to one credential never widens any other credential.
  • One decision function. The dry-run explainer and the live request path call the same evaluate(). What the broker reports and what it enforces cannot drift apart.
  • Content-free audit. Who reached what, when, with what outcome, and through which lifecycle state. Never what they saw.

Tools

ToolWhat it does
broker_whoamiShow the authenticated agent and its per-credential operation grants.
broker_list_credentialsGranted credentials: id, kind, base URL, provisioned or not. Never values.
broker_explain_requestDry run: would this request be permitted, which rule decides it, and is an approval required or satisfied? No upstream call, no secret touched.
broker_readGET or HEAD through a granted credential. Honestly annotated read-only.
broker_mutatePOST, PUT, PATCH, or DELETE. Annotated destructive and non-idempotent, because its strongest capability is. May require an approval and an idempotency key.
broker_request_credentialOpt-in (BROKER_ALLOW_KEY_REQUESTS=1). Asks the operator for a key by opening the key manager pre-filled. The agent never sees the page, the token or the key.

Policy (version 2)

Policy objects reject unknown fields at every level. Correct misspelt keys and remove unsupported metadata before upgrading; ignored fields could otherwise remove a restriction, such as a misspelt enabled or deny.

One YAML file declares credentials and per-credential operation grants:

yaml
version: 2credentials:  - id: github-readonly    kind: bearer                 # bearer | header | basic | query    env_var: GITHUB_READONLY_TOKEN    base_url: https://api.github.com
agents:  - id: researcher    grants:      - credential: github-readonly        operations:          - id: read-repo            method: GET            path: /repos/*/*     # literal segments, '*', or trailing '**'            response_body: true  # default is metadata only        deny:          - /repos/*/*/keys

A request must clear every gate: identity provisioned and enabled, credential granted, URL canonical and provably unambiguous, origin exactly the credential's origin, path inside the credential's base path, no deny match, and an operation whose method, path template, query parameter allowlist, and body rule all match. broker_explain_request reports which gate decided any outcome.

Semantics worth knowing:

  • Operation paths are relative to the credential's base path. With base_url: https://api.example.com/v2, the template /weather authorises /v2/weather.
  • Path matching is case-sensitive for operations and case-insensitive for deny rules, because many upstreams treat paths case-insensitively.
  • Query parameters not named in query_params are denied.
  • Operations without a body rule reject any request body. Body rules name allowed content types and a byte cap. Mutations must declare requires_approval explicitly, true or false.
  • Responses default to metadata only. response_body: true relays the body, and only for content types in response_content_types (default application/json).
  • Credentials of kind query must set high_risk: true: URLs are commonly retained by upstream and proxy telemetry, so a query-string secret has a wider blast radius than a header.

Approvals

An operation with requires_approval: true executes only when the request carries an approval_id that exists in the approval store, is bound to exactly this principal, credential, and operation, is unexpired, and is not revoked, checked at execution time, not config-load time. On stdio the store is a JSON file (config/approvals.json by default) that is re-read on every check, so editing it revokes access mid-flight:

json
[  {    "id": "apr-2026-08-13-01",    "agent_id": "researcher",    "credential_id": "github-readonly",    "operation_id": "create-issue",    "expires_at": "2026-08-14T00:00:00Z",    "revoked": false  }]

Migrating from version 1

Version 1 policies shared one method list and path set across every credential an agent held, so authority needed for one credential widened all of them. The broker refuses v1 files. Convert with:

bash
npm run migrate -- config/broker.yaml > config/broker-v2.yaml

The output is deliberately conservative (mutations require approval, query parameters must be enumerated) and flagged for review: it makes the old blast radius visible rather than silently preserving it.

Safety properties

  • Every URL is canonicalised once; policy and the outbound request consume the same canonical value, and the outbound bytes are round-trip checked. Encoded separators, double encoding, control characters, backslashes, userinfo, non-ASCII path segments, repeated or trailing slashes, and trailing-dot segments are rejected, not guessed at.
  • Secrets are injected into exactly one header or query parameter. One redactor covers response bodies, relayed headers, error chains, and audit records, across raw, Base64, base64url, percent-encoded, form-encoded, and NFC/NFD representations, including truncation boundaries.
  • Raw upstream error text is never relayed to agents; they receive a stable error category and a trace id, and the redacted detail goes to the audit log.
  • Redirects are refused: a redirect could point anywhere, and fetch would re-send the injected credential there.
  • A credential can only be exercised against its exact origin and base path; lookalike hosts and string-prefix tricks are refused.
  • Plain-http upstreams are rejected at policy load, except on loopback.
  • Response headers are allowlisted; Set-Cookie and friends are dropped.
  • Responses are size-capped per operation, metadata-only by default.
  • Mutations are a separate, honestly-annotated tool; approval state is checked at execution time; a dispatch failure on a mutation is recorded as indeterminate, never silently retried.
  • Every decision is audited through its full lifecycle without request or response content, and audit records pass through the redactor too.

Identity boundary

On stdio, BROKER_AGENT_ID is a trusted-launcher assertion: the operator starting the process vouches for which agent is connected. It is only a real boundary when the broker runs under the secure-launch profile in SECURITY.md: dedicated OS identity, owner-only policy/approvals/audit files, a fixed identity wrapper the agent cannot edit, and no agent-readable secret environment. The broker loads only its principal's secrets and scrubs every policy credential variable from its environment after loading. One broker process serves one principal; never share a process between agents.

Managing keys

bash
npm installnpm run keys

This opens a local page in your browser where you:

  • Add an API: name, base URL, how the key is sent, paste the key, then choose individual agents or group shortcuts. The key goes into the OS keychain; the policy file gets persistent group assignments and separate read-only grants for individually selected agents (GET on any path under the base URL, only the query parameters you list).
  • Save, replace, test, or remove a key for any API already in the policy. Test makes one GET with the key and reports the status code only. Keys are write-only: the page never shows one back.
  • Import keys you already have. "Find my keys" looks in Windows user environment variables, MCP client configs (Claude Code, Claude Desktop, Cursor), and .env files under Documents and C:\Dev (override with BROKER_IMPORT_ROOTS, semicolon-separated). Known providers (OpenRouter, Gemini, ElevenLabs, DigitalOcean, Nansen, TypeSafe, Clerk, CoinGecko, PixelLab, OpenAI, Anthropic, GitHub) can be added as APIs in one click and are tested straight away; anything else is stored only. Values are read by the key manager process and never sent to the page. Wallet keys are flagged and never offered as APIs. Original copies are not touched.
  • Add an agent (Agents page): id, display name, enabled, and which APIs it may read. A new agent starts with no access at all; only the APIs you tick become read grants. No key is involved.
  • Copy the claude mcp add command that registers the broker for an agent with absolute paths filled in (Settings page).

A key saved in the keychain that no API in the policy uses is listed on the Keys page under Not connected to an agent yet, with a Connect to an API action; no agent can use it until then.

The page is a small site: a sticky header with the page links (Overview, Keys, Agents, Approvals, Activity, Import, Settings; a menu button on narrow screens), search (/ or Ctrl+K), a New key button, the pause control and a status chip. Activity is the content-free audit log, with filters and CSV export. It follows your system's light or dark theme, works with the keyboard alone, and is served entirely by the key manager on loopback: no external script, style, font or image.

Write access (POST, PUT, PATCH, DELETE) is never granted from the page; add those operations to the policy by hand. Restart the MCP client (or set BROKER_HOT_RELOAD=1, see below) after changing a key, because the broker loads keys once at start-up.

Optional top-level groups: in broker.yaml maps a name to registered agent IDs. all: ['*'] means every registered agent. The example policy shows hermes, grokbot and all; replace their sample members with your own IDs. Groups cannot be empty, nested or refer to unknown agents. Selecting a group in the key manager writes a group_grants: entry for that credential. The broker resolves it for the authenticated agent on every request. Editing groups: changes access after the broker restarts and reloads its policy. Membership alone grants nothing; a matching group_grants: entry is required. Group and direct denials are combined, and group mutations must require approval. The key cards show groups actually assigned to each credential.

Keys live in the OS keychain as credential-broker/<credential-id>: on Windows in Control Panel > Credential Manager > Windows Credentials, on macOS in the login keychain (Keychain Access shows them under that service name), on Linux in the Secret Service (Seahorse or KWallet Manager shows them with the credential-broker attribute). The macOS and Linux backends drive the security and secret-tool commands and send the key over stdin, never on a command line; they are unit tested against a fake and still need a real round trip on each platform before you rely on them. An env_var value, if set, overrides the stored key. The page listens on 127.0.0.1 only, needs a per-run token from the printed link, and closes after 30 minutes idle. On other platforms, set each credential's env_var instead.

Expiry dates and notes

Each key can carry an expiry date and a free-text note (where it was created, how to rotate it). They are kept in key-notes.json beside the policy file (override with BROKER_KEY_NOTES_FILE), never in the policy and never with the secret. Keys that are expired or expire within 30 days raise a banner, sort first, and show a badge on their card. Nothing in the broker engine reads this file, so a date never blocks a request; it is a reminder for you.

Letting an agent ask for a key

Set BROKER_ALLOW_KEY_REQUESTS=1 on a broker process to give that agent the broker_request_credential tool. The agent supplies a lowercase name, a short reason and, optionally, a known provider id (for example github, openai, itch). The broker then opens the key manager in your browser, pre-filled with the name and the reason, with a banner saying which agent asked.

  • The agent never receives the page address, the session token or anything you type. The tool result says only that a window opened.
  • The base URL and key style come from the broker's own table of known providers, never from the agent. An unknown provider leaves them blank for you to fill in, so an agent cannot steer a key to a host of its choosing.
  • Nothing is added until you press the button, and you choose who may use it.
  • Requests are limited to one per credential per 10 minutes and five an hour per process, and each one writes a content-free audit line.
  • The broker loads keys when it starts, so restart the MCP client after saving. The tool is off by default.

Panic button

The header of the key manager has a red Pause all access button. It opens a dialog that says what will happen, shows how many agents and keys are affected, and asks you to type PAUSE. From then on every broker refuses every request on its next call. Nothing is deleted: policy, keys and approvals stay as they were. Resume all access asks you to type RESUME, because resuming is the risky direction. Pausing one agent (Agents panel) or one key (its card) asks a plain confirmation and then offers an eight second Undo; resuming one asks a confirmation.

The typed word is a safeguard against a stray click in the page. It is not a security boundary: anyone who can write the policy directory can pause or resume, which is the same trust as editing the policy.

From a terminal, when no browser is to hand, the command acts at once with no prompt, and prints exactly what it changed:

bash
npm run pause -- on --reason "key leaked"            # everythingnpm run pause -- on --agent claude                   # one agentnpm run pause -- on --credential github              # one keynpm run pause -- off                                 # resume everythingnpm run pause -- status                              # exit code 1 while anything is paused

--yes is accepted so a script can say plainly that it means it; it changes nothing.

The switch is the file pause.json beside the policy (override with BROKER_PAUSE_FILE). Brokers re-read it on every request, so it needs no restart, and it fails closed: a missing file means nothing is paused, but a file that exists and cannot be read pauses everything. Agents are told only that access is paused and not to retry; your typed reason stays private.

Every pause and resume, from the page or the terminal, appends one line to the audit log: the scope, the direction, where it came from and when. The reason is never written there.

Tamper evidence. Resuming never deletes pause.json; it writes a fresh file with an explicit resume record. A running broker remembers the last pause it enforced, so if that pause disappears (the file is deleted, emptied or replaced) without a matching resume record, the broker stays paused and writes a PAUSE_TAMPER audit line. Only a valid file carrying the resume releases it: run npm run pause -- off, or pause and resume once from the page. This catches accidents and casual meddling. A hostile process running as the same OS user can still write a valid file; the real protection against that is the secure-launch profile in SECURITY.md.

Hot reload

Set BROKER_HOT_RELOAD=1 on a broker process and it picks up key manager changes (a new key, a new API, a changed grant) on the next request, with no restart. The key manager writes a small marker beside the policy after every change. If the new policy is invalid, the broker keeps its previous working state and writes an audit line. Off by default.

Each opt-in control has a short page saying what it does and what it trusts: pause, hot reload, key requests, approvals.

Usage, rotation and approvals

  • Each key card shows when it was last used, by which agent, and how its last 30 days of requests ended, read from the content-free audit log.
  • Replacing a key records the date. For known providers a link opens the provider's key page so you can revoke the old key.
  • The Approvals panel creates and revokes approvals for operations the policy marks requires_approval, with a lifetime of 1 minute to 24 hours. It cannot approve anything else, and it never grants write access itself.
  • About twenty providers are known (OpenAI, Anthropic, GitHub, Cloudflare, Stripe, itch.io and others); picking one fills in the address and key style.

Running

bash
npm installcp config/broker.example.yaml config/broker.yaml   # then edit, or use npm run keysBROKER_AGENT_ID=researcher npm start

Environment:

VariableMeaning
BROKER_AGENT_IDIdentity this stdio session runs as. Required.
BROKER_POLICY_FILEPolicy path. Default config/broker.yaml.
BROKER_AUDIT_FILEAudit log path. Default data/audit.jsonl.
BROKER_APPROVALS_FILEApproval store path. Default config/approvals.json.
BROKER_KEYCHAINoff stops the broker and key manager reading Credential Manager.
BROKER_KEYS_PORTFixed port for npm run keys. Default: a free port.
BROKER_KEY_NOTES_FILEExpiry dates and notes. Default key-notes.json beside the policy.
BROKER_PAUSE_FILEThe pause switch. Default pause.json beside the policy.
BROKER_RELOAD_MARKERHot reload marker. Default .broker-reload beside the policy.
BROKER_HOT_RELOAD1 lets a running broker pick up key manager changes. Off by default.
BROKER_ALLOW_KEY_REQUESTS1 enables broker_request_credential for this agent. Off by default.
(per credential)Each credential's env_var carries its secret, overriding a stored key.

Manual Claude Code registration from a checkout:

json
{  "mcpServers": {    "credential-broker": {      "command": "node",      "args": ["/absolute/path/to/credential-broker/dist/src/stdio.js"],      "env": {        "BROKER_AGENT_ID": "researcher",        "BROKER_POLICY_FILE": "/absolute/path/to/broker.yaml",        "BROKER_AUDIT_FILE": "/absolute/path/to/audit.jsonl",        "BROKER_APPROVALS_FILE": "/absolute/path/to/approvals.json"      }    }  }}

Verification

Run npm run check for types, lint and unit tests, npm run verify:pack for the package allowlist, and npm run test:e2e for the installed-server proof. CI runs these on Windows, macOS and Linux with Node 22 and 24.

The end-to-end test packs the project, installs the tarball into an empty directory and starts its declared stdio executable. Synthetic credentials and a loopback HTTP API exercise tool discovery, principal-scoped grants, denials before upstream calls, response redaction, metadata-only responses, approval revocation and content-free audits. It also runs the installed credential-broker-pause binary through pause, status and resume, and starts credential-broker-keys, checks its CSP and token gate, and closes it. No production credential, OS keychain entry or external API is used. This does not verify the key manager page in a browser, secure-launch deployment, independent operator workflows or the eventual npm-hosted artifact.

Idempotency keys are required and recorded when the policy says so. They are audit identifiers, not upstream deduplication: the broker neither forwards them as headers nor suppresses repeated mutations.

The manual release workflow uses Node 24 for the npm trusted-publishing toolchain and runs the installed proof through prepublishOnly before publication. See npm's trusted-publisher requirements. The package's npm trust configuration and the release tag still need operator verification before a first publish.

What this is not

  • Not an OAuth authorization server. It brokers static secrets you already hold. OAuth token acquisition and refresh are on the roadmap.
  • Not a cloud service. It runs where your agents run, and your secrets stay on your machine. If you want hosted multi-tenant auth for agents, use a platform built for that.
  • Not a bypass. It delegates through existing gates with scoped-down authority; it does not defeat anything.

How it compares

Other tools solve neighbouring problems. This section names only what was read on the projects' own pages on 2026-11-06; it is not a review of their security, and they may have moved on since.

  • Hosted secrets managers with an MCP server, such as Doppler's. Doppler's server is described as experimental and intended for development and evaluation, calls the Doppler API with an account token kept in the system keyring, and lists "read secret values" among its tools. That is a different shape: the manager hands values to the agent on request and relies on token permissions. This broker never returns a value; the agent gets the result of a scoped call, and nothing leaves the machine.
  • Governance gateways, such as Agenthof (Apache-2.0, Go, pre-release). It injects per-role or per-resource credentials the agent never holds, grants access per named tool or resource, and keeps a hash-chained audit ledger attributed to the human who asked. It is a broader control plane with OIDC human identity. This broker is narrower: one process per agent, one YAML file, per-operation method and path grants, no identity provider, no server to run.
  • Credential-proxy MCP servers that follow the same "the agent calls through a process that holds the key" pattern exist (for example Janee and pincer-mcp appear in directories). Their pages could not be read for this section, so nothing is claimed about them here.

Where this broker is deliberately small: it brokers static keys you already hold, it has no OAuth flows yet, no rate limits beyond key requests, and no hosted or multi-user mode. Where it is deliberately strict: deny by default per operation, a single decision function for explain and execute, secrets redacted in every representation it creates, a content-free audit, and operator controls that only ever narrow access.

Roadmap

  • OAuth 2.1 device and refresh flows for credentials that expire
  • HTTP transport with mutually authenticated, audience-bound, expiring principal tokens through the same engine, matching agent-handoff-mcp
  • Per-credential rate limits and spend counters
  • Key manager page: provision, replace, test, and remove keys
  • Keychain backends for macOS (security) and Linux (secret-tool), unit tested with a faked command runner; real round trips on a Mac and a Linux desktop are still to be confirmed by hand
  • Operator CLI: approve, rotate

Licence

Apache 2.0. See LICENSE.

来源:README.md,提交 c05624c

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

1
  1. v0.1.1最新Nov 7, 2026

评分

已满足适用检查项的 50%

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

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

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

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分