run402-mcp
Version:
MCP server for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.
101 lines • 4.41 kB
TypeScript
/**
* `writeApproval` — the passkey-signed, target-scoped credential a person
* signed in on the command line needs to provision, deploy, or write secrets
* without a wallet. Reached as `r.writeApproval.*`.
*
* The ceremony: {@link WriteApproval.requestChallenge} opens a passkey approval
* scoped to one `(action, target)` and returns a same-origin `confirm_url`; the
* person approves with their passkey in the browser; the confirm page redirects
* to the CLI's `127.0.0.1` loopback with a one-time `code`;
* {@link WriteApproval.exchangeClaimCode} (PKCE) mints the token. The token is
* sent as `X-Run402-Write-Approval: Bearer <write_approval_token>` beside the
* sign-in session bearer, and dies with that session. A write approval never
* satisfies step-up.
*
* Isomorphic seams — the loopback server and PKCE generation live in the Node
* CLI (`run402 approve`).
*/
import type { Client } from "../kernel.js";
import type { WriteApprovalCapability } from "../credentials.js";
/** Input to {@link WriteApproval.requestChallenge}. */
export interface WriteApprovalChallengeInput {
/** The capability to approve. Determines whether `orgId` or `projectId` is required. */
action: WriteApprovalCapability;
/** Required for `org.project.create`. */
orgId?: string;
/** Required for the project-scoped capabilities (`project.deploy`, `project.secret.write`, …). */
projectId?: string;
/** The CLI's loopback redirect, e.g. `http://127.0.0.1:54321/callback`. */
cliRedirectUri: string;
/** PKCE S256 challenge = base64url(sha256(verifier)). */
codeChallenge: string;
/** Opaque CSRF state echoed back on the loopback redirect. */
state: string;
/**
* The sign-in session bearer. Falls back to the client's default auth when
* omitted — pass it explicitly unless the client was constructed with
* sign-in session credentials.
*/
token?: string;
}
/** Result of {@link WriteApproval.requestChallenge}. Forward-compatible. */
export interface WriteApprovalChallengeResult {
challenge_id: string;
confirm_url: string;
expires_at?: string;
action?: string;
org_id?: string | null;
project_id?: string | null;
delivery?: "cli_loopback" | "postmessage" | (string & {});
[key: string]: unknown;
}
/** Input to {@link WriteApproval.exchangeClaimCode}. */
export interface WriteApprovalClaimInput {
/** Authorization code received on the loopback redirect. */
code: string;
/** The PKCE verifier whose hash was sent as `codeChallenge`. */
codeVerifier: string;
/** Must match the `state` used at challenge time. */
state: string;
}
/** One write approval's metadata as the gateway reports it (never the token). */
export interface WriteApprovalSessionInfo {
write_approval_session_id: string;
authenticator_class?: string;
org_id?: string | null;
project_id?: string | null;
capabilities?: string[];
risk_ceiling?: string;
/** ISO-8601 idle expiry — the token's usable life. */
idle_expires_at?: string;
/** ISO-8601 absolute expiry. */
absolute_expires_at?: string;
[key: string]: unknown;
}
/** Minted write-approval token payload, returned ONCE. Forward-compatible. */
export interface WriteApprovalTokenResult {
write_approval_token: string;
/** Always `"write_approval"`. */
token_type?: string;
/** Always `"X-Run402-Write-Approval"`. */
header?: string;
session?: WriteApprovalSessionInfo | null;
[key: string]: unknown;
}
export declare class WriteApproval {
private readonly client;
constructor(client: Client);
/**
* Open a scoped approval (`POST /agent/v1/control-plane/write-approval/challenges`).
* Carries the sign-in session bearer; a `device`-grade session is refused.
*/
requestChallenge(input: WriteApprovalChallengeInput): Promise<WriteApprovalChallengeResult>;
/**
* Exchange the loopback claim `code` (+ PKCE verifier + `state`) for the
* write-approval token (`POST …/write-approval/cli/token`). No `redirect_uri`
* — it is bound at challenge time. Unauthenticated (code + verifier are the
* credential); the minted token is still bound to the issuing sign-in session.
*/
exchangeClaimCode(input: WriteApprovalClaimInput): Promise<WriteApprovalTokenResult>;
}
//# sourceMappingURL=write-approval.d.ts.map