Skip to content
Draft
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,12 +341,12 @@ Inputs that mirror the API's nested `proxy`, `network`, `browser`, and proxy `co
- `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 vaults; use one per end user.
- `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. AgentCard `checkout_origin` is caller-declared for eligible autopilot rule matching on non-prepared checkout authorizations; Kernel forwards it without comparing it with the browser page. Omission keeps the existing approval flow, autopilot may fall back to user approval, and prepared checkout uses `preparation.merchant_origin`. It does not enable autopilot or ensure payment success.
- `manage_vault_wallets` - Connect Kernel-hosted card wallets or Kernel-managed/configured Link/AgentCard wallets, import Link grants from a trusted backend, and inspect live payment methods and eligibility.
- `manage_vault_cards` - Create card requests or update supported providers according to the API's lifecycle rules; explicitly authorize an advertised Kernel card after user approval (Visa returns a hosted spend-approval action). Does not implicitly authorize Link cards. AgentCard `checkout_origin` is caller-declared for eligible autopilot rule matching on non-prepared checkout authorizations; Kernel forwards it without comparing it with the browser page. Omission keeps the existing approval flow, autopilot may fall back to user approval, and prepared checkout uses `preparation.merchant_origin`. It does not enable autopilot or ensure payment success.
- `manage_vault_credentials` - Create credentials through one of two user-chosen paths: Kernel-hosted collection (definitions for private human collection; update values or description with version and optional immutable item identity preconditions) or 1Password brokered approval (connect a 1Password account, then create a request for 1-5 logins the user approves in the 1Password app). Agents reuse an existing credential for the site first, otherwise ask the user where their login lives before creating credentials.
- `manage_vault_items` - List, get, invoke advertised operations (including fill and `webmcp_invoke` with value-free bindings), observe events, and delete vault items. Read credential definitions, presence, version, collection links, and explicitly non-sensitive values; sensitive values remain hidden. `collect` reopens the full form; provider approvals remain user actions. Ready is not login or payment success.

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 six 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. Credential create → collect → readiness → fill is supported entirely through MCP tools. `prepare_checkout` remains API/CLI-only. The SDK dependency is pinned in `bun.lock`.
See [Vault payments](docs/vault-payments.md) for the 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 six 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. Credential create → collect → readiness → fill is supported entirely through MCP tools. `prepare_checkout` remains API/CLI-only. The SDK dependency is pinned in `bun.lock`.

### 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.

37 changes: 34 additions & 3 deletions docs/vault-payments.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,38 @@ 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.

The released Node SDK dependency is pinned in `bun.lock`.
The released Node SDK dependency is pinned in `bun.lock`. The API's Visa
`merchant_country` field is not yet in the generated SDK type; the tool validates
and forwards it unchanged.

## Kernel-hosted payment card

Use one vault per end user. Create it with `manage_vaults`, then create a wallet with
`manage_vault_wallets` using `action: "create"`, `provider: "kernel"`, `spec: {}`,
and a stable wallet key. Give the returned `card_enrollment` action URL only to the
intended cardholder in a private surface, outside the agent-controlled browser.
Never request or pass a PAN, CVC, expiration date, or hosted action URL as tool input.
Observe the wallet with `manage_vault_items` `get` until connected. Use
`manage_vault_wallets` `payment_methods` to inspect the enrolled card's advisory
`capabilities.single_use_card`: `eligible: false` means do not proceed; missing
capabilities are unknown, not proof of eligibility.

Create one card request with `manage_vault_cards` `action: "create"`,
`provider: "kernel"`, a new immutable key, and `spec` containing `wallet`, `amount` (integer
minor currency units, maximum 50000), `currency`, `merchant_name`, HTTPS
`merchant_url`, and `merchant_country` (ISO 3166-1 alpha-2; required for Visa).
This only creates a request, not a merchant payment. Kernel cards cannot be updated.
After explicit user approval and only when the card advertises `authorize`, call
`manage_vault_cards` with `action: "authorize"`, `provider: "kernel"`, the same
vault/key, and no spec. Mastercard can become ready without a hosted approval;
Visa may return a `spend_approval` action. Give that URL only to the cardholder
privately, never open it on their behalf or log it. Observe `get`/`events` until
ready; a pending response does not mean the card can be used. If `fill` is
advertised, attach the vault to a new browser and invoke that operation with
value-free bindings on the exact HTTPS origin of `merchant_url` before
`expires_at`. Fill does not submit checkout or prove payment. No aliases or
egress substitution are available. Never retry an uncertain authorization,
fill, or merchant payment; reconcile `recovery_required` with support.

## Credential collection and observation

Expand Down Expand Up @@ -254,7 +285,7 @@ The `vaults` toolset configuration can further restrict access, never grant it.
| `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_cards` | `create`, `update`, `authorize` |
| `manage_vault_credentials` | `create`, `update`, `connect_account` |
| `manage_vault_items` | `list`, `get`, `invoke`, `events`, `delete` |

Expand All @@ -270,7 +301,7 @@ to inspect the connection's scope.
`vault` accepts an ID or immutable name. `key` is an immutable item key within that
vault, not the item ID. Vault names, item keys, and project ownership cannot be renamed.

Wallet/card writes take a `provider` (`link` or `agentcard`) and a JSON `spec`
Wallet/card writes take a `provider` (`link`, `agentcard`, or `kernel`) and a JSON `spec`
**object**, not a string or a `{type, spec}` envelope. The tool injects `provider`;
if present in `spec`, it must match. Tool schemas describe the provider-specific
fields and reject unknown fields, including nested ones. No defaults or currency
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"@modelcontextprotocol/core": "2.0.0",
"@modelcontextprotocol/server": "2.0.0",
"@onkernel/managed-auth-react": "0.5.5",
"@onkernel/sdk": "0.117.0",
"@onkernel/sdk": "0.119.0",
"@posthog/mcp": "0.17.0",
"@types/jsonwebtoken": "^9.0.10",
"@types/redis": "^4.0.11",
Expand Down
69 changes: 59 additions & 10 deletions src/lib/mcp/tools/vault-cards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ import type { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";
import type { McpDependencies } from "@/lib/mcp/dependencies";
import { projectForOperation } from "@/lib/mcp/project-selection";
import { throwVaultError, vaultItemResponse } from "@/lib/mcp/vault-responses";
import {
throwKernelVaultError,
throwVaultError,
vaultItemResponse,
} from "@/lib/mcp/vault-responses";
import { errorResponse } from "@/lib/mcp/responses";
import {
agentcardCardSpecSchema,
linkCardSpecSchema,
kernelCardSpecSchema,
vaultItemSchema,
vaultKeySchema,
vaultProviderSchema,
Expand All @@ -20,17 +26,22 @@ export function registerVaultCardTools(
"manage_vault_cards",
{
description:
'configure payment card requests in a per-end-user vault, not merchant payments. use wallet/card items for credit card numbers, security codes, and expiration dates; never store that data in credential items. 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. for agentcard, optional checkout_origin is a caller-declared canonical https origin (or localhost http origin) that KERNEL forwards for eligible autopilot rule matching on non-prepared checkout authorizations. KERNEL does not compare it with the browser page; it does not enable autopilot or ensure payment success. omitting it retains the existing approval flow, and autopilot may fall back to user approval. prepared checkout uses preparation.merchant_origin. eligible unused agentcard cards advertise a checkout-preparation operation for supported tokenization checkout; invoke it through manage_vault_items with the api-required checkout inputs. keep the returned approval page open, poll until ready_to_submit, and submit native pay before preparation.expires_at. preparations are single-use, even after failure or expiry. 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 in a per-end-user vault, not merchant payments. KERNEL cards use a connected KERNEL wallet, amount in minor units, https merchant_url and optional iso merchant_country (required by visa). "authorize" is only for KERNEL cards: after explicit user approval it invokes the currently advertised authorize operation, returning a visa spend_approval action for the cardholder or an issued mastercard card. give action urls only to the intended user privately; do not open them or include them in logs/traces. KERNEL cards cannot be updated; inspect with manage_vault_items get/events, and use advertised fill only when ready. card enrollment is hosted; never accept card numbers, cvc, or expiration data in tool inputs or credential items. 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. for agentcard, optional checkout_origin is a caller-declared canonical https origin (or localhost http origin) that KERNEL forwards for eligible autopilot rule matching on non-prepared checkout authorizations. KERNEL does not compare it with the browser page; it does not enable autopilot or ensure payment success. omitting it retains the existing approval flow, and autopilot may fall back to user approval. prepared checkout uses preparation.merchant_origin. eligible unused agentcard cards advertise a checkout-preparation operation for supported tokenization checkout; invoke it through manage_vault_items with the api-required checkout inputs. keep the returned approval page open, poll until ready_to_submit, and submit native pay before preparation.expires_at. preparations are single-use, even after failure or expiry. 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.',
inputSchema: vaultToolInput({
...vaultItemSchema,
key: vaultKeySchema(),
action: z.enum(["create", "update"]),
action: z.enum(["create", "update", "authorize"]),
provider: vaultProviderSchema,
spec: z
.union([linkCardSpecSchema, agentcardCardSpecSchema])
.union([
linkCardSpecSchema,
agentcardCardSpecSchema,
kernelCardSpecSchema,
])
.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.",
),
"(create/update) full provider specification object, not a {type, spec} envelope. embedded provider must match provider. KERNEL: wallet, amount, currency, merchant_name, https merchant_url, and merchant_country for visa. no defaults or normalization are applied.",
)
.optional(),
}),
annotations: {
title: "configure KERNEL vault cards",
Expand All @@ -50,16 +61,52 @@ export function registerVaultCardTools(
);
const options = { maxRetries: 0, signal: ctx.mcpReq.signal };
try {
if (params.action === "authorize") {
if (params.provider !== "kernel" || params.spec !== undefined)
return errorResponse(
"authorize requires provider kernel and no spec.",
);
const current = await client.vaults.items.retrieve(
params.key,
{ id_or_name: params.vault },
options,
);
if (
current.type !== "card" ||
current.spec.provider !== "kernel" ||
!current.available_operations.some((op) => op.type === "authorize")
)
return errorResponse(
"kernel card does not advertise authorize; inspect item state and events.",
);
const item = await client.vaults.items.performOperation(
params.key,
{ id_or_name: params.vault, type: "authorize" },
options,
);
return vaultItemResponse(item, target);
}
if (params.provider === "kernel" && params.action === "update")
return errorResponse(
"kernel card updates are not supported; inspect the existing item.",
);
if (!params.spec)
return errorResponse("spec is required for create/update.");
const spec =
params.provider === "link"
? {
...linkCardSpecSchema.parse(params.spec),
provider: params.provider,
}
: {
...agentcardCardSpecSchema.parse(params.spec),
provider: params.provider,
};
: params.provider === "agentcard"
? {
...agentcardCardSpecSchema.parse(params.spec),
provider: params.provider,
}
: {
...kernelCardSpecSchema.parse(params.spec),
provider: params.provider,
};
const item =
params.action === "create"
? await client.vaults.items.upsert(
Expand All @@ -74,6 +121,8 @@ export function registerVaultCardTools(
);
return vaultItemResponse(item, target);
} catch (error) {
if (params.provider === "kernel")
throwKernelVaultError("manage_vault_cards", params.action);
throwVaultError("manage_vault_cards", params.action, error);
}
},
Expand Down
Loading
Loading