Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,13 @@ Call `get_connection_context` before deciding whether to create or select a proj
- `manage_auth_connections` - Create, list, get, update, delete, login, submit, inspect timelines, and wait for managed-auth connections in every client. Supports health-check and automatic re-auth settings, managed-auth browser configuration, and canonical interaction-bound field/choice submissions. Use domain-filtered `list` for discovery. App-capable clients additionally receive `open_auth_login`; the programmatic actions remain available there too.
- `manage_credentials` - Create, list, get, update, and delete stored credentials; fetch a current TOTP code for credentials with a configured totp_secret.
- `manage_credential_providers` - Create, list, get, update, and delete external credential providers (e.g. 1Password); list available items and test the provider connection.
- `manage_vault_provider_configs` - Create, list, get, rename, rotate secrets, and delete organization-owned Link and AgentCard configurations. Writes require organization scope.
- `manage_vaults` - Create, list, get, and delete project-owned payment vaults.
- `manage_vault_wallets` - Connect Link or AgentCard wallets and inspect live payment methods.
- `manage_vault_cards` - Create card requests or replace their full specification; does not implicitly authorize Link cards.
- `manage_vault_wallets` - Connect Kernel-managed or configured Link/AgentCard wallets, import Link grants from a trusted backend, and inspect live payment methods.
- `manage_vault_cards` - Create or update card requests according to the API's lifecycle rules; does not implicitly authorize Link cards.
- `manage_vault_items` - List, get, invoke advertised operations, observe events, and delete vault items. Provider approvals remain user actions; ready does not mean paid.

See [Vault payments](docs/vault-payments.md) for both provider flows, safety rules, and response shapes. `manage_browsers` accepts creation-only `vaults` references (max 20); existing sessions and pools cannot gain vault bindings. The four vault tools share the `vaults` toolset and prepare/observe credentials rather than submitting merchant payments. They are exposed only when `GET /org/entitlements` reports `features.vaults.enabled: true` for the current credential; missing or unavailable entitlements hide them. Toolset configuration cannot override this access check.
See [Vault payments](docs/vault-payments.md) for both provider flows, safety rules, and response shapes. `manage_browsers` accepts creation-only `vaults` references (max 20); existing sessions and pools cannot gain vault bindings. The five vault tools share the `vaults` toolset and prepare/observe credentials rather than submitting merchant payments. They are exposed only when `GET /org/entitlements` reports `features.vaults.enabled: true` for the current credential; missing or unavailable entitlements hide them. Toolset configuration cannot override this access check. Provider configuration support uses the released `@onkernel/sdk` 0.101.0.

### Standalone tools

Expand Down
4 changes: 2 additions & 2 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

107 changes: 94 additions & 13 deletions docs/vault-payments.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,36 @@ The vault tools prepare and observe payment credentials. They do **not** submit
merchant payments, expose real card values, or complete provider approval actions.
They use the same vault API as the Kernel CLI.

**These are live payment cards. Test-mode creation is unsupported.** Do not assume
that a development or staging MCP endpoint makes a card request a test transaction.
**Assume real payment effects.** Mode comes from the selected provider credentials;
there is no per-item test flag. AgentCard configuration responses report the
introspected `test_mode`. A development or staging MCP endpoint does not make a
card request a test transaction.

Provider configuration support uses the released Node SDK 0.101.0.

## Tools and scope

The four vault tools are exposed only when the current credential's
The five vault tools are exposed only when the current credential's
`GET /org/entitlements` response reports `features.vaults.enabled: true`.
Access is rechecked on every authenticated MCP request, including tool calls,
without caching grants across requests or connections. A missing field, malformed
response, or failed lookup hides the vault tools but leaves other toolsets usable.
The lookup has a five-second timeout, forwards cancellation, and is not retried.
The `vaults` toolset configuration can further restrict access, never grant it.

| Tool | Actions |
| ---------------------- | ------------------------------------------- |
| `manage_vaults` | `create`, `list`, `get`, `delete` |
| `manage_vault_wallets` | `create`, `payment_methods` |
| `manage_vault_cards` | `create`, `update` |
| `manage_vault_items` | `list`, `get`, `invoke`, `events`, `delete` |
| Tool | Actions |
| ------------------------------- | ------------------------------------------- |
| `manage_vault_provider_configs` | `create`, `list`, `get`, `update`, `delete` |
| `manage_vaults` | `create`, `list`, `get`, `delete` |
| `manage_vault_wallets` | `create`, `payment_methods` |
| `manage_vault_cards` | `create`, `update` |
| `manage_vault_items` | `list`, `get`, `invoke`, `events`, `delete` |

Provider configurations are organization-owned and do not accept a project
selector. Reads are available to project-scoped credentials; writes require an
organization-scoped connection. The API remains the authorization authority.

Every tool accepts an optional `project` name or ID. Vaults are project-owned;
The other four tools accept an optional `project` name or ID. Vaults are project-owned;
omitting `project` uses the API's effective default project, **not** all projects.
Project-scoped connections cannot switch projects. Use `get_connection_context`
to inspect the connection's scope.
Expand All @@ -51,6 +60,70 @@ For browser checkout automation too, use `vaults browsers playwright computer`.
To hide the payment tools, set `KERNEL_MCP_DISABLED_TOOLSETS=vaults`.
This filters discovery; API authorization still enforces resource access.

## Provider configurations and imported grants

`manage_vault_provider_configs` supports both `link` and `agentcard`:

- `create`: `name`, `provider`, and `credentials: {client_id, client_secret}`.
Duplicate names return a conflict, never a credential replacement.
- `get` / `delete`: `config` selects an ID or name. Deletion requires confirmation
and is blocked while any non-deleted item references the config.
- `list`: optional `limit` (1–100) and `offset` (0 or greater); returns one page
with `items`, `has_more`, and `next_offset`.
- `update`: `config` plus `name` and/or `credentials: {client_secret}`. Omitted
fields stay unchanged. Provider, client ID, and credential mode cannot change.
Secret rotation affects all wallets bound to the configuration.

Client secrets and imported tokens are write-only inputs for a **trusted backend
or client**. Do not ask users to paste them into chat. Do not use a client that logs
MCP arguments. The server disables SDK payload logging and omits credentials from
output and analytics; validation and API failures do not return raw secret bodies.
Public configuration responses contain ID, name, provider, non-secret client ID,
timestamps, and AgentCard's introspected mode only.

Configuration credentials identify an application; **they are not user grants**.
A customer-managed Link wallet requires the backend to complete Link OAuth first,
then call `manage_vault_wallets` with the following specification (placeholders are
not real credentials):

```json
{
"action": "create",
"vault": "checkout",
"key": "imported-wallet",
"provider": "link",
"spec": {
"authorization": {
"method": "oauth",
"client": {
"type": "customer_managed",
"provider_config": { "name": "my-link-client" }
},
"tokens": {
"access_token": "<valid-access-token-from-backend>",
"refresh_token": "<same-grant-refresh-token-from-backend>"
}
}
}
}
```

Both tokens must belong to the referenced client and the same grant. Import
requires a valid access token; refresh expired access in the backend first.
After import, **Kernel owns refresh-token rotation**; stop refreshing that grant
in the backend. Configuration selection alone does not start hosted Link OAuth.

Use exactly one config `id` or `name`. Responses preserve the resolved config ID;
renaming does not rebind wallets. An identical wallet create never replaces its
grant, even after rotation or degradation. Changing config requires a new wallet.
There is no in-place imported reauthorization: obtain a fresh grant and use a new
wallet key for **new payments only**. Existing cards remain bound to the old wallet;
retain unresolved attempts for provider/support reconciliation, not retries.

For AgentCard, add `"provider_config": {"name": "my-agentcard"}` to the wallet
`spec`; no user OAuth tokens are accepted. Omit it to retain Kernel-managed
credentials. A reused `user_id` must belong to the same organization and config.

## Link flow

1. Create or retrieve a vault with `manage_vaults`:
Expand Down Expand Up @@ -157,7 +230,7 @@ then connect a wallet with `manage_vault_wallets`:
```

Complete the returned enrollment action. Alternatively, `spec.user_id` may refer
to a user already enrolled in this organization. Once connected, configure a card
to a user already enrolled in this organization under the same configuration. Once connected, configure a card
with `manage_vault_cards`:

```json
Expand Down Expand Up @@ -216,8 +289,16 @@ A reusable card remaining `ready` does not establish that the last payment succe
No vault request is automatically retried. After a failed, timed-out, rejected,
or indeterminate payment, inspect state/events; do not replay checkout, invoke
again, or reconfigure a card to retry it.
- Card `update` replaces the **entire spec**; omitted optional fields are removed.
The API decides when a card can be reconfigured.
- Requested-card `update` replaces the spec. Pending issuance updates preserve
omitted optional fields and clear explicit empty lists; only provider-supported
changes are allowed. Provider/wallet bindings cannot change after authorization
starts. The tool forwards omissions and empty values without normalization.
The API decides which edits are allowed; an uncertain update enters
`recovery_required` and must not be retried.
- `recovery_required` is preserved in responses and ends the API's bounded wait.
It is neither decline nor expiry. Stop payment attempts and reconcile with the
provider or support. There is no reset or caller-asserted reconciliation tool.
Unresolved cards can also block deletion of their wallet and vault.
- Browser attachments accept at most 20 references, each containing exactly one
`id` or `name`. They are creation-only and unavailable for browser pools. You
cannot add vaults to an existing browser. Vault-bound browser creation also
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@clerk/themes": "^2.4.19",
"@modelcontextprotocol/sdk": "1.26.0",
"@onkernel/managed-auth-react": "0.5.1",
"@onkernel/sdk": "^0.100.0",
"@onkernel/sdk": "^0.101.0",
"@posthog/mcp": "0.10.1",
"@types/jsonwebtoken": "^9.0.10",
"@types/redis": "^4.0.11",
Expand Down
10 changes: 10 additions & 0 deletions src/lib/mcp/kernel-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ import { describe, expect, test } from "bun:test";
import { createKernelClient } from "@/lib/mcp/kernel-client";

describe("createKernelClient", () => {
test("disables SDK payload logging even when KERNEL_LOG requests debug", () => {
const previous = process.env.KERNEL_LOG;
process.env.KERNEL_LOG = "debug";
try {
expect(createKernelClient("test-key").logLevel).toBe("off");
} finally {
if (previous === undefined) delete process.env.KERNEL_LOG;
else process.env.KERNEL_LOG = previous;
}
});
test("uses an explicit project before the server default", () => {
const previous = process.env.KERNEL_PROJECT;
process.env.KERNEL_PROJECT = "proj_default";
Expand Down
2 changes: 2 additions & 0 deletions src/lib/mcp/kernel-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Kernel } from "@onkernel/sdk";
export function createKernelClient(apiKey: string, project?: string) {
return new Kernel({
apiKey,
// SDK debug logging includes request bodies, which can contain vault secrets.
logLevel: "off",
project: project ?? process.env.KERNEL_PROJECT,
baseURL: process.env.API_BASE_URL,
defaultHeaders: {
Expand Down
1 change: 1 addition & 0 deletions src/lib/mcp/register.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ describe("MCP toolset allowlist", () => {
]);
expect(captureRegistration(mcpApps, true).legacyTools).toEqual([
"get_connection_context",
"manage_vault_provider_configs",
"manage_vault_wallets",
"manage_vault_cards",
"manage_vault_items",
Expand Down
7 changes: 4 additions & 3 deletions src/lib/mcp/tools/vault-cards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
vaultItemSchema,
vaultKeySchema,
vaultProviderSchema,
vaultToolInput,
} from "@/lib/mcp/vault-schemas";

export function registerVaultCardTools(
Expand All @@ -17,8 +18,8 @@ export function registerVaultCardTools(
) {
server.tool(
"manage_vault_cards",
'Configure requests for live payment cards, not merchant payments. Test-mode creation is unsupported. "create" creates or retrieves an identical card request by immutable key. "update" replaces the ENTIRE spec, removing omitted optional fields, only when the API permits it. Neither implicitly authorizes Link: inspect available_operations with manage_vault_items and obtain explicit user approval before invoking. AgentCard authorizes at checkout. Amounts are integer minor currency units. No card data, OAuth tokens, provider secrets, or domain configuration. Never reconfigure a card to retry a failed, timed-out, rejected, or indeterminate payment. Requests are not automatically retried.',
{
'Configure payment card requests, not merchant payments. Mode is determined by the wallet credentials, not a per-item test flag; never assume a test transaction. "create" creates or retrieves an identical card request by immutable key. "update" replaces requested-card specs. Pending issuance updates preserve omitted optional fields and clear explicit empty lists, only for provider-supported edits allowed by the API. Wallet/provider binding cannot change after authorization starts. Uncertain updates enter recovery_required; do not retry. Neither implicitly authorizes Link: inspect available_operations with manage_vault_items and obtain explicit user approval before invoking. AgentCard authorizes at checkout. Amounts are integer minor currency units. No card data, OAuth tokens, provider secrets, or domain configuration. Never reconfigure a card to retry a failed, timed-out, rejected, or indeterminate payment. Requests are not automatically retried.',
vaultToolInput({
...vaultItemSchema,
key: vaultKeySchema(),
action: z.enum(["create", "update"]),
Expand All @@ -28,7 +29,7 @@ export function registerVaultCardTools(
.describe(
"Full provider specification object, not a {type, spec} envelope. Embedded provider must match provider. No defaults or normalization are applied. Integers must be within JavaScript's safe range, including expires_at.",
),
},
}),
{
title: "Configure Kernel vault cards",
readOnlyHint: false,
Expand Down
7 changes: 4 additions & 3 deletions src/lib/mcp/tools/vault-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
vaultItemSchema,
vaultKeySchema,
vaultWaitSchema,
vaultToolInput,
} from "@/lib/mcp/vault-schemas";

export function registerVaultItemTools(
Expand All @@ -25,8 +26,8 @@ export function registerVaultItemTools(
) {
server.tool(
"manage_vault_items",
'Inspect payment vault items and immutable audit events. "list" reads items; "get" reads state, public aliases, required user actions, available_operations, and available_expansions. "invoke" fetches the item again and submits only an advertised operation; read its description and obtain explicit user approval first. Provider actions (OAuth, enrollment, MFA, approval) must be completed by the user, not invoked as operations. "events" observes outcomes; use the last event ID as after. "delete" invalidates an item credential; confirm with the user first. Ready does not mean paid. Requests are never automatically retried. Do not retry failed, timed-out, rejected, or indeterminate payments; inspect state/events instead.',
{
'Inspect payment vault items and immutable audit events. "list" reads items; "get" reads state, public aliases, required user actions, available_operations, and available_expansions. "invoke" fetches the item again and submits only an advertised operation; read its description and obtain explicit user approval first. Provider actions (OAuth, enrollment, MFA, approval) must be completed by the user, not invoked as operations. "events" observes outcomes; use the last event ID as after. "delete" invalidates an item credential; confirm with the user first. Unresolved payments block item and parent deletion. recovery_required is not decline or expiry: stop payment attempts and reconcile with the provider or support; no reset exists. Ready does not mean paid. Requests are never automatically retried. Do not retry failed, timed-out, rejected, or indeterminate payments; inspect state/events instead.',
vaultToolInput({
...vaultItemSchema,
action: z.enum(["list", "get", "invoke", "events", "delete"]),
key: vaultKeySchema()
Expand Down Expand Up @@ -54,7 +55,7 @@ export function registerVaultItemTools(
"(events) Return events after this event ID; preserve the vault and item key.",
)
.optional(),
},
}),
{
title: "Inspect and operate Kernel vault items",
readOnlyHint: false,
Expand Down
Loading
Loading