api-patterns
3CX's native PBX MCP server: the per-PBX endpoint shape (every PBX is its own FQDN and its own OAuth authorization server — there is no shared mcp.3cx.com),…
Reading credential material out of Keeper safely: what `get_secret` returns and exactly which parts of it masking covers, the `fields` parameter, `unmask` semantics under a container deployment with no confirmation prompt, why a record's field list is not guaranteed complete,
$ npx -y skills add wyre-technology/msp-claude-plugins --skill retrieving-credentials --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/retrieving-credentialsContext preview
The summary Claude sees to decide when to auto-load this skill.
Reading credential material out of Keeper safely: what `get_secret` returns and exactly which parts of it masking covers, the `fields` parameter, `unmask` semantics under a container deployment with no confirmation prompt, why a record's field list is not guaranteed complete,
name: "Keeper Credential Retrieval" description: > Reading credential material out of Keeper safely: what `get_secret` returns and exactly which parts of it masking covers, the `fields` parameter, `unmask` semantics under a container deployment with no confirmation prompt, why a record's field list is not guaranteed complete, `get_totp_code` versus unmasking a TOTP seed, and the handling rules for secret material once it is in an agent transcript. when_to_use: >- When a Keeper value is about to be read, revealed, or passed on to something else. Use when: get_secret, unmask, keeper password, keeper totp, get_totp_code, reveal secret, unmask keeper, keeper attachment, or "give me the password for".
Four of the nine served tools return credential material. Everything in this skill follows from one property of the environment: **a secret read into an agent transcript has been disclosed**, to the transcript, to whatever stores it, and to anything downstream the transcript reaches. Masking narrows that; it does not undo it. So the discipline is to read the least, as late as possible, and to move it onward without copying it.
| Need | Use | Why | |------|-----|-----| | One value | `get_field` with notation | Returns exactly that value | | A live second factor | `get_totp_code` | Returns a code, not the seed | | Field names / record shape | `get_secret` **masked** | The response keys *are* the field names, read from the real record | | A genuinely whole record | `get_secret` with `unmask: true` | Last resort — see below |
Reaching for `get_secret` because it is fewer keystrokes than composing notation is the common failure. One record can carry a password, an API secret, recovery codes, and notes containing a second credential; all of it lands in context at once.
{ "uid": "NJ_xXSkk3xYI1h9ql5lAiQ" } // masked
{ "uid": "NJ_xXSkk3xYI1h9ql5lAiQ", "fields": ["login", "url"] } // subset
{ "uid": "NJ_xXSkk3xYI1h9ql5lAiQ", "unmask": true } // full reveal`uid` must be a real UID — 16 to 32 characters — and a title fails with `invalid UID: UID must be between 16 and 32 characters`. Resolve titles first; see [finding-secrets](../finding-secrets/SKILL.md).
With no `fields`, the response carries `uid`, `title`, `type`, `notes` if present, one key per standard field the record type is expected to have, `custom_fields` keyed by label, and `files` (name, title, size, type — metadata, never content).
With `fields`, you get `uid`, `title`, `type` and only the named fields; `notes`, `custom_fields` and `files` are dropped entirely unless you name `"notes"` explicitly. Naming the one or two fields you need is the cheap way to cut exposure when notation does not fit — and, as a side effect, the surest way to keep unread notes out of the transcript.
With `unmask` unset, a value is masked only when its **name** matches a fixed sensitive-word list by case-insensitive substring — `password`, `secret`, `key`, `token`, `privateKey`, `cardNumber`, `cardSecurityCode`, `accountNumber`, `pin`, `passphrase`, `auth`, `routingNumber`, `licenseNumber`, `oneTimeCode`, `otp`, `answer`, `paymentCard`, `bankAccount`, `keyPair`. For standard fields the name tested is the field type; for custom fields it is the label the user typed. Masked output is `first3 + "***" + last3`, or `******` for values of six characters or fewer.
A few sub-values inside composite fields are masked by explicit rule instead: `paymentCard.cardNumber` and `.cardSecurityCode`, `bankAccount.routingNumber` and `.accountNumber`, `keyPair.privateKey`, `securityQuestion.answer`, `script.command`, `appFiller.macroSequence`, and `passkey.privateKey` (replaced outright with `***MASKED***`). Their siblings are not — `cardExpirationDate`, `publicKey`, `accountType`, every `address`, `phone` and `name` sub-value, and the whole `pam*` settings family come back in clear.
Four consequences:
present. In real MSP vaults notes routinely hold a second password, a recovery phrase, or a PIN. A "masked" `get_secret` frequently discloses more through notes than through the field it carefully starred out.
`Recovery Code`, `Service Account Credential` and `Break-glass` match nothing and come back in clear.
redacted value. Do not paste one into a ticket on the assumption that it is safe.
`oneTimeCode` / `otp` fields hold the full `otpauth://` URI. Masked, it is starred; unmasked, the record's permanent second factor is in the transcript. This is the strongest single reason to use `get_totp_code` rather than unmasking a record to read a code off it.
Upstream ksm-mcp is built to stop here and ask a human, over a terminal, with the warning *"This will expose all requested fields of the secret, including the password if present, directly TO THE AI MODEL and its context."* There is no terminal in a container, so that prompt is never shown and `unmask: true` executes directly.
Treat the warning as addressed to you instead. Before setting `unmask`, have an answer to: which field is needed, what is it for, and does the person who asked have a use for it right now. If the answer is "so I can show them the record", that is not a use — offer the masked view plus the record's title and location.
With no `fields` argument, `get_secret` iterates a **hard-coded list of field types per record type** — for a `login` record that is `login`, `password`, `url`, `oneTimeCode`, `otp`, and nothing else. A standard field
One command to supercharge Claude Code for MSP workflows. Then restart Claude Code. That's it. Documentation: mcp.wyre.ai
Repo: wyre-technology/msp-claude-plugins
3CX's native PBX MCP server: the per-PBX endpoint shape (every PBX is its own FQDN and its own OAuth authorization server — there is no shared mcp.3cx.com),…
3CX's live-operations surface: read-only visibility into active calls, recordings, voicemail, department and queue membership, and forwarding/presence…
3CX's read-only directory surface: resolving a caller by email or by exact extension, searching the PBX's own phonebooks, searching contacts synced from an…
3CX's system-and-configuration surface: server time, PBX event log and application log search, service status, database schema and the read-only SELECT-only…
Abnormal Security abuse mailbox cases: user-reported email submissions, case statuses and judgments, the case lifecycle, bulk and remediation actions, and…
Abnormal Security message analysis: message retrieval, email header inspection, attachments, sender reputation, delivery context, and SPF/DKIM/DMARC…