run402-mcp
This server is a full-stack backend provisioning and management API for Run402 projects, letting an agent create and operate Postgres databases, REST APIs, auth, storage, serverless functions, static sites, and deploys without a human console.
Provision & manage projects: create Postgres projects (
provision_postgres_project), list/rename/delete them, check tier pricing and usage, and manage org-level lease/admin actions.Run SQL & REST queries: execute arbitrary SQL (
run_sql), query/mutate tables via PostgREST with anon or service keys (rest_query), and introspect schema/RLS (get_schema).Declarative authorization: apply convergent expose manifests for tables/views/RPCs (
apply_expose), validate them (validate_manifest), and read the current manifest (get_expose).Deploy apps & sites: run the full
run402 upworkflow (app_up), apply unified ReleaseSpecs with migrations, functions, sites, routes, subdomains, and assets (deploy), deploy static sites from inline files or directories, diagnose/resolve URLs, list/diff releases, and resume/verify deploys.Serverless functions: deploy Node 22 functions with bundled
@run402/functionshelpers, invoke them, update/delete/rebuild, manage durable runs (schedule, retry, cancel, redrive), and fetch logs.Storage & assets: upload/download/list/delete blobs, generate presigned URLs, diagnose CDN state, wait for CDN freshness, and use immutable content-addressed URLs.
Secrets & config: set/list/delete project secrets for function env injection.
CI/CD: create/list/get/revoke GitHub Actions OIDC deploy bindings with optional route scopes.
Snapshots & branches: create/list/get/restore/delete project snapshots and create/renew/delete contained branch projects.
Portable archives: export, inspect, verify, and import portable
.r402arproject archives for Core/Cloud portability.Payments & billing: call arbitrary URLs with x402 payment (
pay_url), check allowance/balance, request testnet faucet, set/check tier, and list tenant payments for priced routes.Apps marketplace: browse/fork/publish apps and list published versions.
Subdomains: claim/delete/list custom subdomains.
Project transfers: initiate, preview, accept/claim, cancel, and list incoming/outgoing project transfers.
User roles: promote/demote users to project_admin by email.
Image generation: generate PNG images from prompts (square/landscape/portrait) via x402.
Managed jobs: submit/get/log/cancel/purge platform-managed jobs and download their artifacts.
Admin/moderation: archive/reactivate projects and toggle org lease-perpetual escape hatch (platform-admin only).
Enables management of PostgreSQL databases through the Run402 platform, including provisioning, schema updates, and access control via expose manifests.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@run402-mcpProvision a new hobby tier Postgres database for my app"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Run402 is open-source backend infrastructure for AI agents and coding agents — a backend-as-a-service addressed to a machine rather than to a person. An autonomous agent provisions a Postgres database, user auth, file storage, serverless functions and site hosting, ships them through one staged deploy workflow, and pays for the usage itself. Comparable in surface to Supabase, Firebase or Vercel; different in that there is no dashboard you have to sign into to get started (the console exists for people; the agent never needs it) and no human-issued API key to copy.
This is the backend Kychee's open products run on. We needed a layer an agent can drive end to end, with room for whatever each app turns out to need, and nothing off the shelf had all of it, so we built it and opened it the same way we open the apps: this repo holds the agent surfaces (MIT), run402-core holds the open self-hostable runtime slice (Apache-2.0; the managed Cloud control plane remains proprietary, see CLOUD_VS_CORE.md), and kysigned is the first product running on it.
One call to run402 gives an agent a full Postgres database, REST API, user auth, content-addressed file storage, static site hosting, serverless functions, and image generation, paid with x402 (USDC on Base) or MPP (pathUSD on Tempo, or sats over Bitcoin Lightning) — or card-funded allowance. The prototype tier is free on testnet.
Run402 is agent-first because agents are first-class participants, not because people disappear. A person or agent acts through its own Run402 principal and authenticator, and its actions remain attributable. Identity answers who acted; memberships, roles, grants, grant keys, freshness, and spend policy determine what that principal may do.
An autonomous agent may remain the legitimate owner of the org-of-one it creates. People may join through explicit co-ownership. Agents entering somebody else's organization receive bounded authority instead of borrowing a human account. Different keys. Equal standing. Explicit authority.
Use the CLI by default to provision, deploy, inspect and recover. Use the typed, opinionated SDK when writing programmatic TypeScript/JavaScript workflows; shell scripts and CI can keep using CLI. MCP serves MCP-native hosts, and direct HTTP supports deliberate lower-level integrations.
This monorepo ships these interfaces:
Surface | Use when… |
Terminal, scripts, CI, agent-controlled shells: JSON in, JSON out, exit code on failure | |
Calling run402 from TypeScript: typed kernel, isomorphic (Node 22 / Deno / Bun / V8 isolates) with a Node entry that auto-loads the local keystore + wallet + x402 / Lightning fetch | |
Claude Desktop, Cursor, Cline, Claude Code: core run402 operations as MCP tools | |
OpenClaw agents (no MCP server required) | |
Buzz people and agents: install from run402.com, preflight/link one agent's dedicated identities, deploy a contextual demo, then offer human co-ownership through a normal HTTPS/passkey handoff; Buzz remains unchanged | |
Imported inside deployed functions ( | |
Astro integration for SSR, ISR cache, hosted auth components, and image variants |
These interfaces share a single typed kernel where appropriate: @run402/sdk. MCP tools, CLI subcommands, and OpenClaw scripts are thin shims over SDK calls. @run402/functions is the in-function helper that runs inside deployed code; the npm package on the registry is the artifact Cloud bundles. @run402/astro layers the SDK and functions runtime into Astro's build and SSR flow. The HTTP API is the foundation; the SDK owns shared client workflows and orchestration; CLI and MCP expose them in machine-friendly forms. Native SDK/MCP references explain intentional alternatives.
Deploy summaries share the SDK workflow view. CLI writes redacted detail under .run402/diagnostics/; MCP retains it through expand_result. Typed SDK callers keep the full result. Snapshot collection excludes platform runtime files automatically.
30-second start
First create the complete run402.json and index.html from Your first deploy. Run these commands in that application directory; --name requests a new project.
npm install -g run402@latest
run402 up --name my-app -y # bootstrap wallet/tier/project/link, then deploy manifest
run402 up verify # rerun app HTTP verification without deploying
run402 up --verify # deploy, then wait for gateway/edge coherenceThat's a real Postgres database + a deployed static site, paid for autonomously with testnet USDC.
Buy from any x402 seller with the same wallet and a default $0.10 ceiling:
run402 pay https://seller.example/translate --method POST \
--body '{"text":"hello"}' --max-usd 0.05 \
--idempotency-key translation:1 --require-receiptThe SDK equivalent is
r.pay.fetch(url, init, { maxUsdMicros, idempotencyKey, requireReceipt });
MCP callers run the same SDK call as a run snippet. All three return the
same x402-commerce-result.v1 settlement, movement/replay, delivery, offer,
merchant-receipt, signer-relationship, policy, and raw-evidence fields and pass
unpriced URLs through with payment: null. Requiring a receipt rejects before
payment when no wallet-rooted offer is eligible. If a promised receipt cannot
be verified after settlement, PaymentPolicyError retains the upstream
response and paid result and tells the caller to reconcile—never to pay again.
For a
trusted Run402 PAYMENT_INTENT_PENDING, all three surfaces prescribe one
recovery path: wait for Retry-After, then repeat the same request with the
same payer and key. Never replace the key. The SDK and MCP can also re-present
an ambiguous proof while their process remains alive; custom/arbitrary sellers
remain ambiguous and require reconciliation.
Prefer run402 up when a repo has run402.deploy.json or app.json. The CLI stays a thin shim over the Node SDK action runner (r.actions.run(...) / r.up(...)): it validates the manifest first, then recursively performs only the missing prerequisites. Project resolution is --project, .run402/project.json, manifest project_id, approved creation from --name; global active state never selects a deploy target. --name is project creation/link metadata only; it is not part of the deploy manifest and never renames an existing project. Use --check for local validation and --plan for gateway-reviewed intent before applying. Local validation covers every file the manifest references (migration sql_path/sql_file, function sources and files, site paths and dir() targets, assets.put sources): a missing one fails with MANIFEST_FILE_MISSING (details.missing[] of { field_path, path, kind }, one create_file next action per file) before any gateway call, in every mode and in run402 deploy. With no manifest in the working directory, UP_MANIFEST_REQUIRED looks one directory down and names what it found (details.nearby_manifests[], a read-only run_in_directory action for a single candidate, or one unranked select_application action for multiple apps); --manifest <path> to a missing file is a typed MANIFEST_NOT_FOUND.
If an app manifest defines verify.http[], run402 up verifies those URLs after deploy. Fresh run402 edge sentinel misses are reported as propagation_pending rather than permanent failures while the binding is still converging; tune that wait with --propagation-budget-s (default 120) or return immediately with --no-propagation-wait. run402 up verify reruns the same HTTP checks without uploading, deploying, creating projects, or mutating resources.
The CLI checks for newer run402 releases opportunistically and fail-open. Success stdout stays the command result; stale-version notices are advisory JSON on stderr, or cli.update_available NDJSON events in --json-stream. run402 doctor --refresh is the explicit live npm check and reports the install context plus the safest upgrade command for local, global, or ephemeral installs. run402 doctor answers { ok, blocking[], warnings[], checks[] }: ok is true exactly when blocking[] is empty, every check carries severity: "blocking" | "advisory" | "info", advisory findings (an unbound passkey, a stale CLI, vault gaps, a tier-less own org that can still reach another org's projects: TIER_MISSING_ON_OWN_ORG) land in warnings[] without changing ok or the exit code, and the tier check's status is a fixed vocabulary (ok | inactive | frozen | past_due | dormant | purged | missing | unknown | error, never a tier name; the name and raw lifecycle are in value.tier / value.lifecycle).
Typed deploy configs use the same commands. Executable configs are trusted local code, so v1 only runs them when passed explicitly:
run402 up --manifest run402.deploy.ts --check
run402 up --manifest run402.deploy.ts --plan
run402 up --manifest run402.deploy.ts --require-plan plan_...--check and --print-spec are local-only (both verify that every referenced file exists). --plan asks the gateway for a reviewed plan with plan_id, plan_fingerprint, warnings, diff, and one next action. --require-plan reapplies only if the normalized spec and reviewed gateway events still match.
import { defineConfig, dir, nodeFunction, sqlFile } from "@run402/sdk/config";
export default defineConfig(({ env }) => ({
project_id: env.required("RUN402_PROJECT_ID"),
database: { migrations: [sqlFile("db/001_init.sql")] },
site: { replace: dir("dist"), public_paths: { mode: "implicit" } },
functions: { replace: { api: nodeFunction("dist/functions/api.js") } },
secrets: { require: ["OPENAI_API_KEY"] },
}));Helpers normalize to the same ReleaseSpec as JSON manifests. dir() walks deterministically and rejects unsafe files unless explicitly allowed, sqlFile() derives the migration id from the filename unless supplied, and nodeFunction() currently expects JavaScript output; point TypeScript functions at built .js files.
Related MCP server: Database MCP Server
The patterns
Paste-and-go assets: content-addressed URLs with SRI
Upload files with the CLI. Keep the returned AssetRef, including immutable identity and image variants, when saving references in application data. Do not reconstruct content hashes or variant URLs yourself.
run402 assets put ./logo.png ./app.js ./app.css --project prj_exampleUse a manifest asset slice when these files must activate with a release. See the storage guide and native SDK AssetRef helpers for HTML emitters and programmatic composition. Binary files must remain bytes; never read them as UTF-8 before uploading.
Dark-by-default tables + the expose manifest
Tables you create are unreachable via /rest/v1/* until you declare them in a manifest. That closes the "agent created a table, forgot to set RLS, data leaked" footgun. A valid anon key against an existing but undeclared table gets a structured 403 TABLE_NOT_EXPOSED (never a bare Postgres 42501) whose next_actions say exactly that: expose_table (declare it and redeploy), edit_request (the expose endpoint), or use_function (keep it dark and read it from a function with adminDb()); it is not an RLS problem. The manifest is convergent: applying it twice is a no-op; items removed between applies have their policies, grants, triggers, and views dropped.
cat > manifest.json <<'EOF'
{
"$schema": "https://run402.com/schemas/manifest.v1.json",
"version": "1",
"tables": [
{ "name": "items", "expose": true, "policy": "user_owns_rows",
"owner_column": "user_id", "force_owner_on_insert": true },
{ "name": "audit", "expose": false }
],
"views": [
{ "name": "leaderboard", "base": "items", "select": ["user_id", "score"], "expose": true }
],
"rpcs": [
{ "name": "compute_streak", "signature": "(user_id uuid)", "grant_to": ["authenticated"] }
]
}
EOF
run402 projects validate-expose <project_id> --file manifest.json
run402 projects apply-expose <project_id> --file manifest.json
run402 projects get-expose <project_id>Built-in policies: user_owns_rows (rows where owner_column = auth.uid(); with force_owner_on_insert: true a BEFORE INSERT trigger sets it), public_read_authenticated_write (anyone reads, any authenticated user writes), public_read_write_UNRESTRICTED (fully open; requires i_understand_this_is_unrestricted: true), and custom (escape hatch: your own CREATE POLICY SQL).
Use run402 projects validate-expose for a non-mutating feedback loop before applying. Optional migration SQL is used only to check manifest references; it is not executed as a PostgreSQL dry run, and this does not validate deploy manifests.
Auth-as-SDLC: put the same JSON under database.expose in your v2 ReleaseSpec. The gateway validates it against your migration SQL during deploy and rejects mismatches with a structured errors array listing every violation.
Directory deploy (advanced primitive)
For a standalone static directory on an existing project:
run402 sites deploy-dir ./dist --project prj_example > result.json 2> events.logUse run402 up for a complete application with a deploy manifest. The SDK owns file hashing, upload deduplication and release orchestration; the CLI renders progress and the result.
Same-origin web routes: static site + function ingress
Apply-v1 routes and static public paths are release resources: the release pointer activates after the required deploy stages in run402 deploy. Applied migrations and external side effects are not rolled back by changing that pointer. Release static asset paths such as events.html are distinct from browser-visible public static paths such as /events. Use site.public_paths for ordinary clean static URLs; keep routes for function ingress and exact, method-aware static aliases.
{
"project_id": "prj_...",
"site": {
"replace": {
"index.html": { "data": "<!doctype html><main id='app'></main><script>fetch('/api/hello')</script>" },
"events.html": { "data": "<!doctype html><h1>Events</h1>" }
},
"public_paths": {
"mode": "explicit",
"replace": {
"/events": { "asset": "events.html", "cache_class": "html" }
}
}
},
"functions": {
"replace": {
"api": {
"runtime": "node22",
"source": {
"data": "export default async function handler(req) { const url = new URL(req.url); return Response.json({ ok: true, path: url.pathname }); }"
}
},
"login": {
"runtime": "node22",
"source": { "data": "export default async function handler(req) { return Response.json({ ok: true }); }" }
}
}
},
"routes": {
"replace": [
{ "pattern": "/api/*", "methods": ["GET", "POST", "OPTIONS"], "target": { "type": "function", "name": "api" } },
{ "pattern": "/login", "methods": ["POST"], "target": { "type": "function", "name": "login" } }
]
}
}site.public_paths.mode: "explicit" means only the complete public_paths.replace table is directly reachable as static URLs. In the example, /events serves the release asset events.html, while /events.html is not public unless separately declared. mode: "implicit" restores filename-derived public reachability and can widen access, so review gateway warnings before confirming it.
Omit routes or pass routes: null to carry forward base routes. Use routes: { "replace": [] } to clear the route table. Route entries are an ordered replace list, not a path-keyed map. Function targets use { "type": "function", "name": "<materialized function name>" }. Static route targets use exact patterns only, methods ["GET"] or ["GET","HEAD"], and { "pattern": "/events", "methods": ["GET","HEAD"], "target": { "type": "static", "file": "events.html" } } where file is a release static asset path, not a public path, URL, CAS hash, rewrite, or redirect. Use static route targets for method-aware aliases such as static GET /login plus function POST /login; in explicit public path mode the backing asset can stay private by filename. Direct /functions/v1/:name calls remain API-key protected; browser-routed paths are public same-origin ingress.
Function routes can charge a fixed tenant x402 price before the handler runs by adding pricing: { "mode": "always", "amount_usd_micros": 250000, "pay_to": "org_default_payout" } to the route entry. 250000 is $0.25 per matching action. The portable ReleaseSpec contract also accepts receipt: "on_fulfillment" on a priced function route; a compatible host then requires the function to return payment.fulfilled(response) before it authors a receipt. Run402-hosted advertising remains gated off until the standard delegated-signer carrier is available—receipt intent never silently downgrades. Omit networks for production mainnet only; include "testnet" explicitly for testnet acceptance. Static aliases cannot be priced, direct function invocation is not monetized, and service/admin keys do not bypass a priced browser route. The owning org must have a resolvable payout wallet: set it with run402 orgs payout-wallet <org_id> <wallet_address>. Conditional credit systems should expose one fixed-price route such as POST /api/credits, then keep the rest of the app behind unpriced routes and app-local authorization.
Matching is exact or final-prefix-wildcard only. /admin and /admin/ are exact trailing-slash equivalents; /admin/* matches children but not /admin, /admin/, /admin.css, or /administrator, so deploy both /admin and /admin/* for a routed section root. Query strings are ignored for matching and preserved in the handler's full public req.url. Exact routes beat prefix routes; longest prefix wins; method-compatible dynamic routes beat static assets. A POST /login route can coexist with static GET /login HTML. Unsafe method mismatch returns 405, and matched dynamic route failures fail closed instead of falling back to static files.
Routed functions use the Node 22 Fetch Request -> Response contract: export default async function handler(req) { ... }. req.method is the browser method, and req.url is the full public URL on managed subdomains, hosts, and verified custom domains. Derive OAuth callbacks from it, for example new URL("/admin/oauth/google/callback", new URL(req.url).origin). Append multiple cookies with headers.append("Set-Cookie", value); redirects, cookies, and query strings are preserved. On priced routes, import getRoutedPaymentContext from @run402/functions, read const paymentContext = getRoutedPaymentContext(req), and key app-side idempotency by paymentContext.paymentId. For a receipt-enabled route, return payment.fulfilled(response) only after the response represents completed delivery; the helper fails closed outside a settled, current, receipt-enabled routed invocation. The context helper reads gateway-confirmed x-run402-payment-* headers and returns null for unpriced or direct calls. The raw run402.routed_http.v1 envelope is internal; do not write route handlers against it.
Recipe: static home page + SPA shell. A SPA site ships index.html as the shell serving every unmatched route (match spa_fallback), so by default GET / serves the shell too. To serve a real static home page at / while keeping the shell for app routes, ship home.html at the site root alongside index.html and add an exact root static route alias: "routes": { "replace": [ { "pattern": "/", "target": { "type": "static", "file": "home.html" } } ] }. Route matching runs before all static resolution (including the implicit / -> index.html root mapping), and SPA-fallback derivation is independent of the route table, so GET / serves home.html (route_static_alias), unmatched app routes such as /dashboard still serve the shell (spa_fallback), and named static pages keep serving unchanged (static_exact). Expect two non-blocking plan lints: STATIC_ALIAS_SHADOWS_STATIC_PATH (warn: the alias overrides what / would otherwise serve; accurate and expected here) and STATIC_ALIAS_DUPLICATE_CANONICAL_URL (info: /home.html stays directly reachable in implicit public-path mode; add <link rel="canonical"> to home.html if duplicate-content SEO matters). Omitting routes on later deploys carries the alias forward; routes.replace is total, so a pipeline that sends it must include the alias every time. Verify with run402 deploy resolve --url https://<your-site>/ --method GET (or r.project(id).apply.resolve) and confirm match: "route_static_alias" with target_file: "home.html".
Avoid routing every static file, broad method lists by default, wildcard static route targets, leading-slash static files, directory shorthand, and one-static-route-target-per-page tables that exhaust route limits. Also watch wildcard function routes that shadow direct public static paths. Warning codes to handle include STATIC_ALIAS_SHADOWS_STATIC_PATH, STATIC_ALIAS_RELATIVE_ASSET_RISK, STATIC_ALIAS_DUPLICATE_CANONICAL_URL, STATIC_ALIAS_EXTENSIONLESS_NON_HTML, and STATIC_ALIAS_TABLE_NEAR_LIMIT; inspect active routes, static_public_paths, and resolve diagnostics to distinguish the route pattern from the backing asset_path.
Resolve public URLs with the CLI or its MCP/SDK equivalents:
run402 deploy resolve https://example.com/events --project prj_123 --method GET
run402 deploy resolve --url https://example.com/events?utm=x#hero --project prj_123 --method GET
run402 deploy resolve --host example.com --path /events --project prj_123 --method GETr.project(id).apply.resolve({ url, method: "GET" }) (from MCP, a run snippet) returns would_serve, diagnostic_status, match, normalized request data, warnings, full resolution JSON, edge_propagation, and next steps. When returned, asset_path, reachability_authority, and direct explain which release asset backs the public URL and whether reachability came from implicit file-path mode, explicit site.public_paths, or a route-only static alias. Stable-host diagnostics may also include authorization_result, cas_object (sha256, exists, expected_size, actual_size), hostname-specific response_variant, route/static fields such as allow, route_pattern, target_type, target_name, and target_file, and edge_propagation (settled, propagating, or sync_pending). Known match literals are host_missing, manifest_missing, active_release_missing, unsupported_manifest_version, path_error, none, static_exact, static_index, spa_fallback, spa_fallback_missing, route_function, route_static_alias, and route_method_miss; preserve unknown future strings. Known authorization_result values include authorized, not_public, not_applicable, manifest_missing, target_missing, active_release_missing, unsupported_manifest_version, path_error, missing_cas_object, unfinalized_or_deleting_cas_object, size_mismatch, and unauthorized_cas_object. Known fallback_state values include active_release_missing, unsupported_manifest_version, and negative_cache_hit; preserve unknown future strings. result is the diagnostic body status, not the HTTP status of the SDK call, so host misses can still be successful CLI/MCP/SDK calls with would_serve: false. Do not treat resolve/diagnose as a fetch, cache purge, or cache-policy oracle; route method misses should inspect allow, CAS authorization/health failures should inspect or redeploy the affected static asset, and fresh host misses should inspect edge_propagation or rerun run402 up verify. Branch on structured JSON fields such as cache_class and preserve unknown cache classes.
Release observability exposes stable asset identity and public reachability. Inventories include release_generation, static_manifest_sha256, nullable static_manifest_metadata (file_count, total_bytes, cache_classes, cache_class_sources, spa_fallback), and static_public_paths[] when returned. site.paths lists release static assets; static_public_paths[] lists browser-visible public paths with public_path, asset_path, reachability_authority, direct, cache class, and content type. Plan and release diffs expose static_assets counters: unchanged/changed/added/removed, newly_uploaded_cas_bytes, reused_cas_bytes, deployment_copy_bytes_eliminated, legacy_immutable_warnings, previous_immutable_failures, and cas_authorization_failures.
Runtime route failure codes to branch on: ROUTE_MANIFEST_LOAD_FAILED (manifest/propagation), ROUTED_INVOKE_WORKER_SECRET_MISSING (custom-domain Worker secret), ROUTED_INVOKE_AUTH_FAILED (internal invoke signature), ROUTED_ROUTE_STALE (selected route failed release revalidation), ROUTE_METHOD_NOT_ALLOWED (method mismatch), PAYOUT_WALLET_REQUIRED / PAYOUT_WALLET_AMBIGUOUS / PAYOUT_WALLET_UNRESOLVED (priced-route payout setup), PAYMENT_PROOF_MISMATCH (stale or wrong x402 proof), and ROUTED_RESPONSE_TOO_LARGE (body over 6 MiB).
GitHub Actions OIDC deploys: link once, deploy with the same CLI
For repo-driven deploys, run402 does not need service keys or wallet files in GitHub secrets. Run a local link command once:
run402 ci link github --project prj_... --manifest run402.deploy.json
# Optional route authority for CI route declarations:
run402 ci link github --project prj_... --manifest run402.deploy.json --route-scope /admin --route-scope /api/*That creates a deploy-scoped /ci/v1/* binding and writes a workflow that grants id-token: write, checks out the repo, and runs the existing deploy primitive:
permissions:
contents: read
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to run402
run: npx --yes run402@3.7.5 deploy --manifest 'run402.deploy.json' --project 'prj_...'CI deploys are intentionally narrow: site, functions, database, absent/current base, and route declarations only when the binding has covering --route-scope patterns. Without route scopes, CI cannot ship routes. Keep secrets, domains, subdomains, checks, non-current base, and broader trust changes in a local wallet-backed deploy. If the gateway returns CI_ROUTE_SCOPE_DENIED, re-link with exact scopes like /admin or final-wildcard scopes like /api/*, or deploy locally. Manage bindings with run402 ci list and run402 ci revoke.
In-function helpers: caller-context vs BYPASSRLS
Inside a deployed function, import from @run402/functions. Two distinct DB clients keep RLS clean:
import { db, adminDb, auth, email, ai } from "@run402/functions";
export default async (req: Request) => {
const user = await auth.requireUser();
// Caller-context: db() mints a 60s actor JWT so run402.current_user_id() resolves in RLS.
// No .eq("user_id", user.id) needed: RLS already binds the visitor's rows; the redundant
// filter is a deploy-fail (R402_AUTH_REDUNDANT_USER_FILTER) under @run402/functions v3.0+.
const mine = await db().from("items").select("*");
// BYPASSRLS: for platform-authored writes (audit logs, cron cleanup, webhook handlers).
await adminDb().from("audit").insert({ event: "items_read", user_id: user.id });
// Send mail from the configured default outbound mailbox.
if (mine.length === 0) {
await email.send({ to: user.email, subject: "Welcome", html: "<h1>hi</h1>" });
}
return Response.json(mine);
};adminDb().sql(query, params?) runs raw parameterized SQL and always bypasses RLS. The current runtime returns the gateway envelope, including rows and row_count; read result.rows, not result[0]. Older helper typings incorrectly described a bare array. See the owning runtime reference and match local helper types to the runtime version used by your deploy.
@run402/functions is auto-bundled into deployed code; install it in your editor for full TypeScript autocomplete (also works at build time for static-site generation with RUN402_SERVICE_KEY + RUN402_PROJECT_ID set).
ai.generateImage({ prompt, aspect? }) is available inside deployed functions for live app flows such as generated avatars or OG images. It calls the project runtime image endpoint with RUN402_SERVICE_KEY, so deployed functions do not need wallets or x402 signing code. Aspects are square, landscape, and portrait; the result is { image, content_type, aspect } with base64 image bytes. Runtime image generation is billed, rate-limited, and spend-capped against the project organization; public routed functions should authenticate/rate-limit their users before calling it.
assets.put(key, source, opts?) uploads bytes from inside a deployed function through the same CAS-backed apply substrate as deploy-time assets. It uses RUN402_SERVICE_KEY, accepts a string, Uint8Array, or { content | bytes }, and returns an SDK-compatible AssetRef with mutable and immutable URLs.
Operating data from outside a function: use the CLI with an explicit project. For deliberate HTTP integrations, the native HTTP reference distinguishes administrative REST from caller-scoped REST. Never expose a service key to the browser.
run402 projects sql prj_example "SELECT count(*) FROM audit"repos: your repository history, encrypted before it leaves the machine
run402 repos is a Git remote whose contents are encrypted on your own machine and stored as a chain of signed, admitted heads. It exists so your repository history outlives the machine it was written on — without that outliving requiring you to hand Run402 the plaintext. The wire protocol is r402s/v0. One noun, seventeen verbs: KyGit is the brand, a vault is the resource, a repo is what you have — run402 repos on the command line and r.repos in the SDK. Two pairs of the seventeen mint and claim a single-use bearer key: handoff/resume hand a checked-out working tree — dirty state included — from one agent to ANOTHER, the sender stopping; invite/join bring a SECOND agent into the SAME work while the first keeps going, sharing a coordination room. See "Handoff / resume" and "Invite / join" below.
Three claims, three different strengths. These are the entire approved claims vocabulary for this feature:
Run402 cannot decrypt your vault or repository history. Deployment artifacts remain a disclosed plaintext custody boundary. Cryptographic, against Run402 itself: in the vault lane, source payload and repository-history content are ciphertext-only; the substrate retains only enumerated plaintext metadata and holds zero vault keys. The deploy lane is separate and disclosed — the platform custodially holds the plaintext artifacts of every deploy. It can read what you deployed; it cannot read what you did not.
Activation requires vault admission by default; an explicit, audited override can bypass it. An operational platform invariant, enforced and auditable — not cryptographic against the platform that enforces it.
Retention is an operational promise of the platform, not a cryptographic guarantee against it (the host controls timestamps and bytes).
The vault-only track — three lines, muscle memory intact, nothing to pay:
run402 init # once per machine
run402 repos create my-notes # project + vault + origin remote, one free call
git push -u origin main # publishes, encrypted before it leaves the machineorigin is claimed additively: when the directory has no origin yet, the scaffold names ours origin — git push origin main just works, no side-remote name to remember. An existing origin is never touched; the fallback is run402 instead, and the response says which happened and why. An app that lives inside another repository (a monorepo workspace) is never scaffolded into that repository: the skip carries a create_nested_repo next action, and run402 repos create --nested --project <project_id> (or run402 up --nested) gives the app root its own nested repository and run402 remote, appending exactly one line to the enclosing repository's local .git/info/exclude and touching nothing else there; repos create prints a git push next action only for a remote it actually added. The free path is the whole path — no slug, no fee, no ceremony. When you want pretty run402::<org-slug>/<name> addresses (clone-by-name, push-to-create), claim an org slug once — the optional named-address upgrade described below.
Named addressing. run402::<org-slug>/<name> works alongside the id-form run402::<org_id>/<project_id> in the same slot — pick an org slug once (run402 orgs slug <slug>, owner-only, a small one-time fee), and every repo under it is run402::<slug>/<name>. Pushing a name that doesn't exist yet push-to-creates it: the project and vault are allocated atomically, and a losing concurrent pusher resolves cleanly to the winner's repo instead of erroring — its work is not lost, it just wasn't the creator. The first time a named remote resolves on a checkout, the resolved id is pinned into that checkout's local git config — every later push/fetch follows the pin directly, so a later rename of the org slug or repo name never breaks an existing clone. The id-form address needs no pin (a project id never changes) and stays the cold-restart path: an agent that lost its local state but still holds authority on the project can always fall back to run402::<org_id>/<project_id>.
One thing to know up front: a vault has a writer set, not a single key. Every admitted member or handoff recipient opens the vault and pushes under its OWN keystore key (run402 repos access lists them). A vault whose only admitted principal is this keystore is exactly as safe as this keystore — see "If you lose the keystore" below, or admit a second principal.
The explicit, ceremonial form still works, and allocates the SAME way git push does lazily on first use — useful for scripts, or for the receipt to land in JSON stdout instead of stderr:
# 1. Provision. Inside a repository that already exists, this adds the origin
# remote (run402::<org_id>/<project_id>). Not a repository yet?
# `run402 init --git-remote` creates one first. It needs a project selected
# (`run402 projects use <project_id>`, or RUN402_PROJECT_ID).
run402 init
# 2. Allocate the repo's vault explicitly. Separate from `run402 init` on
# purpose: this is the step that mints key material on this machine and
# prints a one-shot recovery receipt. Idempotent — an existing vault comes
# back deduplicated. (Skip this step and git push / repos capture
# against an unallocated project allocates the SAME way, lazily, on
# first use — the two paths don't stack; this one just does it now,
# explicitly, so the receipt lands in JSON stdout instead of stderr.)
run402 repos create --project <project_id>
# 3. Snapshot — capture the working tree, encrypt it, publish a signed head.
run402 repos capture --message "wip: refactor the parser"
git push origin main # ...or push your own branches, via git-remote-run402
# 4. View, then fsck: walk the head chain from your authenticated pin.
run402 repos view
run402 repos fsck --budget 500
# Restore anywhere, with plain git.
git clone run402::<org_id>/<project_id> restoredCloning needs a Run402 principal on this machine — a wallet and a keystore holding an envelope for this vault — this is encrypted git, not a shareable link.
A fresh clone installs local refs/r402/retain/<oid> refs for every retained deploy-capture tip no branch reaches, so a plain git fsck is silent — git for-each-ref refs/r402/ lists what is retained. Clones made by a client older than this one (or a checkout whose ref write degraded) may still show dangling commits under git fsck; harmless, not corruption — one run402 repos fsck run installs the missing refs. A retained ref locally pins that history against git gc until the vault prunes the capture, at which point the next fetch retracts it.
repos capture is the CAPTURE lane — the protocol deploy ref plus the HEAD target — because a dirty tree captures as a synthetic commit that sits on no branch. Your own branches and tags reach the vault through git push origin <branch>.
Allocating a vault does NOT gate the project's deploys. vault_policy stays unset until you set it — a vault created by a first git push or repos create never silently changes how you deploy. A deploy against a vaulted, ungated project proceeds ungated and its result carries a typed next_actions entry offering run402 repos policy required; every later ungated deploy carries a warnings[] entry naming the drift, until the policy is set either way — never a block, never an interactive prompt. Once vault_policy is required, a deploy must present a vaulted capture at commit — run402 deploy produces one automatically on any machine holding the keystore; un-gate with run402 repos policy grandfathered --reason "<why>" (owner + step-up, audited, reversible with run402 repos policy required). Vaulting your source is never gated on a deploy, either way. run402 doctor reports the policy, whether this machine can satisfy it, and where the keystore lives.
Before capture reports that anything landed, the client compares every finalization receipt against its local expected manifest and reads the admitted head back from storage — a 200 alone is never enough. Maintenance is one verb, run402 repos gc — git gc's own two halves (checkpoint publication + prune planning), never described as "exactly git gc" since the deletion ceremony is stricter: it plans locally, and submits only when handed both verifier receipts — one from this CLI, one from the independent r402s-verify — with --submit --intent-core <path> --verifier-receipt <path>; only the control-plane-signed completion says what was deleted.
From the SDK, with identical semantics — vault reads run anywhere, and the verbs that touch a git working tree or the on-disk keystore are Node-only:
For typed repository automation, see the native SDK KyGit reference.
The encrypted second remote — the zero-migration pattern. Keep GitHub/GitLab as the primary (collaboration, CI, reviews, unchanged) and add KyGit as the second remote: git remote add vault run402::<org_id>/<project_id> + git push vault --all, and a complete, continuously updated copy of your history exists that the storage provider itself cannot read. The reason this matters, said plainly and as capability rather than accusation: a host that can READ private repositories can — under a future policy, an acquisition, a training pipeline, a subpoena, or a breach — index them, train models on them, or hand them to someone who will. Run402 cannot decrypt your vault or repository history. Deployment artifacts remain a disclosed plaintext custody boundary.
A vault-only project is first-class. run402 init (or run402 repos create <name>), then git push origin …, then gc / fsck / access, and never a deploy — a supported shape, not a degraded one. One consequence is worth stating plainly: a vault-only project has no deploy lane, so the disclosed plaintext custody boundary is empty and there is consequently no custodial restore path.
If you lose the keystore. The vault protects source history from host-side loss while a principal keystore survives. The "while" clause is load-bearing: in V0-A, whole-machine or whole-keystore loss is terminal for vault history until human envelopes ship, and run402 repos view prints that sentence verbatim. Back up the keystore directory run402 repos view reports as keystore.root and prints under the terminal-loss statement — ~/.config/run402/vault for the default wallet, ~/.config/run402/profiles/<wallet>/vault for a named one. The recovery receipt is an integrity anchor, not a decryption key — it proves the vault you are served is the one you created, and it decrypts nothing. It is not a secret; the more copies the better. The reminder gets louder as the vault gets more valuable: quiet at genesis, a STANDING run402 doctor warning once the vault crosses any of ≥10 generations / ≥10 MB / ≥14 days since genesis — cleared only by adding a second principal, never by an attestation, because V0 cannot verify one is true.
The exit ramp: mirror your own copy. run402 repos mirror <destination> [--profile <name> | --ambient] (S3 or a plain directory) configures a second, customer-owned copy of the vault's ciphertext — the destination and credential name live in a config file beside the keystore, never in run402.config.json, never a raw secret. Once set, every capture is mirrored to it automatically, reported as a separate mirror_push field beside the vault result; a mirror failure never blocks, slows, or changes the actual publish. run402 repos mirror --backfill (idempotent, resumable) catches it up on demand; run402 repos fsck --mirror is a KEYLESS integrity probe — it reports the recoverable generation without touching key material. run402 repos recover <source> --out <dir> needs no server at all: it reads the mirror, verifies the chain, and decrypts with the local keystore alone. Named recover rather than restore, which already means something else in git. Two things to know before you rely on it: it proves validity, never freshness — an older mirror looks identical to a genuinely short history — and a mirror without the keystore or an equivalent key recovers nothing, since mirroring ciphertext does not create a second key; the V0 terminal-loss statement above applies.
The human backup path (vault-recovery-custody). A human org member who completed source enrollment at console.run402.com/account holds an equivalent key with no keystore at all: their member key lives as sealed wrappers (passkey PRF and/or a source recovery code), and run402 repos recovery-bundle downloads the versioned recovery bundle (key identity + wrapper ciphertexts — still nothing the platform can open). Kept with a vault mirror — copy it to member-recovery-bundles/<name>.json under the mirrored prefix — that bundle + the source recovery code + the vault's recovery receipt recover the repository with no run402 server and no keystore: run402 repos recover <source> --out <dir> --receipt <pin.json> (the code is prompted with hidden input; --bundle <file> if the bundle isn't in the mirror). A raw passkey PRF output is deliberately NOT a recovery input — the no-server path for a human is the recovery code. run402 doctor's recovery_posture check tells you whether each vault-owning org actually has this backstop configured.
run402 repos mirror s3://acme-vault-mirror --profile acme --region us-east-1
run402 repos mirror --backfill
run402 repos recover s3://acme-vault-mirror --out ./restored --repo src_1a2b3c
run402 repos recovery-bundle --out ./bundle.json # the member's no-keystore recovery half
run402 repos recover ./mirror-copy --out ./restored --receipt ./recovery-receipt.json --bundle ./bundle.jsonHandoff / resume — pass a working tree to another agent, dirty state and all. run402 repos handoff captures the actual working tree — staged, unstaged, and untracked changes, exactly as git stash push -u would — and mints a single-use bearer key, kgh1_…, printed to stdout exactly once (--json still keeps it off stderr; there is no second place to find it if you lose it). Hand that key to another agent — another machine, another session, no shared keystore, no shared wallet — and run402 repos resume kgh1_… claims it, clones a fresh checkout, and reapplies the exact dirty state with git stash apply --index. The resuming agent also becomes a run402 wallet of its own on the way in: with no active tier, resume folds the same cold-start chain create does (wallet → faucet → one x402 prototype payment) before the claim; --no-init opts out, and the claim never waits on it. A Handoff Note rides alongside (a short JSON summary: what's done, what's in progress, what's failing, next steps) and renders as Markdown by default on resume. The key confers real authority — by default the sender's own org role — until it is claimed or its TTL (default 1h, --ttl <seconds>) expires; the mint response says so, and the CLI echoes the warning before printing the key. Sensitive untracked files (.env, *.pem, *.key, SSH/AWS/GPG directories, and 18 more patterns) are excluded from capture by default; opt one back in with --include-sensitive <glob>.
run402 repos handoff --note-file handoff.json # captures the working tree, mints the key, prints it ALONE to stdout
run402 repos resume kgh1_… # on the other machine: redeem it, clone, restore, print the noteNeither verb has an MCP tool — handoff mints a bearer secret and resume mutates org membership, the same "mutating verbs are CLI-only" reasoning as create/delete above.
Writers, plural. A vault admits heads from a SET of writer keys, each a member's own keystore identity (protocol rev 47). resume makes the recipient a writer before it returns — git push works at once, under the recipient's own key, and the sender's environment can be deleted afterwards. Any member added with run402 orgs members add (developer or above) becomes a writer the same way: the adder's client admits the new key inline when it can, and REFUSES the add (VAULT_WRITER_NOT_ADMITTED, request_writer_sync) when it cannot, so no member is ever left able to read but not push. run402 repos view lists writers[] and pending_writers[]; run402 repos access sync admits pending keys on demand; removing a member rides the next epoch rotation and that key can never be re-added. Nobody's seed is ever copied: a writer is admitted by a live writer's signature or by a sender-signed handoff grant the recipient completes with its own key.
Invite / join — bring a second agent into the exact work, dirty tree included, and talk in a shared room. A Handoff passes the work on; an Invite grows the team. run402 repos invite captures the working tree exactly like handoff does — the inviter's own worktree, index, branch, refs, and access are all untouched, and it keeps pushing throughout — registers the inviter's own presence in a coordination room (the project's default room, or --room <key> for a named org room), mints a single-use bearer key, kgi1_…, printed to stdout exactly once, and posts ONE room message naming the checkpoint and the invite id (never the key). Minting requires an ACTIVE writer key, the same as handoff (INVITE_MINT_REQUIRES_WRITER names run402 repos access sync as the fix). Hand that key to another agent and run402 repos join kgi1_… pays its own way in — the joining agent folds the SAME cold-start chain resume does (wallet → faucet → one x402 prototype payment) before the redemption, so it arrives as a paid-up run402 wallet of its own — clones a fresh checkout, becomes a writer of the vault under its OWN key before the command returns (nothing is copied from the inviter), restores the exact dirty state, pins the invite's room locally, registers its own presence, posts ONE arrival message, and reports who invited it (name, labels, whether they're still live), who else is in the room, and the last few messages. Both agents push, interleaved, each signing under its own key. From there run402 messages wait is the agent's ear: it blocks until the other side speaks (or a bounded timeout elapses) using the gateway's held read, never errors on silence, and reports who is still live either way. The minted role defaults to developer and never exceeds the inviter's own; the Invite Note (same shape as the Handoff Note) rides alongside and renders as Markdown by default on join. Taking access back is run402 orgs members rm, which rotates the vault's epoch so the removed key can no longer push while every remaining agent keeps working.
run402 repos invite --note-file invite.json # captures the working tree, mints the key, prints it ALONE to stdout
run402 repos join kgi1_… # on the other machine: pay in, redeem, become a writer, clone, restore
run402 messages wait # then: block until the other agent speaks (or the timeout elapses)Like handoff/resume, neither invite nor join has an MCP tool — invite mints a bearer secret and join mutates org membership and writes a working tree, the same reasoning as create/delete/handoff/resume above.
Verify it without trusting our client. r402s-verify is an independent-lineage verifier for the same protocol — a separate language, separate authorship, and a separate primitive stack, deliberately sharing no implementation code with the SDK. That non-sharing is the point: a differential verifier that reuses the code it is checking verifies nothing. It lives on the r402s-verify branch of this repository with its own workflow, ships prebuilt release binaries, and also builds with cargo build --release. The full protocol specification and threat model it verifies against are published in docs/kygit/, and the frozen conformance vectors in test-vectors/r402s-v0/.
Cost. There is no separate repos price — a vault's bytes count against the organization-pooled vault quota (sourceBytes: prototype 1 GB, hobby 10 GB, team 50 GB), a separate pool from the storage your projects share, charged once per unique object with a 4 KiB per-object accounting floor and a 1 MiB per-vault minimum.
SDK: @run402/sdk
npm install @run402/sdkTwo entry points:
@run402/sdk: isomorphic. Bring your ownCredentialsProvider(a session-token shim, a remote vault, anything that resolves project keys + auth headers). Works in Node 22, Deno, Bun, V8 isolates.@run402/sdk/node: Node-only convenience. Reads local profile state plus the project-key credential cache (credentials/project-keys.v1.json) and signs x402 payments from one deterministic source: an explicit opaquepaymentSigner, explicitwalletPath, the supplied provider'sreadWallet(), or the default active-profile wallet. Auth and payer may intentionally differ; a selected payment source never falls back to an ambient wallet.r.paymentPayer()reports only safe public payer/source provenance. Also exposessites.deployDir(...),fileSetFromDir(...), typed deploy-manifest helpers (loadDeployManifest,normalizeDeployManifest), andresolveRun402TargetProfile()for app build scripts that need the same Core/Cloud target the CLI uses.
import { run402 } from "@run402/sdk/node";
const r = run402();
// Prepare the complete first-deploy manifest and referenced app files.
const result = await r.up({ name: "my-app", manifest: "run402.json" }, { approval: "yes" });
console.log(result);The SDK is organised into focused namespaces: actions (Node recursive action runner), pay (bounded arbitrary-URL x402 buyer), projects, snapshots, branches, archives, assets, cache, ci, sites, functions, jobs, secrets, subdomains, domains, email (+ webhooks), auth, apps, tier, billing, contracts, ai, wallets (the local wallet: status, create, export, faucet; plus the server label), service, admin, session (a person's sign-in session: run402 login loopback and --device seams plus the browser surface), writeApproval (the passkey write approval behind run402 approve), me (account overview and status), wallets (signed server-side wallet label), orgs (org-owned control plane + r.org(id) sub-client), grants (per-project capability grants), and identityLinks (public, protocol-discriminated human/agent Nostr attribution), plus const project = await r.project(id); await project.apply(spec) for staged multi-resource writes (release slices + assets slice via /apply/v1/*). Every operation throws a typed Run402Error subclass on failure: PaymentRequired, PaymentBuyerError, ProjectNotFound, Unauthorized, ApiError, NetworkError, LocalError, Run402DeployError. apply() automatically re-plans safe current-base BASE_RELEASE_CONFLICT races and emits apply.retry progress events. See sdk/README.md.
Buzz/Nostr identity links
Humans and agents can publicly attribute separately held Buzz/Nostr identities to their Run402 principal. Agent links use the EOA-plus-kind-1 protocol; human links use a normal browser, fresh passkey, and released Buzz consent ceremony at https://console.run402.com/identity-links/connect. Both produce the same public idlnk_… resource shape with a discriminating proof_protocol. One principal may have several active Nostr subjects, while one active Nostr subject belongs to only one principal. This is attribution only: Nostr identities never authenticate, authorize, pay, deploy, or receive transfers. Run402 never accepts or derives from an nsec, Nostr private key, mnemonic, seed, passkey, session credential, or derivation path.
The human-facing install is a Buzz message—no terminal required:
Please install the run402.com skill.That is the entire human instruction. In a managed Buzz context, first-party discovery routes it to run402-buzz; the agent reads the apex install router and installs the self-contained skill into its workspace (normally the user-home .buzz directory). The request means install and connect: after verifying the inert files, the agent loads the installed skill directly and continues through preflight, setup, and identity linking in the same turn. It does not stop at “available next turn” or ask a second setup question. For a Codex runtime, prefer supplying the working directory and environment separately to the agent's command runner:
working_directory: <user-home>/.buzz
environment: { "DO_NOT_TRACK": "1" }
command: npx --yes skills@latest add https://run402.com -s run402-buzz -a codex -yShell-only POSIX environments use:
cd "$HOME/.buzz"
DO_NOT_TRACK=1 npx --yes skills@latest add https://run402.com -s run402-buzz -a codex -yWindows PowerShell uses:
Set-Location (Join-Path $HOME '.buzz')
$env:DO_NOT_TRACK = '1'
npx --yes skills@latest add https://run402.com -s run402-buzz -a codex -yClaude Code uses -a claude-code, Goose uses -a goose, a confirmed .agents/skills consumer may use -a universal, and Claude Code plus Codex uses -a claude-code codex. universal is the shared path, not all runtimes; do not use the invalid explicit target -a claude. The skill bytes come from immutable digest-verified artifacts at run402.com; first-run npx can still require npm. GitHub is the one availability-only fallback, while any integrity failure stops before setup. Success reports the observed first-party digest and exact managed-workspace path; a GitHub source or global runtime path is never mislabeled first-party.
The file installation stage is inert. Continuing onboarding publishes a durable public kind-1 Nostr event and durable Run402 proof connecting the two public identities; revocation does not erase their history, and a Buzz-managed event may also expose its owner's public NIP-OA attestation. The agent initializes only if needed, creates or reuses the link, independently verifies it, and immediately offers one context-relevant quick test or demo with Deployment: none retained in the expanded receipt. On Windows the setup helper runs npm's and Run402's JavaScript entrypoints through the exact managed Node runtime with shell: false, avoiding .cmd process-boundary failures. It waits for explicit approval before building or deploying. After independently verifying the live app, it creates an inert durable offer and posts a normal HTTPS “Become an owner” handoff. The browser owns human login/passkey and the existing Buzz six-digit consent callback; no human terminal command or Buzz change is required.
See the buzz/ guide for prerequisites, the no-secret signer model, released-client fixtures, migration guidance, and the full workflow, or inspect the exact run402-buzz listing on skills.sh. The low-level CLI commands remain available for debugging, but they are not a competing onboarding path.
The community control plane keeps four concepts separate: installing the skill is inert shared capability; installing a community associates a Buzz relay community with a Run402 organization after dual consent; human adoption records a terminal consent receipt, creates the human's public Buzz identity link, and adds an ordinary owner membership without demoting the founder agent; agent enrollment gives each later agent principal only bounded, expiring grants to named existing projects. The completed receipt, public attribution, and membership remain independent: revoking the link does not remove org authority, and removing the membership does not revoke the link or rewrite the receipt. Buzz itself remains unchanged: approval uses already-shipped browser-fragment/kind-1 behavior plus released NIP-11/NIP-43 evidence, while Run402 owns offers, organizations, descriptor discovery, and lifecycle. run402 buzz status capability-detects older gateways; MCP only renders exact HTTPS/CLI next steps. See the Fizz/Honey workflow.
Astro SSR + ISR cache. For Astro apps, use @run402/astro 1.0+: export default run402(); in astro.config.mjs returns an AstroUserConfig composing the SSR adapter (Lambda + SnapStart + ISR cache + AsyncLocalStorage request-context), image integration, and build-time detectors. Functions opt into the SSR class via FunctionSpec.class: "ssr" in ReleaseSpec; the gateway provisions SnapStart and caches HTML responses keyed by (host, path, search, method, locale, release_id). Cache is bypass-by-default (no-store unless Cache-Control explicitly allows it AND no Set-Cookie AND no auth-taint flag from auth.* helpers / payment primitives). Invalidate from in-function code or out-of-band: r.cache.invalidate(url) / r.cache.invalidatePrefix({ host, prefix }) / r.cache.invalidateAll({ host }) (SDK), run402 cache invalidate <url> (CLI). Inspect cached state with r.cache.inspect(url) / run402 cache inspect <url>. Agent DX helpers also in the CLI: run402 doctor (5 health checks), run402 dev (Astro dev with .env.local), run402 logs --request-id req_... (correlate across functions). Full reference at astro/README.md and cli/llms-cli.txt (R402_* SSR Runtime Error Codes section).
CLI: run402
npm install -g run402@latestEvery subcommand prints JSON to stdout, JSON errors to stderr, exits 0 on success and 1 on failure: designed for an agent shell, not a human. Full reference: cli/llms-cli.txt (also at https://docs.run402.com/llms-cli.txt) — an index carrying the whole first-deploy contract plus a table of fetchable topic slices (/llms-cli-deploy.txt, /llms-cli-commands.txt, /llms-cli-functions.txt, …); /llms-cli-full.txt is the whole thing in one document.
run402 up --name my-app -y # recursive SDK action runner: init/tier/project/link/deploy
run402 up verify # rerun app HTTP verification without a deploy
run402 up --nested -y # app root inside another repo: its own nested repo + encrypted remote
run402 doctor # { ok, blocking[], warnings[], checks[] }: ok means this agent can ship
run402 logs --request-id req_abc123 # every function in the project; app output only (--all for the raw stream)
run402 init # one-shot wallet + faucet + tier check
run402 pay https://seller.example/resource --max-usd 0.05 --require-receipt
run402 status # organization snapshot (wallet, rail, balances, tier, projects)
run402 projects provision --name my-app
run402 projects sql <project_id> "CREATE TABLE …"
run402 projects validate-expose <project_id> --file manifest.json
run402 projects apply-expose <project_id> --file manifest.json
run402 sites deploy-dir ./dist
run402 deploy verify op_... --project <project_id> --wait # confirm gateway/edge release coherence
run402 deploy releases active --project <project_id> # inspect current-live release inventory
run402 deploy resolve https://example.com/events --project <project_id> --method GET
run402 deploy --manifest app.json --json # deploy only; rehearses automatically when a live release has migrations to protect
run402 snapshots list prj_...
run402 branches create prj_... --ttl-days 7 --json
run402 functions deploy <project_id> <name> --file fn.ts
run402 functions runs create <project_id> <name> --event-type reminder.send --idempotency-key reminder:123 --delay 10m
run402 ci link github --project <project_id> # GitHub Actions OIDC deploy binding (--route-scope for CI routes)
run402 assets put ./asset.png --immutable
run402 assets diagnose <url> # inspect live CDN state for a public URL
run402 cdn wait-fresh <url> --sha <hex> # poll until a mutable URL serves the new SHAup is the only compound CLI command: it calls the SDK action runner, emits steps[], and writes .run402/project.json when it needs to remember the workspace project. Against run402 Core it skips Cloud wallet/tier prerequisites and fails closed if no Core project is selected.
Rehearsal is automatic: a migration-bearing run402 up / run402 deploy against a project with a live release is rehearsed on a contained branch and committed only on a passing report (result.deploy.rehearsal); a first deploy has nothing to protect and commits directly (reason: "no_live_release"), and a redeploy whose migrations are all already applied with identical checksums is skipped as migrations_unchanged, so a page-only redeploy that still carries its migrations ships in seconds. --no-rehearse skips it. ADVANCED: run402 deploy rehearse [<plan_id>] [--manifest <path>] rehearses without committing — from a persisted plan, or from the manifest in the current directory (plan, upload, rehearse). Manual restore points live under run402 snapshots create|list|get|restore|delete; restore is a two-step plan/confirm flow. Branch projects live under run402 branches create|list|renew|delete, default to a 7-day TTL, use sandboxed email by default, and are marked noindex; a parent with no live release yields an empty branch.
Your HTML never needs a pasted key: every Run402 host serves /_run402/config.js (window.RUN402 = { project_id, api_base, anon_key }) for the project it resolves to. run402 up also names this principal when it has none — RUN402_AGENT_NAME if your runtime declares one (it overrides an existing name), else a detected client (claude-code, codex, cursor, grok; RUN402_CLIENT=<name> declares a client with no marker of its own, checked first); when nothing is known nothing is written — so promotion credit names you; set it any time with run402 whoami --set-name <name>. result.identity always reports detected (the client seen this run) and detection: { applied, reason }, where name_already_set means a client was detected but the principal already had a name. projects provision never touches git; up scaffolds a run402 remote on the app root only, and an app root inside another repository is skipped with a create_nested_repo next action unless you pass --nested, which makes it its own nested repository (one line appended to the enclosing repository's local .git/info/exclude, nothing else touched).
Portable archives export the supported run402 Core runtime slice of a Cloud project for local Core import. This is the no-lock-in trust path, separate from allowance/spend-cap financial-risk controls.
run402 archives create <project_id> --target cloud --scope portable-runtime-v1 --auth stubs --consistency pause-writes --wait --output ./project.r402ar --json
run402 archives verify ./project.r402ar --json
run402 archives import ./project.r402ar --target core --name imported-project --env-file ./required.env --json--target names the deployment each verb talks to: create, status, and download export from Run402 Cloud (--target cloud, the default); import loads into a local Run402 Core (--target core, the default). Archive v1 excludes secret values, auth credentials, logs, billing/allowance state, Cloud operations metadata, Cloud import, and existing-project merge import. Verify is local/offline and checks integrity plus compatibility; archives remain untrusted input until Core import verifies and stages them.
The active project is sticky: run402 projects use <project_id> server-validates <project_id> and stores it as the default for subsequent <project_id>-taking subcommands, so most commands work without it. Local key material is managed separately under run402 credentials project-keys ...; that cache is never project inventory.
MCP server: run402-mcp
npx -y run402-mcp # standalone testEight tools, a few kilobytes of schema in a host's context: up and deploy for the first deploy, status, whoami, doctor, docs, run, and expand_result. Everything else is a run snippet against r, the Node SDK client, executed in a QuickJS-in-WebAssembly sandbox with no filesystem, process, or network of its own. Needs Node.js 22.13 or later. Local, so it can actually pay: an x402 payment needs a signing key, so a wallet-less remote server cannot make one.
Remote endpoint (no install)
A hosted streamable-HTTP MCP server runs at https://mcp.run402.com/mcp with free discovery tools only: run402_quickstart, x402_price_check (decode any URL's x402 challenge, unpaid), and experiment_scoreboard. It never handles funds — paid capabilities (image generation, deploys, payments) require the local server below, which holds your wallet. Registry entry com.run402/mcp lists both (packages[] npm + remotes[]). The remote itself runs as a run402 function — the platform hosting its own MCP server.
Stdio MCP transports must keep stdout reserved for JSON-RPC. Use the package bin (npx -y run402-mcp) or node dist/index.js from a built checkout. If a host insists on npm start, set npm_config_loglevel=silent; npm's lifecycle banner is stdout and otherwise appears as non-JSON prelude. The repo .npmrc and Docker image set this for source/container hosts.
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"run402": { "command": "npx", "args": ["-y", "run402-mcp"] }
}
}Cursor
Add to .cursor/mcp.json:
{
"mcpServers": {
"run402": { "command": "npx", "args": ["-y", "run402-mcp"] }
}
}Cline
Add to your Cline MCP settings:
{
"mcpServers": {
"run402": { "command": "npx", "args": ["-y", "run402-mcp"] }
}
}Claude Code
claude mcp add run402 -- npx -y run402-mcpOpenClaw skill
cp -r openclaw ~/.openclaw/skills/run402
cd ~/.openclaw/skills/run402/scripts && npm installEach script re-exports from cli/lib/*.mjs: the OpenClaw command surface is identical to the CLI command surface by construction. See openclaw/README.md.
MCP tools
Tool | What it does |
| The first deploy: any missing setup (wallet, tier, project, workspace link), then the deploy. Returns the |
| Applies a ReleaseSpec to a project ( |
|
|
|
|
|
|
| The SDK reference and the |
| Runs a TypeScript snippet against the SDK in a sandbox; returns the value, the captured logs, and the SDK calls it made. |
| Pages a stored result: a |
A snippet is the body of an async function; the value of its last expression is the result:
{ "code": "const { projects } = await r.projects.list();\nprojects.filter((p) => !p.site_url).map((p) => p.id)" }The result is { status, value, value_ref, shown, total, logs, logs_ref, calls, duration_ms, wallet, error? }: a large value is stored whole by item (an array's elements, a result's rows) and its leading whole items arrive in value_window, including in structuredContent (expand_result pages the rest by item), calls[] lists every SDK call with its outcome, and a timeout (60 s by default, 300 s at most) still lists the calls that completed. An SDK error passes through with its own code and next_actions.
Structured results. Every tool also returns its result as structuredContent under a declared outputSchema, so a host reads fields instead of parsing text. The object has status: "ok" | "error"; the fixed tools put the SDK object under result, and every error carries error.code, error.message, and error.next_actions. The fenced JSON in the text is the same object.
One-time secrets stay in the CLI. An operation that returns or consumes a one-time secret (minting or rotating a grant key, a Handoff or Invite Key, a Room Invite Key, provisioning a project or rotating its credentials, a project token, creating, importing, or exporting a wallet, the Lightning pairing) refuses inside run with SECRET_REQUIRES_CLI and one next action, { "type": "run_cli_command", "command": "run402 …" }, naming the exact command to hand the person. The refusal is in the SDK method itself, before any request, so nothing secret reaches a result.
Full reference: llms-mcp.txt.
Configuration
Variable | Default | Purpose |
|
| API base URL (override for staging) |
|
| Local credential storage base directory (named wallets live under |
|
| Active named wallet (profile). Overridden by |
|
| Custom wallet file path |
| (unset) | A grant-key bearer from |
Local state lives at:
profile
state.json: active project pointer and profile stateprofile
credentials/project-keys.v1.json(0600): local anon/service key cache for explicit credential-required operations~/.config/run402/wallet.json(0600): wallet for x402 / MPP signing
Legacy projects.json files are one-way migration input only. anon_key and service_key have no expiry; lease enforcement happens server-side. Inspect cache state with run402 credentials project-keys status --project <project_id> and export secrets only with run402 credentials project-keys export --project <project_id> --reveal.
Development
npm run build # builds core/, sdk/, then the MCP server
npm test # SKILL + sync + unit tests
npm run test:e2e # builds generated CLI SDK mirrors, then runs CLI end-to-end tests
npm run test:sync # checks MCP/CLI/OpenClaw/SDK stay in sync
npm run test:skill # validates SKILL.md frontmatter + bodyArchitecture: every tool / subcommand / skill script is a thin shim over an @run402/sdk call. core/ holds Node-only filesystem primitives (keystore, wallet, SIWE signing) wrapped by the SDK's Node provider. See CLAUDE.md for the full layout.
Links
Web: https://run402.com
Self-host backend (run402 Core): https://github.com/kychee-com/run402-core
API docs (HTTP): https://run402.com/llms.txt · https://run402.com/openapi.json
CLI docs: https://docs.run402.com/llms-cli.txt (index + fetchable slices; https://docs.run402.com/llms-cli-full.txt for the whole reference)
Status: https://api.run402.com/status
Health: https://api.run402.com/health
License
MIT for this repo (the agent surfaces: SDK, CLI, MCP server, Astro integration, OpenClaw skill). The full backend, run402-core, is Apache-2.0.
Available Tools
8 toolsdeployA
Unified apply primitive. Accepts a structured ReleaseSpec — database (migrations + expose), value-free secrets.require/delete declarations, functions, site, site.public_paths, site.embedding (framing opt-in by catalog key, e.g. { frame_ancestors: ['localhost'] }; null = deny), subdomains, and routes.replace web routes — with explicit replace vs patch semantics per resource. Migration entries use id for immutable versioned SQL or name for generated/idempotent content-tracked SQL; name compiles client-side to _<sha256(sql)[0:16]>. Use site.public_paths for clean static URLs such as /events backed by release asset events.html; explicit mode does not expose /events.html unless separately declared, while mode: 'implicit' restores filename-derived reachability and can widen access. Route entries map exact/final-wildcard browser paths like /admin and /admin/* to Node 22 Fetch Request -> Response functions, or exact GET/HEAD method-aware static aliases such as /events to { type: 'static', file: 'events.html' }; intentional read-only GET/HEAD wildcard function routes may set acknowledge_readonly: true. Direct /functions/v1/:name remains API-key protected. Secret values are set first with r.secrets.set (a run snippet) or run402 secrets set, never placed in deploy specs. All bytes ride through CAS (no inline-body cap). Returns release_id, URLs, warnings, and a structured progress-event log. Stops before upload/commit on confirmation-required warnings unless reviewed codes are passed with allow_warning_codes or allow_warnings is true.
| Name | Required | Description | Default |
|---|---|---|---|
| base | No | Diff base. Default `{ release: 'current' }`. Use `{ release: 'empty' }` for a fresh deploy that fails if a release already exists. | |
| i18n | No | Routed-locale-context release slice. Omit to carry forward from base release; pass null to clear the slice; pass { defaultLocale, locales, detect? } to replace. Drives the negotiated locale that the gateway surfaces to routed HTTP function invocations via x-run402-locale and x-run402-default-locale request headers (omitted entirely when the active release has no i18n slice). Static-route hits do NOT receive locale negotiation. | |
| site | No | ||
| assets | No | v1.48 unified-apply assets slice. Asset writes promote inside the same activation transaction as functions/site/secrets so a release flips atomically. | |
| routes | No | Apply-v1 web routes. Omit or pass null to carry forward base routes; pass { replace: [] } to clear routes; pass { replace: [{ pattern, methods?, target: { type: 'function', name } }] } for functions or exact GET/HEAD { target: { type: 'static', file } } entries for method-aware static route aliases. Prefer site.public_paths for ordinary clean static URLs. | |
| secrets | No | ||
| database | No | ||
| functions | No | ||
| project_id | Yes | Project ID to deploy to (from provision). | |
| subdomains | No | At most one subdomain per project — multi-element `set` is rejected with SUBDOMAIN_MULTI_NOT_SUPPORTED. | |
| allow_warnings | No | Continue past plan warnings that require confirmation. Default false: the tool stops before upload/commit so an agent can set missing secrets or inspect warnings. | |
| idempotency_key | No | Optional client idempotency key. Combined with the project id and gateway-computed manifest digest to deduplicate retries. | |
| allow_warning_codes | No | Continue past specific reviewed plan warning codes. Prefer this to allow_warnings when only one known warning class is intentional. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| events | No | |
| result | No | |
| status | Yes | |
| warnings | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure, and it does so thoroughly: it explains CAS transport, id vs name migration semantics, public_paths explicit vs implicit reachability, acknowledge_readonly, the warning-stop behavior, and the returned fields. This is unusually transparent for a deploy tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long and dense, but nearly every sentence carries substantive information, and the purpose is front-loaded. It could benefit from bullet structure or shorter sentences, but the length is largely justified by the tool's complexity and the absence of annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the output schema, and the lack of annotations, the description is quite complete: it covers CAS, warning gates, route semantics, migration semantics, and return contents. Minor gaps remain—such as i18n, base diffing, assets sync, and subdomain constraints—but those are already documented in the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 69%, and the description adds real meaning beyond the schema for several key parameters: migration id/name compilation, public_paths mode implications, route target types, secret handling, and warning acknowledgements. It does not cover every one of the 13 parameters, but the schema already documents many of those.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Unified apply primitive' and clearly states what it does: accepts a structured ReleaseSpec covering database, secrets, functions, site, subdomains, and routes, with replace vs patch semantics. It is specific about the resource and action, but it does not explicitly distinguish itself from sibling tools such as 'up'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives strong operational context—how migrations, public paths, routes, secrets, and warnings behave—and implies this is the unified tool for applying a ReleaseSpec. However, it never explicitly states when to use this tool versus alternatives like 'up', and it lacks when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
docsA
The SDK reference for run snippets, from the copy shipped in this package, so it matches the SDK the snippet runs against. No arguments: the run primer, the r namespace table, and the topics. topic: one namespace or section (assets, project.apply, rooms, local-state) or sdk for all of it; search: sections containing every word. Long answers are a window plus a ref for expand_result. Any other operation is a run snippet against r, the Node SDK client; docs is its reference.
| Name | Required | Description | Default |
|---|---|---|---|
| topic | No | `index` (default: the run primer, the r namespace table, the topics), `sdk` (the whole SDK reference), or one section: a namespace such as `projects`, `assets`, `project.apply`, `rooms`, or a section slug from the index. | |
| search | No | Words to look for; returns up to 8 SDK reference sections whose heading or body contain all of them. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ref | No | |
| kind | No | |
| error | No | |
| lines | No | |
| shown | No | |
| total | No | |
| status | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It discloses the default output (run primer, namespace table, topics), how topic and search alter results, and that long answers come as 'a window plus a ref for expand_result.' It does not explicitly state that the tool has no side effects, but 'SDK reference' and the contrast with run make the read-only nature reasonably clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but efficient, with no filler and the core purpose front-loaded. It is slightly run-on with semicolons, but each clause carries meaningful information about modes, scope, or relationships to sibling tools.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only reference tool with two optional parameters and an output schema, this description covers the default behavior, all parameter modes, the SDK-version guarantee, and the relationship to run and expand_result. Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds value beyond the schema by giving concrete topic examples (assets, project.apply, rooms, local-state), clarifying search as 'sections containing every word,' and explaining the expand_result link for long answers. This is more than the schema alone provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence identifies docs as 'the SDK reference for run snippets,' and the final sentence explicitly contrasts it with run ('Any other operation is a run snippet... docs is its reference'). This gives a clear verb-adjacent purpose (reference/lookup) and distinguishes it from execution tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly divides labor: docs is for looking up SDK reference, run is for executing operations against r, and expand_result is the companion for long answers. It also spells out the invocation modes (no args, topic, search), so an agent knows exactly when and how to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
doctorB
Local health and configuration diagnostics (r.doctor()): { ok, blocking[], warnings[], checks[] }, the same report as run402 doctor. ok is false only on a blocking finding. Any other operation is a run snippet against r, the Node SDK client; docs is its reference.
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | No | Target this project's vault check. Omitted: the repository's own remote, else the active project. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| result | No | |
| status | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must disclose behavioral traits. It explicitly defines the return object and the meaning of 'ok', which is useful. However, it does not state whether the tool is read-only, has side effects, or requires specific permissions, leaving those gaps unfilled.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is reasonably compact but includes the extraneous sentence about other operations being run snippets, which is not specific to this tool and could confuse the agent. It is not front-loaded with the key purpose; the first sentence does state it, but the trailing context dilutes focus.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple diagnostic tool with a single optional parameter and an output schema, the description plus schema cover the essentials: purpose, output structure, and parameter semantics. It lacks any mention of error cases or environment assumptions, but these are not critical for basic invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter 'project_id' is thoroughly described in the schema. The main description adds no extra parameter context, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as local health and configuration diagnostics and states the report format. It differentiates from 'run' and 'docs' via the SDK context, but does not explicitly contrast with the sibling 'status', leaving ambiguity about when to choose one over the other.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a general context ('local health diagnostics') but provides no explicit when-to-use vs alternatives, no exclusions, and no prerequisites. The reference to other operations as 'run' hints at an SDK pattern but does not guide selection between this tool and siblings like 'status' or 'deploy'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
expand_resultA
Fetch more of a result a previous tool showed you only a window of. Tools on this surface truncate the VIEW, never the DATA: when one prints a ref together with shown and total, the full result is held behind that ref and this is how you read the rest of it. Pass the ref plus offset and limit to page through it. Refs live in this server process only — they expire after 30 minutes and only the most recent handful are kept, so re-run the producing tool rather than storing a ref across sessions. A result that carried a secret is never retained and never has a ref, so nothing here can hand one back.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | Yes | The opaque handle a tool printed alongside its bounded view (res_ followed by 16 hex). Refs are per-process and short-lived — do not store one across sessions. | |
| limit | No | How many items to return, 100 by default and at most 1000. The window stays bounded even when expanded — page with offset rather than asking for everything at once. | |
| offset | No | Index of the first item to return. Defaults to 0. Page by adding the previous window's shown count. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ref | No | |
| kind | No | |
| error | No | |
| items | No | |
| shown | No | |
| total | No | |
| offset | No | |
| status | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the full disclosure burden. It explains that refs are process-local, expire after 30 minutes, only the most recent few are kept, and secret-carrying results are never retained or given refs. This is substantial behavioral context beyond a generic 'fetch' statement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded in the first sentence, and each subsequent sentence earns its place by explaining ref lifecycle, paging behavior, or security guarantees. There is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a fully documented schema and an output schema, the description supplies the missing operational context: where refs come from, how long they live, how to page through results, and which results cannot be accessed this way. An agent has everything needed to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents all three parameters at 100% coverage, including ref format, expiry, limit bounds, and offset paging. The description reinforces the interaction ('Pass the ref plus offset and limit to page through it') but adds little meaning beyond what the structured schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: 'Fetch more of a result a previous tool showed you only a window of.' This clearly identifies the tool as the pagination entry point and differentiates it from the unrelated sibling tools like up, deploy, and status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit triggering condition: when a tool prints a ref together with shown and total counts, this is how to read the rest. It also provides a when-not: do not store refs across sessions; re-run the producing tool instead. It even excludes secret-bearing results from having refs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
runA
Run a TypeScript snippet against the SDK in a sandbox. r is the Node SDK client (@run402/sdk/node); call docs for its reference. The code is the body of an async function: await r chains, and the value of the last expression (or a return) is the result, e.g. (await r.projects.list()).projects.map((p) => p.id). No filesystem, process, fetch, timers, or imports; console is captured. Returns { status, value, value_ref, shown, total, logs, logs_ref, calls, duration_ms, wallet, error? }; a large value is stored whole and expand_result pages it. Operations that return or consume a one-time secret (grant keys, Handoff and Invite Keys, project credentials, wallet keys) refuse with SECRET_REQUIRES_CLI naming the exact CLI command to hand the person. Any other operation is a run snippet against r.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | TypeScript or JavaScript, run as the body of an async function: top-level await works, and the value of an explicit return or of the last expression statement is the result. `r` is the Node SDK client (`@run402/sdk/node`): await any chain, e.g. `(await r.projects.list()).map(p => p.project_id)` or `await r.project("prj_…").functions.list()`. Types are stripped, not compiled: no enum, no parameter properties. No filesystem, process, fetch, timers, or imports; `console` is captured. | |
| timeout_seconds | No | Deadline for the whole run, 60 s by default and at most 300. An SDK call in flight at the deadline completes on its own; the result lists every call that completed. |
Output Schema
| Name | Required | Description |
|---|---|---|
| logs | No | |
| calls | No | |
| error | No | |
| shown | No | |
| total | No | |
| value | No | |
| status | Yes | |
| wallet | No | |
| logs_ref | No | |
| value_ref | No | |
| value_kind | No | |
| duration_ms | No | |
| logs_dropped | No | |
| value_window | No | |
| calls_dropped | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden. It details sandbox restrictions (no filesystem, process, fetch, timers, imports), async function semantics, return shape, secret refusal, and large-value paging behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with its purpose, then systematically covers code semantics, restrictions, return shape, and special secret handling. Every sentence adds information; there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the description covers sandbox behavior, result format, error condition for secrets, and paging. With an output schema present, return values are sufficiently explained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds an example but mostly restates what the schema already documents for `code`; `timeout_seconds` is fully documented in the schema as well.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific action: 'Run a TypeScript snippet against the SDK in a sandbox.' It also distinguishes itself from siblings by referencing `docs` for SDK reference and `expand_result` for paging large values.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use the tool: 'Any other operation is a run snippet against r,' and gives an exclusion for one-time secret operations that require the CLI (SECRET_REQUIRES_CLI). Also directs users to `docs` for reference, providing clear alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
statusA
The organization's state as this server's wallet sees it (r.status()): the wallet's local_label, server_label, and address, the tier and its lease, the allowance, the projects, and the active project. Never key material. Any other operation is a run snippet against r, the Node SDK client; docs is its reference.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| result | No | |
| status | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must bear the full burden. It discloses a critical behavioral trait: 'Never key material' – a security guarantee that agents can rely on. It also describes the perspective ('as this server's wallet sees it') and lists exact fields, but it does not explicitly state whether the operation is mutation-free or describe error conditions. Given the simplicity of a status call, this is adequate additional context over a bare name.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: it states the purpose in the first sentence, lists included fields, adds a security note, and then gives routing guidance for other operations. Every sentence adds value, and nothing is redundant. The structure makes it easy for an agent to quickly grasp what the tool does and what it doesn't do.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple, parameterless tool with an output schema available, the description is complete. It details the content of the state, excludes key material, and explains how it fits into the broader server API (via run and docs). No crucial information an agent would need to call this tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and the input schema is an empty object. Per the rubric, the baseline for 0 parameters is 4. The description does not need to explain any parameters, and it adds no parameter-related information, which is appropriate. It does not compensate for anything because there is nothing to compensate for.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool returns the organization's state as the server's wallet sees it (r.status()), listing specific fields (local_label, server_label, address, tier, lease, allowance, projects, active project). It explicitly notes it never returns key material, distinguishing it from potential secret-retrieval operations. It also differentiates from siblings by stating any other operation is a 'run' snippet, so an agent knows this is the dedicated status call.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear when-to-use signal: this tool is the status operation. It also provides an explicit exclusion: 'Any other operation is a run snippet', which routes agents to the run tool for other tasks. It references 'docs' for the SDK reference, but it does not compare directly with sibling tools like whoami or deploy, so it's clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upA
Plan or run the canonical app-aware run402 up workflow from a local path or repo URL: any missing setup (wallet, tier, project, workspace link), then the deploy. Delegates to the SDK and returns the shared up result envelope with graph steps, resources, diagnostics, and next_actions. deploy only deploys.
| Name | Required | Description | Default |
|---|---|---|---|
| dir | No | Workspace directory to inspect when source is omitted. | |
| yes | No | Approve non-interactive prerequisite, spend, and local-write prompts. | |
| name | No | Project/app instance name, for example kysigned2. | |
| tier | No | Bootstrap tier if account readiness is needed. | |
| source | No | Local app directory or public Git repository URL. Defaults to the current directory. | |
| dry_run | No | Plan only. No gateway mutation, build execution, release commit, local link write, or prune. | |
| manifest | No | Explicit manifest path. Defaults to run402.json, then advanced release-only manifests. | |
| build_mode | No | Override app build mode. | |
| project_id | No | Existing project id to install into. | |
| allow_prune | No | Approve destructive managed-resource prune steps. | |
| no_rehearse | No | Skip the automatic rehearsal. By default a migration-bearing deploy against a project with a live release is rehearsed on a contained branch and committed only on a passing report; a first deploy has nothing to protect and commits directly, and a plan whose migrations are all already applied with an identical checksum is not rehearsed either (result.deploy.rehearsal says which: no_live_release / migrations_unchanged / no_migrations). | |
| display_name | No | Display name to set on this principal (promotion credit and room presence use it); overrides an existing name. Omitted: RUN402_AGENT_NAME when set (same effect); else, only when the principal has no name yet, the detected client name (claude-code, codex, cursor, or grok; RUN402_CLIENT=<name> declares one that is not auto-detected) is set and reported as identity.source "detected"; otherwise nothing is written (identity.source "undetected", room presence 'agent' for coordination only). A detected client that was not applied is still reported under identity.detected / identity.detection. | |
| max_spend_usd | No | Maximum spend up may approve for readiness steps. | |
| idempotency_key | No | Root idempotency key for resumable app-up graph mutations. | |
| allow_shell_build | No | Approve shell-string build commands after review. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| result | No | |
| status | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It discloses plan-vs-run behavior, automatic setup steps (wallet, tier, project, workspace link), delegation to the SDK, and the shared result envelope. It does not spell out all side effects such as spend, local writes, or destructive prune, but these are surfaced through parameter descriptions, and the overall mutating/deploying nature is clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with no filler: the first states the action and scope, the second explains return contents, and the third draws a clear boundary against `deploy`. It is well front-loaded and every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 15-parameter tool with an output schema and complete parameter documentation, the description provides the essential overview, source input options, setup/deploy behavior, and return envelope. It does not cover every behavioral edge case, but those are adequately documented in the schema; only a small amount of extra context about plan-only invocation would make it fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the individual parameter descriptions are rich. The tool description adds only high-level contextual grouping like 'missing setup (wallet, tier, project, workspace link)', which maps to parameters but does not add detailed semantics beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Plan or run the canonical app-aware run402 up workflow'. It also specifies the input source ('local path or repo URL'), what the workflow includes (missing setup + deploy), and differentiates from the sibling `deploy` by noting that 'deploy only deploys'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly frames `up` as the full setup-plus-deploy workflow and distinguishes it from `deploy` with 'deploy only deploys'. This gives an agent enough to choose between the two, though it does not explicitly mention when to prefer other siblings like `status` or `doctor`. The guidance is present but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
whoamiA
The remote identity (r.orgs.whoami()): the control-plane principal this server's wallet resolves to, its active authenticator and linked identities, its org memberships, and the sign-in session grade (none for a wallet). For the local wallet use status. Any other operation is a run snippet against r, the Node SDK client; docs is its reference.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| result | No | |
| status | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the full burden. It discloses not just that the tool returns identity, but the specific elements of that identity, including the nuance that wallet sessions have no grade. It does not explicitly state that the operation is read-only or describe error cases, but that is lightly implied by the whoami concept.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two dense sentences carry substantial information without filler. The first sentence lists the output components, the second provides sibling routing and a note about the SDK. Some technical jargon ('control-plane principal', 'r.orgs.whoami()') makes it less instantly accessible, but each clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-parameter tool with an output schema, the description is nearly complete: it covers what is returned, how to distinguish this from the local wallet tool, and how it fits into the broader run/docs ecosystem. It could optionally explain 'session grade' in plainer language, but this is a minor gap given the output schema likely documents structure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema is trivially 100% covered and the baseline is 4. The description adds no parameter detail because none is needed; it focuses instead on output and context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly defines the tool as returning the remote identity, enumerating its components: control-plane principal, active authenticator, linked identities, org memberships, and session grade. It distinguishes from siblings by explicitly noting that local wallet identity is handled by 'status' and that other operations belong to 'run'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit routing: 'For the local wallet use status' and 'Any other operation is a run snippet'. This tells an agent exactly when to use this tool versus alternatives and when to use run instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
203 tool updates
- Removed
accept_project_transfer - Removed
add_org_member - Removed
admin_archive_project - Removed
admin_reactivate_project - Removed
admin_set_lease_perpetual - Removed
ai_moderate - Removed
ai_translate - Removed
ai_usage - Removed
allowance_create - Removed
allowance_export - Removed
allowance_status - Removed
app_up - Removed
apply_expose - Removed
assets_get - Removed
assets_ls - Removed
assets_put - Removed
assets_rm - Removed
assets_sign - Removed
auth_settings - Removed
billing_history - Removed
browse_apps - Removed
cancel_function_run - Removed
cancel_project_transfer - Removed
check_balance - Removed
ci_create_binding - Removed
ci_get_binding - Removed
ci_list_bindings - Removed
ci_revoke_binding - Removed
claim_project_transfer - Removed
claim_subdomain - Removed
contract_call - Removed
contract_deploy - Removed
contract_read - Removed
create_auth_user - Removed
create_checkout - Removed
create_email_organization - Removed
create_function_run - Removed
create_mailbox - Removed
create_notification_rule - Removed
create_org - Removed
create_project_branch - Removed
create_project_grant - Removed
create_project_snapshot - Removed
delete_function - Removed
delete_mailbox - Removed
delete_mailbox_webhook - Removed
delete_notification_rule - Removed
delete_passkey - Removed
delete_project - Removed
delete_project_branch - Removed
delete_project_snapshot - Removed
delete_secret - Removed
delete_signer - Removed
delete_subdomain - Removed
delete_version - Removed
demote_user - Changed
deploy5 fields changed- removed
Input schema / properties / database / properties / migrations / items / properties / sql_ref / properties / contentTypeRemoved value: -{ - "type": "string" -} - added
Input schema / properties / database / properties / migrations / items / properties / sql_ref / properties / content_typeAdded value: +{ + "type": "string" +} - changed
Input schema / properties / functions / properties / replace / additionalProperties / properties / source / anyOfPrevious value: -[ - { - "type": "string" - }, - { - "additionalProperties": false, - "properties": { - "contentType": { - "description": "MIME type override. Auto-detected from the path's extension when omitted.", - "type": "string" - }, - "data": { - "type": "string" - }, - "encoding": { - "enum": [ - "utf-8", - "base64" - ], - "type": "string" - } - }, - "required": [ - "data" - ], - "type": "object" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "content_type": { + "description": "MIME type override (snake_case, like every wire field). Auto-detected from the path's extension when omitted.", + "type": "string" + }, + "data": { + "type": "string" + }, + "encoding": { + "enum": [ + "utf-8", + "base64" + ], + "type": "string" + } + }, + "required": [ + "data" + ], + "type": "object" + } +] - changed
Input schema / properties / site / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "public_paths": { - "anyOf": [ - { - "additionalProperties": false, - "properties": { - "mode": { - "const": "implicit", - "description": "Restore filename-derived public reachability for static assets.", - "type": "string" - } - }, - "required": [ - "mode" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "mode": { - "const": "explicit", - "description": "Use only the complete replace table as direct public static URLs.", - "type": "string" - }, - "replace": { - "additionalProperties": { - "additionalProperties": false, - "properties": { - "asset": { - "description": "Release static asset path, such as events.html. This is not a public URL.", - "type": "string" - }, - "cache_class": { - "description": "Optional static cache class, for example html, immutable_versioned, or revalidating_asset.", - "type": "string" - } - }, - "required": [ - "asset" - ], - "type": "object" - }, - "description": "Complete map from public browser paths such as /events to release static asset paths such as events.html.", - "type": "object" - } - }, - "required": [ - "mode", - "replace" - ], - "type": "object" - } - ] - }, - "replace": { - "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files" - } - }, - "required": [ - "replace" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "patch": { - "additionalProperties": false, - "properties": { - "delete": { - "items": { - "type": "string" - }, - "type": "array" - }, - "put": { - "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files" - } - }, - "type": "object" - }, - "public_paths": { - "$ref": "#/properties/site/anyOf/0/properties/public_paths" - } - }, - "required": [ - "patch" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "public_paths": { - "$ref": "#/properties/site/anyOf/0/properties/public_paths" - } - }, - "required": [ - "public_paths" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "embedding": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "frame_ancestors": { + "description": "Platform embedding catalog KEYS (never raw origins). `localhost` expands to http://localhost:* and http://127.0.0.1:*; the gateway rejects unknown keys with INVALID_SPEC naming the valid ones.", + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "frame_ancestors" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny." + }, + "public_paths": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "mode": { + "const": "implicit", + "description": "Restore filename-derived public reachability for static assets.", + "type": "string" + } + }, + "required": [ + "mode" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "mode": { + "const": "explicit", + "description": "Use only the complete replace table as direct public static URLs.", + "type": "string" + }, + "replace": { + "additionalProperties": { + "additionalProperties": false, + "properties": { + "asset": { + "description": "Release static asset path, such as events.html. This is not a public URL.", + "type": "string" + }, + "cache_class": { + "description": "Optional static cache class, for example html, immutable_versioned, or revalidating_asset.", + "type": "string" + } + }, + "required": [ + "asset" + ], + "type": "object" + }, + "description": "Complete map from public browser paths such as /events to release static asset paths such as events.html.", + "type": "object" + } + }, + "required": [ + "mode", + "replace" + ], + "type": "object" + } + ] + }, + "replace": { + "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files" + } + }, + "required": [ + "replace" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "embedding": { + "$ref": "#/properties/site/anyOf/0/properties/embedding", + "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny." + }, + "patch": { + "additionalProperties": false, + "properties": { + "delete": { + "items": { + "type": "string" + }, + "type": "array" + }, + "put": { + "$ref": "#/properties/functions/properties/replace/additionalProperties/properties/files" + } + }, + "type": "object" + }, + "public_paths": { + "$ref": "#/properties/site/anyOf/0/properties/public_paths" + } + }, + "required": [ + "patch" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "embedding": { + "$ref": "#/properties/site/anyOf/0/properties/embedding", + "description": "tenant-site-embedding: who may put the site in an iframe. The gateway then sends `Content-Security-Policy: frame-ancestors <expanded origins>` and drops X-Frame-Options on every response of the host. Omit to carry the previous release's declaration forward; null returns to the default deny." + }, + "public_paths": { + "$ref": "#/properties/site/anyOf/0/properties/public_paths" + } + }, + "required": [ + "public_paths" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "embedding": { + "$ref": "#/properties/site/anyOf/0/properties/embedding" + } + }, + "required": [ + "embedding" + ], + "type": "object" + } +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "error": { + "additionalProperties": true, + "properties": { + "category": { + "type": "string" + }, + "code": { + "type": "string" + }, + "column": { + "type": "integer" + }, + "details": {}, + "fix": {}, + "http_status": { + "type": "integer" + }, + "line": { + "type": "integer" + }, + "logs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "message": { + "type": "string" + }, + "mutation_state": { + "type": "string" + }, + "next_actions": { + "items": { + "additionalProperties": true, + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "operation_id": { + "type": "string" + }, + "phase": { + "type": "string" + }, + "plan_id": { + "type": "string" + }, + "resource": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "safe_to_retry": { + "type": "boolean" + }, + "trace_id": { + "type": "string" + } + }, + "required": [ + "code", + "message", + "next_actions" + ], + "type": "object" + }, + "events": { + "items": { + "additionalProperties": true, + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "result": { + "additionalProperties": true, + "properties": { + "next_actions": { + "items": { + "$ref": "#/properties/error/properties/next_actions/items" + }, + "type": "array" + }, + "operation_id": { + "type": "string" + }, + "release_id": { + "type": "string" + }, + "urls": { + "additionalProperties": {}, + "type": "object" + }, + "warnings": { + "items": { + "additionalProperties": true, + "properties": { + "code": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "release_id", + "operation_id", + "urls" + ], + "type": "object" + }, + "status": { + "enum": [ + "ok", + "error" + ], + "type": "string" + }, + "warnings": { + "items": { + "$ref": "#/properties/result/properties/warnings/items" + }, + "type": "array" + } + }, + "required": [ + "status" + ], + "type": "object" +}
- Removed
deploy_diagnose_url - Removed
deploy_events - Removed
deploy_function - Removed
deploy_list - Removed
deploy_rehearse - Removed
deploy_release_active - Removed
deploy_release_diff - Removed
deploy_release_get - Removed
deploy_resume - Removed
deploy_site - Removed
deploy_site_dir - Removed
deploy_verify_edge - Removed
diagnose_public_url - Added
docs - Added
doctor - Removed
domains_activate - Removed
domains_apply - Removed
domains_check - Removed
domains_disconnect - Removed
domains_ensure - Removed
domains_get - Removed
domains_list - Removed
domains_repair - Removed
domains_test_receive - Removed
drain_signer - Removed
errors_list - Added
expand_result - Removed
export_project_archive - Removed
fork_app - Removed
functions_rebuild - Removed
generate_image - Removed
get_agent_contact_status - Removed
get_app - Removed
get_contract_call_status - Removed
get_email - Removed
get_email_raw - Removed
get_expose - Removed
get_function_logs - Removed
get_function_run - Removed
get_function_run_logs - Removed
get_mailbox - Removed
get_mailbox_webhook - Removed
get_notification_preferences - Removed
get_operator_status - Removed
get_org - Removed
get_project_snapshot - Removed
get_quote - Removed
get_schema - Removed
get_signer - Removed
get_usage - Removed
import_project_archive - Removed
init - Removed
initiate_project_transfer - Removed
inspect_project_archive - Removed
invite_auth_user - Removed
invoke_function - Removed
jobs_cancel - Removed
jobs_download_artifact - Removed
jobs_get - Removed
jobs_logs - Removed
jobs_purge - Removed
jobs_submit - Removed
link_wallet_to_organization - Removed
list_emails - Removed
list_function_runs - Removed
list_functions - Removed
list_incoming_transfers - Removed
list_mailbox_webhook_deliveries - Removed
list_mailbox_webhooks - Removed
list_mailboxes - Removed
list_notification_channels - Removed
list_notification_rules - Removed
list_notifications - Removed
list_org_members - Removed
list_orgs - Removed
list_outgoing_transfers - Removed
list_passkeys - Removed
list_project_branches - Removed
list_project_events - Removed
list_project_snapshots - Removed
list_projects - Removed
list_secrets - Removed
list_signers - Removed
list_subdomains - Removed
list_tenant_payments - Removed
list_versions - Removed
passkey_login_options - Removed
passkey_login_verify - Removed
passkey_register_options - Removed
passkey_register_verify - Removed
pay_url - Removed
preview_project_transfer - Removed
project_get - Removed
project_key_cache_export - Removed
project_key_cache_status - Removed
project_use - Removed
promote_user - Removed
provision_postgres_project - Removed
provision_signer - Removed
publish_app - Removed
redrive_function_run - Removed
redrive_mailbox_webhook_delivery - Removed
register_mailbox_webhook - Removed
remove_org_member - Removed
rename_org - Removed
rename_project - Removed
renew_project_branch - Removed
request_faucet - Removed
request_magic_link - Removed
rest_query - Removed
restore_project_snapshot - Removed
revoke_project_grant - Removed
rotate_webhook_secret - Added
run - Removed
run_sql - Removed
scaffold_roles - Removed
send_email - Removed
send_message - Removed
service_health - Removed
service_status - Removed
set_agent_contact - Removed
set_auto_recharge - Removed
set_low_balance_alert - Removed
set_mailbox_defaults - Removed
set_notification_preferences - Removed
set_org_member_role - Removed
set_org_payout_wallet - Removed
set_recovery_address - Removed
set_secret - Removed
set_tier - Removed
set_user_password - Removed
start_operator_passkey_enrollment - Changed
status2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "error": { + "additionalProperties": true, + "properties": { + "category": { + "type": "string" + }, + "code": { + "type": "string" + }, + "column": { + "type": "integer" + }, + "details": {}, + "fix": {}, + "http_status": { + "type": "integer" + }, + "line": { + "type": "integer" + }, + "logs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "message": { + "type": "string" + }, + "mutation_state": { + "type": "string" + }, + "next_actions": { + "items": { + "additionalProperties": true, + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "operation_id": { + "type": "string" + }, + "phase": { + "type": "string" + }, + "plan_id": { + "type": "string" + }, + "resource": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "safe_to_retry": { + "type": "boolean" + }, + "trace_id": { + "type": "string" + } + }, + "required": [ + "code", + "message", + "next_actions" + ], + "type": "object" + }, + "result": { + "additionalProperties": true, + "properties": { + "active_project": { + "type": [ + "string", + "null" + ] + }, + "projects": { + "items": { + "additionalProperties": true, + "properties": { + "project_id": { + "type": "string" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "type": "array" + }, + "tier": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "expires": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "name", + "status", + "expires" + ], + "type": "object" + }, + { + "type": "null" + } + ] + }, + "wallet": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "address": { + "type": "string" + }, + "local_label": { + "type": "string" + }, + "server_label": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "local_label", + "address" + ], + "type": "object" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "wallet", + "projects", + "active_project" + ], + "type": "object" + }, + "status": { + "enum": [ + "ok", + "error" + ], + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" +}
- Removed
test_notification - Removed
tier_status - Added
up - Removed
update_function - Removed
update_mailbox - Removed
update_mailbox_webhook - Removed
update_version - Removed
validate_manifest - Removed
verify_agent_contact_email - Removed
verify_magic_link - Removed
verify_project_archive - Removed
wait_for_cdn_freshness - Changed
whoami2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "error": { + "additionalProperties": true, + "properties": { + "category": { + "type": "string" + }, + "code": { + "type": "string" + }, + "column": { + "type": "integer" + }, + "details": {}, + "fix": {}, + "http_status": { + "type": "integer" + }, + "line": { + "type": "integer" + }, + "logs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "message": { + "type": "string" + }, + "mutation_state": { + "type": "string" + }, + "next_actions": { + "items": { + "additionalProperties": true, + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "operation_id": { + "type": "string" + }, + "phase": { + "type": "string" + }, + "plan_id": { + "type": "string" + }, + "resource": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "safe_to_retry": { + "type": "boolean" + }, + "trace_id": { + "type": "string" + } + }, + "required": [ + "code", + "message", + "next_actions" + ], + "type": "object" + }, + "result": { + "additionalProperties": true, + "properties": { + "memberships": { + "items": { + "additionalProperties": true, + "properties": { + "org_id": { + "type": "string" + }, + "role": { + "type": "string" + } + }, + "required": [ + "org_id" + ], + "type": "object" + }, + "type": "array" + }, + "principal": { + "additionalProperties": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "session": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "grade": { + "type": "string" + } + }, + "type": "object" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "principal", + "memberships" + ], + "type": "object" + }, + "status": { + "enum": [ + "ok", + "error" + ], + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" +}
3 tool updates
v4.13.3- Added
pay_url - Changed
request_magic_link4 fields changed- added
Input schema / properties / deliveryAdded value: +{ + "description": "Email credential mode. Defaults to link.", + "enum": [ + "link", + "code", + "both" + ], + "type": "string" +} - changed
Input schema / properties / email / descriptionPrevious value: -"Email address to send the magic link to"New value: +"Email address to authenticate" - changed
Input schema / properties / redirect_url / descriptionPrevious value: -"URL to redirect to after clicking the magic link. Must be an allowed origin for this project (localhost, claimed subdomain, or custom domain)."New value: +"Allowed redirect URL. Required for link/both; optional for code." - changed
Input schema / requiredPrevious value: -[ - "project_id", - "email", - "redirect_url" -]New value: +[ + "project_id", + "email" +]
- Changed
verify_magic_link4 fields changed- added
Input schema / properties / challenge_idAdded value: +{ + "description": "Opaque email-code challenge handle. Required with code.", + "type": "string" +} - added
Input schema / properties / codeAdded value: +{ + "description": "Six-digit email code. Required with challenge_id.", + "type": "string" +} - changed
Input schema / properties / token / descriptionPrevious value: -"The magic link token from the email link URL (?token=...)"New value: +"Magic-link token. Mutually exclusive with challenge_id/code." - changed
Input schema / requiredPrevious value: -[ - "project_id", - "token" -]New value: +[ + "project_id" +]
5 tool updates
v4.8.0- Added
create_notification_rule - Added
delete_notification_rule - Added
list_notification_channels - Added
list_notification_rules - Changed
test_notification3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / event_typeAdded value: +{ + "description": "Synthetic event_type override (flat snake_case, e.g. `signature_failed`) — use this to exercise a specific routing rule's `event_types` filter precisely. Defaults to the gateway's built-in sample event when omitted.", + "type": "string" +} - added
Input schema / properties / sourceAdded value: +{ + "description": "Route the synthetic test event as if it came from the app lane or the platform, so it exercises a specific Telegram routing rule's `source` filter. Defaults to 'platform' when omitted.", + "enum": [ + "app", + "platform" + ], + "type": "string" +}
1 tool update
v4.6.0- Changed
list_project_events2 fields changed- added
Input schema / properties / event_typeAdded value: +{ + "description": "Restrict to one or more event types, comma-separated (e.g. \"signature_completed,booking_created\"). Composes with source — e.g. source: \"app\" + event_type to watch for one specific business fact.", + "type": "string" +} - added
Input schema / properties / sourceAdded value: +{ + "description": "Restrict to one source: \"app\" (business facts a deployed function emitted itself via events.emit) or \"platform\" (every non-app source — the platform's own operational record). Omit to read both lanes in one merged, cursor-ordered feed.", + "enum": [ + "app", + "platform" + ], + "type": "string" +}
1 tool update
v4.5.0- Added
errors_list
1 tool update
v4.4.0- Added
list_project_events
1 tool update
v4.2.1- Changed
invoke_function4 fields changed- added
Input schema / properties / idempotency_keyAdded value: +{ + "description": "Stable Idempotency-Key required by paid function invocations. Reuse it for the same paid intent; use a new key only for a new paid intent.", + "type": "string" +} - added
Input schema / properties / poll_interval_msAdded value: +{ + "description": "Polling interval in milliseconds when wait is true.", + "minimum": 0, + "type": "integer" +} - added
Input schema / properties / timeout_msAdded value: +{ + "description": "Maximum wait time in milliseconds when wait is true.", + "exclusiveMinimum": 0, + "type": "integer" +} - added
Input schema / properties / waitAdded value: +{ + "description": "When a paid invocation returns a 202 run handle, poll the run and replay the same idempotency key for the retained result.", + "type": "boolean" +}
2 tool updates
v4.2.0- Added
list_tenant_payments - Added
set_org_payout_wallet
1 tool update
v4.1.0- Added
deploy_verify_edge
10 tool updates
v4.0.3- Added
create_project_branch - Added
create_project_snapshot - Added
delete_project_branch - Added
delete_project_snapshot - Added
deploy_rehearse - Added
get_project_snapshot - Added
list_project_branches - Added
list_project_snapshots - Added
renew_project_branch - Added
restore_project_snapshot
32 tool updates
v4.0.2- Removed
add_custom_domain - Added
app_up - Added
cancel_function_run - Removed
check_domain_status - Added
create_function_run - Changed
create_mailbox1 field changed- changed
Input schema / properties / slug / descriptionPrevious value: -"Mailbox slug (3-63 chars, lowercase alphanumeric + hyphens, no consecutive hyphens). Creates <slug>@mail.run402.com"New value: +"Project-scoped mailbox local part (3-63 chars, lowercase alphanumeric + hyphens, no consecutive hyphens). Creates <slug>@<project-mail-host>.mail.run402.com"
- Changed
deploy3 fields changed- changed
Input schema / properties / database / properties / migrations / items / properties / id / descriptionPrevious value: -"Stable migration id (e.g. '001_init'). Same id+checksum across re-deploys is a registry noop; same id+different checksum is a hard error."New value: +"Stable versioned migration id (e.g. '001_init'). Same id+checksum across re-deploys is a registry noop; same id+different checksum is a hard error. Use name instead for generated/idempotent SQL." - added
Input schema / properties / database / properties / migrations / items / properties / nameAdded value: +{ + "description": "Content-tracked migration name for generated/idempotent SQL. The SDK compiles this to <name>_<sha256(sql)[0:16]>; changed content applies once under a new id and identical re-deploys noop. SQL declared with name MUST be idempotent.", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$", + "type": "string" +} - removed
Input schema / properties / database / properties / migrations / items / requiredRemoved value: -[ - "id" -]
- Removed
disable_sender_domain_inbound - Added
domains_activate - Added
domains_apply - Added
domains_check - Added
domains_disconnect - Added
domains_ensure - Added
domains_get - Added
domains_list - Added
domains_repair - Added
domains_test_receive - Removed
enable_sender_domain_inbound - Changed
get_function_logs2 fields changed- changed
Input schema / properties / request_id / descriptionPrevious value: -"Only return logs correlated to this routed/function request id, such as req_abc123."New value: +"Only return logs correlated to this routed request id, function run id, or attempt id, such as req_abc123, fnrun_abc123, or fnatt_abc123." - changed
Input schema / properties / request_id / patternPrevious value: -"^req_[A-Za-z0-9_-]{4,128}$"New value: +"^(?:req|fnrun|fnatt)_[A-Za-z0-9_-]{4,128}$"
- Added
get_function_run - Added
get_function_run_logs - Removed
list_custom_domains - Added
list_function_runs - Removed
project_info - Added
project_key_cache_export - Added
project_key_cache_status - Removed
project_keys - Added
redrive_function_run - Removed
register_sender_domain - Removed
remove_custom_domain - Removed
remove_sender_domain - Removed
sender_domain_status
171 tool updates
v3.6.0- First observed
accept_project_transfer - First observed
add_custom_domain - First observed
add_org_member - First observed
admin_archive_project - First observed
admin_reactivate_project - First observed
admin_set_lease_perpetual - First observed
ai_moderate - First observed
ai_translate - First observed
ai_usage - First observed
allowance_create - First observed
allowance_export - First observed
allowance_status - First observed
apply_expose - First observed
assets_get - First observed
assets_ls - First observed
assets_put - First observed
assets_rm - First observed
assets_sign - First observed
auth_settings - First observed
billing_history - First observed
browse_apps - First observed
cancel_project_transfer - First observed
check_balance - First observed
check_domain_status - First observed
ci_create_binding - First observed
ci_get_binding - First observed
ci_list_bindings - First observed
ci_revoke_binding - First observed
claim_project_transfer - First observed
claim_subdomain - First observed
contract_call - First observed
contract_deploy - First observed
contract_read - First observed
create_auth_user - First observed
create_checkout - First observed
create_email_organization - First observed
create_mailbox - First observed
create_org - First observed
create_project_grant - First observed
delete_function - First observed
delete_mailbox - First observed
delete_mailbox_webhook - First observed
delete_passkey - First observed
delete_project - First observed
delete_secret - First observed
delete_signer - First observed
delete_subdomain - First observed
delete_version - First observed
demote_user - First observed
deploy - First observed
deploy_diagnose_url - First observed
deploy_events - First observed
deploy_function - First observed
deploy_list - First observed
deploy_release_active - First observed
deploy_release_diff - First observed
deploy_release_get - First observed
deploy_resume - First observed
deploy_site - First observed
deploy_site_dir - First observed
diagnose_public_url - First observed
disable_sender_domain_inbound - First observed
drain_signer - First observed
enable_sender_domain_inbound - First observed
export_project_archive - First observed
fork_app - First observed
functions_rebuild - First observed
generate_image - First observed
get_agent_contact_status - First observed
get_app - First observed
get_contract_call_status - First observed
get_email - First observed
get_email_raw - First observed
get_expose - First observed
get_function_logs - First observed
get_mailbox - First observed
get_mailbox_webhook - First observed
get_notification_preferences - First observed
get_operator_status - First observed
get_org - First observed
get_quote - First observed
get_schema - First observed
get_signer - First observed
get_usage - First observed
import_project_archive - First observed
init - First observed
initiate_project_transfer - First observed
inspect_project_archive - First observed
invite_auth_user - First observed
invoke_function - First observed
jobs_cancel - First observed
jobs_download_artifact - First observed
jobs_get - First observed
jobs_logs - First observed
jobs_purge - First observed
jobs_submit - First observed
link_wallet_to_organization - First observed
list_custom_domains - First observed
list_emails - First observed
list_functions - First observed
list_incoming_transfers - First observed
list_mailbox_webhook_deliveries - First observed
list_mailbox_webhooks - First observed
list_mailboxes - First observed
list_notifications - First observed
list_org_members - First observed
list_orgs - First observed
list_outgoing_transfers - First observed
list_passkeys - First observed
list_projects - First observed
list_secrets - First observed
list_signers - First observed
list_subdomains - First observed
list_versions - First observed
passkey_login_options - First observed
passkey_login_verify - First observed
passkey_register_options - First observed
passkey_register_verify - First observed
preview_project_transfer - First observed
project_get - First observed
project_info - First observed
project_keys - First observed
project_use - First observed
promote_user - First observed
provision_postgres_project - First observed
provision_signer - First observed
publish_app - First observed
redrive_mailbox_webhook_delivery - First observed
register_mailbox_webhook - First observed
register_sender_domain - First observed
remove_custom_domain - First observed
remove_org_member - First observed
remove_sender_domain - First observed
rename_org - First observed
rename_project - First observed
request_faucet - First observed
request_magic_link - First observed
rest_query - First observed
revoke_project_grant - First observed
rotate_webhook_secret - First observed
run_sql - First observed
scaffold_roles - First observed
send_email - First observed
send_message - First observed
sender_domain_status - First observed
service_health - First observed
service_status - First observed
set_agent_contact - First observed
set_auto_recharge - First observed
set_low_balance_alert - First observed
set_mailbox_defaults - First observed
set_notification_preferences - First observed
set_org_member_role - First observed
set_recovery_address - First observed
set_secret - First observed
set_tier - First observed
set_user_password - First observed
start_operator_passkey_enrollment - First observed
status - First observed
test_notification - First observed
tier_status - First observed
update_function - First observed
update_mailbox - First observed
update_mailbox_webhook - First observed
update_version - First observed
validate_manifest - First observed
verify_agent_contact_email - First observed
verify_magic_link - First observed
verify_project_archive - First observed
wait_for_cdn_freshness - First observed
whoami
TDQS
Scored across 8 tools
Most tools have clearly distinct purposes: status, whoami, doctor, docs, run, and expand_result are each unique. The main overlap is between up and deploy, where up bundles setup plus deploy and deploy is the lower-level apply primitive; descriptions clarify the difference, but an agent might still be uncertain which to call for a simple deployment.
Naming is mixed: some tools are single verbs (up, deploy, run), some are nouns (status, doctor, docs), and expand_result uses snake_case with a verb_noun pattern. The names are readable and follow CLI conventions, but there is no consistent grammatical pattern across the set.
With 8 tools, the server is well-scoped: it exposes high-level workflows (up, deploy), status/inspection (status, whoami, doctor), a reference (docs), a generic execution primitive (run), and a result-pagination helper (expand_result). Each tool earns its place without bloat.
The surface is intentionally minimal but has no real gaps because run provides a generic SDK snippet escape hatch, and the docs tool gives the reference needed to use it. Common workflows are covered by up/deploy, status/whoami/doctor handle inspection, and expand_result ensures large results are accessible.
Maintenance
Related MCP Connectors
Remote MCP server exposing 330 production AI-agent services for web/data processing, validation, AI utilities, blockchain/crypto utilities, and x402 pay-per-use access.
Hosted MCP server for AI-driven data ops. Create apps, manage schemas, and CRUD structured data.
Accountless pay-per-use sandbox, storage, locks, attestation and handoff. Paid over MCP with x402.
Pay-per-action access to APIs and MCP tools over Lightning L402 and Base USDC x402.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA general-purpose PostgreSQL MCP server with full read-write SQL access, atomic multi-statement transactions, and schema inspection. Works with any PostgreSQL instance — local, Supabase, AWS RDS, or self-hosted — and connects to Claude, Cursor, Windsurf, or any MCP-compatible AI client.127 npm3ISC
- AlicenseNot gradedqualityCmaintenanceAn extensible MCP server for database operations that supports PostgreSQL for managing schemas, tables, data, and user permissions. It features automatic migration recording for DDL changes and integrates with various AI-powered editors like Cursor, Zed, and Claude Code.16 npm2MIT
- FlicenseNot gradedqualityDmaintenanceEnables interaction with a PostgreSQL database via MCP, using Docker and NestJS for AI-powered database operations.-
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to securely interact with PostgreSQL databases through a standardized MCP interface, supporting SQL queries, schema inspection, and database management.MIT