@buildbase/sdk 0.0.53 โ†’ 0.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/AGENTS.md +16 -6
  2. package/CHANGELOG.md +99 -0
  3. package/LICENSE +21 -0
  4. package/README.md +278 -85
  5. package/dist/css/styles.css +1 -1
  6. package/dist/index.cjs +1 -1
  7. package/dist/index.d.ts +582 -114
  8. package/dist/index.mjs +1 -1
  9. package/dist/mcp/index.cjs +1 -1
  10. package/dist/mcp/index.d.ts +780 -16
  11. package/dist/mcp/index.mjs +1 -1
  12. package/dist/react/chunks/SettingsDialog-B6DhyNae.cjs +2 -0
  13. package/dist/react/chunks/SettingsDialog-K38BI74F.mjs +2 -0
  14. package/dist/react/chunks/SubscriptionDialog-BidcQ_vc.mjs +2 -0
  15. package/dist/react/chunks/SubscriptionDialog-CfDLoOzW.cjs +2 -0
  16. package/dist/react/chunks/ar-CCKONfUU.mjs +2 -0
  17. package/dist/react/chunks/ar-DrHMtT1E.cjs +2 -0
  18. package/dist/react/chunks/de-Dhtorn10.cjs +2 -0
  19. package/dist/react/chunks/de-X9mfnMFM.mjs +2 -0
  20. package/dist/react/chunks/es--8iZ7Trv.mjs +2 -0
  21. package/dist/react/chunks/es-CUR7LB6a.cjs +2 -0
  22. package/dist/react/chunks/fr-BqMs_F5g.cjs +2 -0
  23. package/dist/react/chunks/fr-rUp34NG7.mjs +2 -0
  24. package/dist/react/chunks/hi-B_IiucJZ.mjs +2 -0
  25. package/dist/react/chunks/hi-C2i1_hdv.cjs +2 -0
  26. package/dist/react/chunks/ja-4hLI6wMX.cjs +2 -0
  27. package/dist/react/chunks/ja-CIGOj3vV.mjs +2 -0
  28. package/dist/react/chunks/react-BXTDLnE8.cjs +2 -0
  29. package/dist/react/chunks/react-CXCk05WI.mjs +2 -0
  30. package/dist/react/chunks/zh-BSgd6ai5.cjs +2 -0
  31. package/dist/react/chunks/zh-DyVvcYFC.mjs +2 -0
  32. package/dist/react/index.cjs +1 -1
  33. package/dist/react/index.d.ts +507 -141
  34. package/dist/react/index.mjs +1 -1
  35. package/docs/ARCHITECTURE.md +419 -0
  36. package/docs/ERROR_CODES.md +96 -0
  37. package/docs/MCP-AND-AGENT-READINESS.md +893 -0
  38. package/docs/THEMING.md +67 -0
  39. package/docs/UI-CONFIG.md +207 -0
  40. package/package.json +17 -4
  41. package/dist/react/chunks/SettingsDialog-BxDYsie6.mjs +0 -2
  42. package/dist/react/chunks/SettingsDialog-Dy8W3NA6.cjs +0 -2
  43. package/dist/react/chunks/SubscriptionDialog-6c5dHoQd.mjs +0 -2
  44. package/dist/react/chunks/SubscriptionDialog-CpVnnXJg.cjs +0 -2
  45. package/dist/react/chunks/ar-1Z1MOGAP.mjs +0 -2
  46. package/dist/react/chunks/ar-VGzBv3AZ.cjs +0 -2
  47. package/dist/react/chunks/de-BjdDg60Y.cjs +0 -2
  48. package/dist/react/chunks/de-CXUItplO.mjs +0 -2
  49. package/dist/react/chunks/es-BBPsSZUp.cjs +0 -2
  50. package/dist/react/chunks/es-BTbzVutz.mjs +0 -2
  51. package/dist/react/chunks/fr-Cax48X_S.cjs +0 -2
  52. package/dist/react/chunks/fr-DPMeOQu3.mjs +0 -2
  53. package/dist/react/chunks/hi-BJqvpG6d.cjs +0 -2
  54. package/dist/react/chunks/hi-JfJx-LV7.mjs +0 -2
  55. package/dist/react/chunks/ja-CDGtLzTk.mjs +0 -2
  56. package/dist/react/chunks/ja-DvVyj5xX.cjs +0 -2
  57. package/dist/react/chunks/react-4SlWxHdh.cjs +0 -2
  58. package/dist/react/chunks/react-OL1uSkpr.mjs +0 -2
  59. package/dist/react/chunks/zh-BAcqxkxk.cjs +0 -2
  60. package/dist/react/chunks/zh-BNZ2Ooe8.mjs +0 -2
package/README.md CHANGED
@@ -7,6 +7,7 @@ Also works server-side (Next.js API routes, Express, Hono) โ€” see [Server-Side
7
7
  ## ๐Ÿ“‘ Table of Contents
8
8
 
9
9
  - [Features](#-features)
10
+ - [Customization Map](#-customization-map)
10
11
  - [Installation](#installation)
11
12
  - [Quick Start](#quick-start)
12
13
  - [UI Configuration](#๏ธ-ui-configuration)
@@ -19,6 +20,7 @@ Also works server-side (Next.js API routes, Express, Hono) โ€” see [Server-Side
19
20
  - [Trial Gates](#-trial-gates)
20
21
  - [Push Notifications](#-push-notifications)
21
22
  - [Notifications](#-notifications)
23
+ - [Connected Agents](#-connected-agents)
22
24
  - [User Management](#-user-management)
23
25
  - [Workspace Management](#-complete-workspace-management)
24
26
  - [Public Pricing (No Login)](#-public-pricing-no-login)
@@ -52,6 +54,7 @@ Also works server-side (Next.js API routes, Express, Hono) โ€” see [Server-Side
52
54
  - **โณ Trial Gates** - `WhenTrialing`, `WhenNotTrialing`, `WhenTrialEnding` components + `useTrialStatus` hook
53
55
  - **๐Ÿ”” Push Notifications** - Browser push notifications with `usePushNotifications` hook, auto-triggers for billing events, and campaign management
54
56
  - **๐Ÿ“ฌ Notifications** - Email + push notification system with per-event channel control, workspace preferences, and server-side `notification.send()` API
57
+ - **๐Ÿ”Œ Connected Agents** - `<ConnectedAgents />` screen to list/revoke authorized AI agents, plus a built-in "Connect an agent" setup guide (ChatGPT, Claude, Cursor, VS Code, Windsurf, Cline) driven by an `mcp` provider prop
55
58
  - **๐Ÿ’บ Seat-Based Pricing** - Per-seat billing with included seats, billable seat tracking, and seat limit enforcement
56
59
  - **๐Ÿ’ฑ Multi-Currency** - Per-currency pricing variants with workspace billing currency lock
57
60
  - **๐Ÿค Affiliate Tracking** - Pass referral data to Stripe checkout via `getCheckoutStripeParams` prop (Rewardful, Endorsely, FirstPromoter, etc.)
@@ -66,6 +69,31 @@ Also works server-side (Next.js API routes, Express, Hono) โ€” see [Server-Side
66
69
  - **๐ŸŒ Internationalization (i18n)** - 8 locales (en, es, fr, de, ja, zh, hi, ar), ICU MessageFormat, RTL support, native numerals
67
70
  - **๐Ÿ  Workspace Modes** - Personal (solo B2C) or Platform (multi-user B2B), configured from admin dashboard
68
71
 
72
+ ## ๐ŸŽจ Customization Map
73
+
74
+ Everything the SDK lets you configure, override, or extend โ€” one row per knob, so you can see the whole surface before reading any deep-dive section. The philosophy throughout: **safe defaults, everything overridable, the SDK accelerates but never gates.**
75
+
76
+ | What you customize | How | Where to read more |
77
+ | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
78
+ | Provider setup & workspace behavior | `<SaaSOSProvider>` / `<BuildBaseProvider>` props (`serverUrl`, `orgId`, `locale`, workspace auto-create, redirects) | [Configuration Reference](#๏ธ-configuration-reference) |
79
+ | Which SDK UI renders at all | `ui` prop: hide/show settings sections, workspace switcher, per-screen toggles | [UI Configuration](#๏ธ-ui-configuration) ยท `docs/UI-CONFIG.md` |
80
+ | Every user-facing string | `ui.messages` deep-override (e.g. rename "Subscription" โ†’ "Billing"), per-locale | [UI Configuration](#๏ธ-ui-configuration) |
81
+ | Language & number systems | `locale` prop โ€” 8 locales, ICU plurals, RTL (`ar`), native numerals | [Internationalization](#-internationalization-i18n) |
82
+ | Look & feel | CSS custom properties (`--primary`, `--destructive`, โ€ฆ) โ€” semantic tokens, light/dark, no palette lock-in | `docs/THEMING.md` |
83
+ | Date/number formats | `ui.formats` (`Intl` options passed through) | `docs/UI-CONFIG.md` |
84
+ | Conditional UI | Gate components: `WhenAuthenticated`, `WhenPermission`, `WhenWorkspaceFeatureEnabled`, `WhenSubscription`, `WhenTrialing`, `WhenQuotaAvailable`, `WhenCreditsAvailable`, โ€ฆ | [Subscription Gates](#-subscription-gates) & siblings |
85
+ | Checkout behavior | `getCheckoutStripeParams` (affiliate/referral params), plan-picker behavior config | [Affiliate Tracking](#affiliate--referral-tracking) |
86
+ | Connect-an-agent guide | `mcp` prop (`url`, `name`, `docsUrl`, `clients`, `prompt`) โ†’ in-app setup guide + `<ConnectedAgents />` screen | [Connected Agents](#-connected-agents) |
87
+ | Error presentation | `ui.errorBoundary`, centralized `handleError` reporting | [Error Handling](#๏ธ-error-handling) |
88
+ | React-free server access | `BuildBase()` factory โ€” workspaces, usage, credits, notifications from API routes/jobs | [Server-Side Usage](#server-side-usage) |
89
+ | Agent discovery surface | `createAgentStack` / `resolveAgentPath`: robots.txt, llms.txt, `.well-known/*`, all documents overridable (e.g. `config.llmsTxt`) | [Agent Readiness](#agent-readiness-discovery) ยท `docs/MCP-AND-AGENT-READINESS.md` |
90
+ | MCP tools | `builtinTools` (`'readonly'`/`'all'`/`false`/include/exclude) + your own via `defineMcpTool` (custom tools override built-ins) | [MCP Server](#mcp-server-buildbasesdkmcp) |
91
+ | MCP resources & prompts | Opt-in `builtinResources` catalog + `defineMcpResource`/`defineMcpResourceTemplate`/`defineMcpPrompt` | [MCP Server](#mcp-server-buildbasesdkmcp) |
92
+ | MCP auth & hardening | `auth.verify` (your token format) or `buildbaseAuth` preset; `rateLimit`, `cors`, `allowedOrigins`, `formatToolError` | `docs/MCP-AND-AGENT-READINESS.md` |
93
+ | Per-request context for your MCP tools | `context(auth, req)` factory โ†’ `ctx.custom` (your DB, services) | [MCP Server](#mcp-server-buildbasesdkmcp) |
94
+ | Money display | `formatMinorAmountIntl`/`formatCents`/`getCurrencyDecimals` โ€” full ISO 4217 (0/2/3-decimal currencies) | [Multi-Currency](#-multi-currency--pricing-utilities) |
95
+ | Webhooks from the platform | `verifyWebhookSignature` (HMAC, timing-safe) | [Webhook Verification](#webhook-verification) |
96
+
69
97
  ## Installation
70
98
 
71
99
  ```bash
@@ -87,6 +115,7 @@ import '@buildbase/sdk/css';
87
115
  // components/provider.tsx
88
116
  'use client';
89
117
 
118
+ // BuildBaseProvider is an identical brand-aligned alias โ€” prefer it in new code
90
119
  import { SaaSOSProvider } from '@buildbase/sdk/react';
91
120
  import { ApiVersion } from '@buildbase/sdk';
92
121
 
@@ -283,7 +312,7 @@ function MembersPanel() {
283
312
 
284
313
  `useUIConfig()` gives you the raw `ui` object if you only need the config values; `mergeUIConfig(base, override)` is the deep-merge used for per-dialog overrides.
285
314
 
286
- ๐Ÿ“– **Full guide with the complete toggle reference, precedence rules, and recipes (single-tenant, external billing, white-label, read-only): [docs/UI-CONFIG.md](./docs/UI-CONFIG.md)**
315
+ ๐Ÿ“– **Full guide with the complete toggle reference, precedence rules, and recipes (single-tenant, external billing, white-label, read-only): [docs/UI-CONFIG.md](https://unpkg.com/@buildbase/sdk/docs/UI-CONFIG.md)**
287
316
 
288
317
  ## ๐Ÿ” Authentication
289
318
 
@@ -346,9 +375,16 @@ openWorkspaceSettings('users'); // Workspace members
346
375
  openWorkspaceSettings('subscription'); // Plan & Billing
347
376
  openWorkspaceSettings('usage'); // Quota usage dashboard
348
377
  openWorkspaceSettings('features'); // Feature toggles
378
+ openWorkspaceSettings('connected-agents'); // Connected AI agents + connect guide
349
379
  openWorkspaceSettings('danger'); // Delete workspace (owner only)
350
380
  ```
351
381
 
382
+ Some sections accept an optional second `action` argument to deep-link past the screen. For connected agents, open the setup guide directly:
383
+
384
+ ```tsx
385
+ openWorkspaceSettings('connected-agents', { action: 'openConnectGuide' });
386
+ ```
387
+
352
388
  ### Authentication Components
353
389
 
354
390
  For declarative rendering, use the conditional components:
@@ -504,7 +540,9 @@ Use the `useUserFeatures` hook to check feature flags programmatically:
504
540
  import { useUserFeatures } from '@buildbase/sdk/react';
505
541
 
506
542
  function FeatureCheck() {
507
- const { features, isFeatureEnabled, refreshFeatures } = useUserFeatures();
543
+ // { features, isFeatureEnabled, loading, error, refetch }
544
+ // (the older `isLoading` / `refreshFeatures` names still work but are deprecated)
545
+ const { features, isFeatureEnabled, refetch } = useUserFeatures();
508
546
 
509
547
  return (
510
548
  <div>{isFeatureEnabled('premium-features') ? <PremiumContent /> : <StandardContent />}</div>
@@ -1074,6 +1112,57 @@ Platform mode supports granular overrides from the admin dashboard:
1074
1112
 
1075
1113
  These let you achieve team-like, managed, or enterprise-like behavior without a separate mode.
1076
1114
 
1115
+ ## ๐Ÿ”Œ Connected Agents
1116
+
1117
+ Let users connect AI agents to their account and manage them. `<ConnectedAgents />` is a ready-made screen (also a workspace settings section) that lists the agents a user has authorized โ€” each with a **Disconnect** action โ€” and, when you provide an MCP server address, shows a **Connect an agent** button that opens a plain-language setup guide.
1118
+
1119
+ ### Enable the connect guide
1120
+
1121
+ Pass an `mcp` config to the provider. Without it the screen still lists and revokes agents; with it, the "Connect an agent" button and setup dialog appear.
1122
+
1123
+ ```tsx
1124
+ <SaaSOSProvider
1125
+ // ...serverUrl, orgId, auth
1126
+ mcp={{
1127
+ url: 'https://app.example.com/api/mcp', // your MCP server endpoint (required to show the guide)
1128
+ name: 'Acme', // friendly name used in prose + config snippets
1129
+ docsUrl: 'https://docs.example.com/agents', // optional "Learn more" link
1130
+ }}
1131
+ >
1132
+ ```
1133
+
1134
+ The dialog walks users through the major AI apps โ€” **ChatGPT, Claude, Cursor, VS Code, Windsurf, Cline** โ€” each with the exact click-path or config-file snippet (your server URL is filled in for them), plus a copy-and-paste prompt for chat assistants. It's fully translated (all 8 locales), RTL-aware, and responsive (full-screen on mobile, centered card on desktop).
1135
+
1136
+ ### The screen
1137
+
1138
+ ```tsx
1139
+ import { ConnectedAgents } from '@buildbase/sdk/react';
1140
+
1141
+ function AgentsPage() {
1142
+ return <ConnectedAgents />;
1143
+ }
1144
+ ```
1145
+
1146
+ Props: `title`, `description`, `disconnectLabel`, `emptyLabel` (all default to translated strings; pass `null` to hide the heading) and `showConnectGuide` (default `true` โ€” set `false` to hide the connect button even when `mcp` is configured).
1147
+
1148
+ Because it's a settings section, you can also open it programmatically:
1149
+
1150
+ ```tsx
1151
+ const { openWorkspaceSettings } = useSaaSAuth();
1152
+
1153
+ openWorkspaceSettings('connected-agents'); // the screen (list + connect button)
1154
+ openWorkspaceSettings('connected-agents', { action: 'openConnectGuide' }); // straight to the setup dialog
1155
+ ```
1156
+
1157
+ The same deep link works via URL: `?bb=action:openConnectGuide`.
1158
+
1159
+ ### Custom UI
1160
+
1161
+ - **`useConnectedAgents()`** โ€” headless `{ agents, loading, error, revoking, refresh, revoke }` for a fully custom list.
1162
+ - **`useMcpConnection()`** โ€” the `mcp` config you passed (or `null`), for building your own guide.
1163
+ - **`<ConnectMcpGuide />`** โ€” the guide body on its own (copyable server URL + paste-in prompt + per-client accordion), embeddable anywhere. Override the app list via `mcp.clients` and the prompt via `mcp.prompt` (`false` hides it).
1164
+ - **`fillMcpTemplate` / `mcpServerKey`** โ€” the placeholder helpers (`{{url}}` / `{{name}}` / `{{key}}`) for building custom client snippets.
1165
+
1077
1166
  ## ๐Ÿ‘ค User Management
1078
1167
 
1079
1168
  ### User Attributes
@@ -1084,8 +1173,9 @@ Manage custom user attributes (key-value pairs):
1084
1173
  import { useUserAttributes } from '@buildbase/sdk/react';
1085
1174
 
1086
1175
  function UserProfile() {
1087
- const { attributes, isLoading, updateAttribute, updateAttributes, refreshAttributes } =
1088
- useUserAttributes();
1176
+ // { attributes, loading, error, refetch, updateAttribute, updateAttributes }
1177
+ // (the older `isLoading` / `refreshAttributes` names still work but are deprecated)
1178
+ const { attributes, loading, updateAttribute, updateAttributes, refetch } = useUserAttributes();
1089
1179
 
1090
1180
  const handleUpdate = async () => {
1091
1181
  // Update single attribute
@@ -1245,19 +1335,23 @@ Plans support **pricing variants** (multi-currency). Use these utilities for dis
1245
1335
 
1246
1336
  ### Currency utilities
1247
1337
 
1248
- | Export | Purpose |
1249
- | ------------------------------------ | --------------------------------------------------------- |
1250
- | `CURRENCY_DISPLAY` | Map of currency code โ†’ symbol (e.g. `usd` โ†’ `$`) |
1251
- | `CURRENCY_FLAG` | Map of currency code โ†’ flag emoji |
1252
- | `PLAN_CURRENCY_CODES` | Allowed billing currency codes (for dropdowns/validation) |
1253
- | `PLAN_CURRENCY_OPTIONS` | Options array for plan currency selects |
1254
- | `getCurrencySymbol(currency)` | Symbol for a Stripe currency code |
1255
- | `getCurrencyFlag(currency)` | Flag emoji for a currency code |
1256
- | `formatCents(cents, currency)` | Format cents as localized price string |
1257
- | `formatOverageRate(cents, currency)` | Format overage rate for display |
1258
- | `formatOverageRateWithLabel(...)` | Overage rate with optional unit label |
1259
- | `formatQuotaIncludedOverage(...)` | "X included, then $Y / unit" style text |
1260
- | `getQuotaUnitLabelFromName(name)` | Human-readable unit label from quota name |
1338
+ | Export | Purpose |
1339
+ | -------------------------------------------------- | --------------------------------------------------------------- |
1340
+ | `CURRENCY_DISPLAY` | Map of currency code โ†’ symbol (e.g. `usd` โ†’ `$`) |
1341
+ | `CURRENCY_FLAG` | Map of currency code โ†’ flag emoji |
1342
+ | `PLAN_CURRENCY_CODES` | Allowed billing currency codes (for dropdowns/validation) |
1343
+ | `PLAN_CURRENCY_OPTIONS` | Options array for plan currency selects |
1344
+ | `getCurrencySymbol(currency)` | Symbol for a Stripe currency code |
1345
+ | `getCurrencyFlag(currency)` | Flag emoji for a currency code |
1346
+ | `formatCents(cents, currency)` | Format a minor-unit amount with the symbol table |
1347
+ | `formatMinorAmountIntl(amount, currency, locale?)` | Locale-aware `Intl` money formatting of minor units |
1348
+ | `getCurrencyDecimals(currency)` | ISO 4217 minor-unit digits (0 JPY, 2 USD, 3 KWD; CLDR fallback) |
1349
+ | `isZeroDecimalCurrency(currency)` | True when the currency has no minor unit (JPY, KRW, โ€ฆ) |
1350
+ | `minorAmountToDisplay(amount, currency)` | Minor units โ†’ display number string (no symbol) |
1351
+ | `formatOverageRate(cents, currency)` | Format overage rate for display |
1352
+ | `formatOverageRateWithLabel(...)` | Overage rate with optional unit label |
1353
+ | `formatQuotaIncludedOverage(...)` | "X included, then $Y / unit" style text |
1354
+ | `getQuotaUnitLabelFromName(name)` | Human-readable unit label from quota name |
1261
1355
 
1262
1356
  ### Pricing variant utilities
1263
1357
 
@@ -1297,7 +1391,9 @@ import {
1297
1391
  const variant = getPricingVariant(planVersion, 'usd');
1298
1392
  const cents = getBasePriceCents(planVersion, 'usd', 'monthly');
1299
1393
  if (cents != null) {
1300
- console.log(getCurrencySymbol('usd') + (cents / 100).toFixed(2));
1394
+ // Never divide by 100 yourself โ€” formatCents applies the currency's ISO 4217
1395
+ // minor-unit factor (JPY ยฅ1,000 stays whole, KWD divides by 1000, USD by 100).
1396
+ console.log(formatCents(cents, 'usd')); // "$12.99"
1301
1397
  }
1302
1398
 
1303
1399
  // Quota display with overage
@@ -2067,7 +2163,7 @@ import { eventEmitter } from '@buildbase/sdk';
2067
2163
 
2068
2164
  ## ๐Ÿ›ก๏ธ Error Handling
2069
2165
 
2070
- The SDK handles errors internally: API failures, auth errors, and component errors are logged and surfaced through hook states (e.g. `error` from `useSaaSWorkspaces`) and callbacks. **SaaSOSProvider** wraps its children in an internal **SDKErrorBoundary** to catch React render errors inside the SDK tree. For app-level errors, wrap your app (or routes) in your own error boundary (e.g. Reactโ€™s `ErrorBoundary` or your frameworkโ€™s error UI). For failed async operations, check the `error` property on hooks and show user feedback (e.g. toast or inline message). See [Error codes](docs/ERROR_CODES.md) for SDK error codes and HTTP mappings.
2166
+ The SDK handles errors internally: API failures, auth errors, and component errors are logged and surfaced through hook states (e.g. `error` from `useSaaSWorkspaces`) and callbacks. **SaaSOSProvider** wraps its children in an internal **SDKErrorBoundary** to catch React render errors inside the SDK tree. For app-level errors, wrap your app (or routes) in your own error boundary (e.g. Reactโ€™s `ErrorBoundary` or your frameworkโ€™s error UI). For failed async operations, check the `error` property on hooks and show user feedback (e.g. toast or inline message). See [Error codes](https://unpkg.com/@buildbase/sdk/docs/ERROR_CODES.md) for SDK error codes and HTTP mappings.
2071
2167
 
2072
2168
  ## โš™๏ธ Settings
2073
2169
 
@@ -2077,7 +2173,11 @@ Access OS-level settings:
2077
2173
  import { useSaaSSettings } from '@buildbase/sdk/react';
2078
2174
 
2079
2175
  function SettingsExample() {
2080
- const { settings, getSettings } = useSaaSSettings();
2176
+ // { settings, loading, error, refetch } โ€” `loading` is true until the one-time
2177
+ // fetch settles, so you can wait instead of rendering with partial defaults.
2178
+ const { settings, loading, refetch } = useSaaSSettings();
2179
+
2180
+ if (loading) return <Spinner />;
2081
2181
 
2082
2182
  return (
2083
2183
  <div>
@@ -2155,9 +2255,11 @@ Prefer these SDK hooks for state and operations instead of `useAppSelector`:
2155
2255
  | `useSaaSAuth()` | Auth state (user, session, status), signIn(returnUrl?), signOut, openWorkspaceSettings |
2156
2256
  | `useSaaSWorkspaces()` | Workspaces, currentWorkspace, loading, switching/switchingToId, CRUD and switch actions |
2157
2257
  | `useSaaSOs()` | OS config (serverUrl, version, orgId, auth, settings) when you need the full config object |
2158
- | `useSaaSSettings()` | Organization settings and getSettings (prefer this when you only need settings) |
2159
- | `useUserAttributes()` | User attributes and update/refresh |
2160
- | `useUserFeatures()` | User feature flags |
2258
+ | `useSaaSSettings()` | Organization settings โ€” `{ settings, loading, error, refetch }` (prefer this when you only need settings) |
2259
+ | `useUserAttributes()` | User attributes โ€” `{ attributes, loading, error, refetch, updateAttribute, updateAttributes }` |
2260
+ | `useUserFeatures()` | User feature flags โ€” `{ features, isFeatureEnabled, loading, error, refetch }` |
2261
+ | `useConnectedAgents()` | Authorized AI agents โ€” `{ agents, loading, error, revoking, refresh, revoke }` |
2262
+ | `useMcpConnection()` | The `mcp` connection config passed to the provider (or `null`), for a custom connect guide |
2161
2263
  | `useSubscriptionContext()` | Subscription for current workspace (response, loading, refetch); use inside SubscriptionContextProvider |
2162
2264
  | `useTrialStatus()` | Trial state: `isTrialing`, `daysRemaining`, `trialEndsAt`, `isTrialEnding` |
2163
2265
  | `usePushNotifications()` | Push notification state and actions: `isSubscribed`, `subscribe()`, `unsubscribe()` |
@@ -2177,12 +2279,12 @@ Using hooks keeps your code stable if internal state shape changes and avoids di
2177
2279
 
2178
2280
  ### Types
2179
2281
 
2180
- All TypeScript types are exported for type safety. See the [TypeScript definitions](./dist/index.d.ts) for complete type information.
2282
+ All TypeScript types are exported for type safety. See the [TypeScript definitions](https://unpkg.com/@buildbase/sdk/dist/index.d.ts) for complete type information.
2181
2283
 
2182
2284
  ### Further documentation
2183
2285
 
2184
- - [Architecture](docs/ARCHITECTURE.md) โ€“ Layers, providers, APIs (BaseApi, UserApi, WorkspaceApi, SettingsApi), state, auth flow
2185
- - [Error codes](docs/ERROR_CODES.md) โ€“ SDK error codes and HTTP status mappings
2286
+ - [Architecture](https://unpkg.com/@buildbase/sdk/docs/ARCHITECTURE.md) โ€“ Layers, providers, APIs (BaseApi, UserApi, WorkspaceApi, SettingsApi), state, auth flow
2287
+ - [Error codes](https://unpkg.com/@buildbase/sdk/docs/ERROR_CODES.md) โ€“ SDK error codes and HTTP status mappings
2186
2288
 
2187
2289
  ## โš™๏ธ Configuration Reference
2188
2290
 
@@ -2935,7 +3037,11 @@ app.post('/webhooks/buildbase', (req, res) => {
2935
3037
 
2936
3038
  ## Agent Readiness (Discovery)
2937
3039
 
2938
- Make a consuming app [agent ready](https://isitagentready.com) by serving the standard machine-readable discovery documents an AI agent looks for โ€” Agent Card, OAuth metadata (RFC 8414/9728), Agent Skills, API Catalog (RFC 9727), MCP Server Card, `robots.txt` with AI-bot rules + Content Signals, `sitemap.xml`, `security.txt` (RFC 9116), `llms.txt`, and `auth.md` โ€” with the BuildBase server as the source of truth. Framework-agnostic and zero React: every function returns a plain `DiscoveryDocument` (`{ status, contentType, body, cacheControl, vary? }`); you wire it into your own router.
3040
+ > **Full guide:** [`docs/MCP-AND-AGENT-READINESS.md`](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md) covers the whole surface โ€” the fast path, the auth model, and the scope/resource customization spectrum. This section is the overview.
3041
+
3042
+ Make a consuming app [agent ready](https://isitagentready.com) by serving the machine-readable discovery documents an AI client looks for โ€” Agent Card, A2A card, OAuth metadata (RFC 8414/9728), Agent Skills, API Catalog (RFC 9727), MCP Server Card (SEP-1649 v1.0) + discovery manifest (SEP-1960), `robots.txt` with AI-bot rules + Content Signals, `sitemap.xml`, `security.txt`, `llms.txt`/`llms-full.txt`, and `auth.md`. Framework-agnostic and zero React: every function returns a plain `DiscoveryDocument` (`{ status, contentType, body, cacheControl, vary? }`).
3043
+
3044
+ The fast path is [`createAgentStack`](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md#fast-path--createagentstack) โ€” one config derives the MCP handler **and** the whole discovery surface. To wire the discovery layer on its own, use `resolveAgentPath`:
2939
3045
 
2940
3046
  ```ts
2941
3047
  // lib/agent-ready.ts
@@ -2944,14 +3050,18 @@ import { resolveAgentPath, type AgentReadyConfig } from '@buildbase/sdk';
2944
3050
  export const agentConfig: AgentReadyConfig = {
2945
3051
  serverUrl: process.env.BUILDBASE_URL!,
2946
3052
  orgId: process.env.BUILDBASE_ORG_ID!,
2947
- siteUrl: 'https://imejis.io',
2948
- site: { name: 'Imejis', description: 'Generate images from templates via API.' },
3053
+ siteUrl: 'https://example.com',
3054
+ site: { name: 'Acme', description: 'Generate images from templates via API.' },
2949
3055
  // Discovery content is YOURS โ€” defined here in code, not in the platform:
2950
- llmsTxt: '# Imejis\n\n> Generate images from templates via API.',
3056
+ scopes: [
3057
+ { name: 'designs:read', description: 'View designs' },
3058
+ { name: 'render:execute', description: 'Render images' },
3059
+ ],
3060
+ llmsTxt: '# Acme\n\n> Generate images from templates via API.',
2951
3061
  robots: { contentSignals: { search: true, aiInput: true, aiTrain: false } },
2952
3062
  sitemap: { urls: ['/', '/pricing'] }, // omit if you already generate sitemaps
2953
- protectedResources: [{ scopes: ['read:profile', 'write:posts'] }], // RFC 9728
2954
- // skills, security, apiCatalog, mcpServerCard, authMd, cacheTtlSeconds โ€” all optional
3063
+ protectedResources: [{ resource: 'https://example.com/mcp' }], // scopes inherited from catalog
3064
+ // skills, security, apiCatalog, mcpServerCard, a2aCard, extraPaths โ€” all optional
2955
3065
  };
2956
3066
 
2957
3067
  export async function serveAgentPath(req: Request): Promise<Response> {
@@ -3031,21 +3141,61 @@ Clean split, no duplication: **your app owns discovery content, the platform own
3031
3141
  | llms.txt | `buildLlmsTxt` |
3032
3142
  | MCP Server Card + live MCP server | `buildMcpServerCard` + [`@buildbase/sdk/mcp`](#mcp-server-buildbasesdkmcp) |
3033
3143
  | Agent Skills / API Catalog | `buildAgentSkillsIndex` / `buildApiCatalog` |
3144
+ | A2A Agent Card | `buildA2AAgentCard` (served by default from `site` + `skills`) |
3034
3145
  | OAuth discovery (RFC 8414) + protected resource (RFC 9728) | `resolveAgentPath` (platform-backed) |
3035
- | DNS-AID | out of SDK scope โ€” add the DNS record at your registrar |
3036
- | Web Bot Auth, commerce (x402/ACP/UCP) | not yet โ€” planned |
3146
+ | Web Bot Auth | `buildWebBotAuthDirectory` (opt-in โ€” publish your JWKS) |
3147
+ | DNS-AID | `buildDnsAidRecords` (returns records โ€” publish at your DNS provider) |
3148
+ | Commerce (x402/ACP/UCP/MPP), openapi.json | `config.extraPaths` (serve any literal document by path) |
3037
3149
 
3038
- **Functions:** `resolveAgentPath`, `resolveWellKnown`, `fetchAgentReadiness`, `clearAgentReadinessCache`, `buildAgentCard`, `buildProtectedResourceMetadata`, `buildAgentSkillsIndex`, `buildSkillMd`, `buildSecurityTxt`, `buildLlmsTxt`, `buildRobotsTxt`, `buildSitemap`, `buildApiCatalog`, `buildMcpServerCard`, `buildAuthMd`, `buildDiscoveryLinkHeader`, `wantsMarkdown`, `negotiateMarkdown`, `provideWebMcpTools`, `sha256Digest`. **Constants:** `AI_BOT_USER_AGENTS`. **Types:** `AgentReadyConfig`, `AgentReadinessBundle`, `AgentSkill`, `ApiCatalogApi`, `McpServerCard`, `RobotsConfig`, `RobotsPolicy`, `ContentSignals`, `SitemapUrl`, `WebMcpTool`, `DiscoveryDocument`.
3150
+ **Functions:** `resolveAgentPath`, `resolveWellKnown`, `fetchAgentReadiness`, `clearAgentReadinessCache`, `buildAgentCard`, `buildA2AAgentCard`, `buildProtectedResourceMetadata`, `buildAgentSkillsIndex`, `buildSkillMd`, `buildSecurityTxt`, `buildLlmsTxt`, `buildLlmsFullTxt`, `buildRobotsTxt`, `buildSitemap`, `buildApiCatalog`, `buildMcpServerCard`, `buildMcpDiscoveryManifest`, `buildAuthMd`, `buildWebBotAuthDirectory`, `buildDnsAidRecords`, `buildDiscoveryLinkHeader`, `wantsMarkdown`, `negotiateMarkdown`, `provideWebMcpTools`, `sha256Digest`. **Constants:** `AI_BOT_USER_AGENTS`. **Types:** `AgentReadyConfig`, `AgentReadinessBundle`, `AgentSkill`, `AppScope`, `ApiCatalogApi`, `A2ACardConfig`, `A2ACardSkill`, `DnsAidRecord`, `McpServerCard`, `RobotsConfig`, `RobotsPolicy`, `ContentSignals`, `SitemapUrl`, `WebMcpTool`, `DiscoveryDocument`.
3039
3151
 
3040
3152
  ## MCP Server (`@buildbase/sdk/mcp`)
3041
3153
 
3042
- Turn your app into a **live MCP server** so AI agents can operate it: the built-in tools expose your BuildBase state (workspaces, subscription, quotas, credits, feature flags, permissions) and you add your own product tools with zod schemas. Stateless Streamable HTTP โ€” pure functions plus a Web-standard `Request`/`Response` adapter, so it runs on Node 18+, edge, Deno, and Bun. Server-only, zero React; split from the core entry because it uses `zod` at runtime.
3154
+ > **Full guide:** [`docs/MCP-AND-AGENT-READINESS.md`](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md).
3155
+
3156
+ Turn your app into a **live MCP server** so AI agents can operate it: the built-in tools expose your BuildBase state (workspaces, subscription, quotas, credits, feature flags, permissions) and you add your own product tools with zod schemas โ€” plus **resources** (context a host loads without tool calls) and **prompts** (user-facing workflow templates). Stateless Streamable HTTP (MCP 2025-11-25, negotiating down to 2024-11-05) โ€” pure functions plus a Web-standard `Request`/`Response` adapter, so it runs on Node 18+, edge, Deno, and Bun. Server-only, zero React; split from the core entry because it uses `zod` at runtime.
3157
+
3158
+ The fast path bundles the server + the whole discovery surface from one config:
3159
+
3160
+ ```ts
3161
+ // lib/agent.ts
3162
+ import { createAgentStack, defineMcpTool } from '@buildbase/sdk/mcp';
3163
+ import { z } from 'zod';
3164
+
3165
+ export const agent = createAgentStack({
3166
+ serverUrl: process.env.NEXT_PUBLIC_BUILDBASE_SERVER_URL!,
3167
+ orgId: process.env.NEXT_PUBLIC_BUILDBASE_ORG_ID!,
3168
+ siteUrl: 'https://example.com',
3169
+ site: { name: 'Acme', description: 'Generate images from templates via API.' },
3170
+ secret: process.env.SYSTEM_SECRET!, // derives buildbaseAuth (verify + aud + sid decrypt)
3171
+ scopes: [{ name: 'render:execute', description: 'Render images' }],
3172
+ mcp: {
3173
+ builtinTools: 'readonly',
3174
+ tools: [
3175
+ defineMcpTool({
3176
+ name: 'generate_image',
3177
+ description: 'Render an image from a template',
3178
+ inputSchema: z.object({ templateId: z.string(), data: z.record(z.string(), z.any()) }),
3179
+ requiredScopes: ['render:execute'],
3180
+ execute: async (input, { bb, workspaceId }) => {
3181
+ await bb.usage.record(workspaceId!, { quotaSlug: 'images', quantity: 1 });
3182
+ return renderTemplate(input.templateId, input.data);
3183
+ },
3184
+ }),
3185
+ ],
3186
+ },
3187
+ });
3188
+
3189
+ // app/api/mcp/route.ts
3190
+ export const { GET, POST, DELETE, OPTIONS } = agent.routes;
3191
+ ```
3192
+
3193
+ Prefer the primitives (own token format, unified web+agent auth)? Wire `createMcpHandler` + `buildbaseAuth` directly โ€” `buildbaseAuth` does the full verify (HS256, RFC 8707 audience binding, `sid` decrypt) so you never hand-roll it:
3043
3194
 
3044
3195
  ```ts
3045
3196
  // lib/mcp.ts
3046
3197
  import BuildBase from '@buildbase/sdk';
3047
- import { createMcpHandler, defineMcpTool, verifyClientJwt } from '@buildbase/sdk/mcp';
3048
- import { z } from 'zod';
3198
+ import { createMcpHandler, defineMcpTool, buildbaseAuth } from '@buildbase/sdk/mcp';
3049
3199
 
3050
3200
  const buildbase = BuildBase({
3051
3201
  serverUrl: process.env.BUILDBASE_URL!,
@@ -3054,56 +3204,35 @@ const buildbase = BuildBase({
3054
3204
 
3055
3205
  export const mcp = createMcpHandler({
3056
3206
  buildbase,
3057
- serverInfo: { name: 'imejis', version: '1.0.0' },
3058
- auth: {
3059
- // Verify the Bearer token your app minted in the OAuth2 app-bridge flow
3060
- // and map it to the BuildBase session the tools run under.
3061
- verify: token => {
3062
- const c = verifyClientJwt(token, process.env.BUILDBASE_CLIENT_SECRET!);
3063
- return { sessionId: String(c.sid), userId: String(c.sub), scopes: c.scope as string[] };
3064
- },
3065
- // Unauthenticated requests get a 401 whose WWW-Authenticate header points
3066
- // here, so agents bootstrap the whole OAuth discovery flow (RFC 9728).
3067
- resourceMetadataUrl: 'https://imejis.io/.well-known/oauth-protected-resource',
3068
- },
3069
- builtinTools: 'readonly', // default; 'all' opts into the mutating tools
3207
+ serverInfo: { name: 'acme', version: '1.0.0' },
3208
+ auth: buildbaseAuth({
3209
+ secret: process.env.SYSTEM_SECRET!,
3210
+ resource: ['https://example.com/mcp', 'https://example.com/api/mcp'],
3211
+ requireAudience: true,
3212
+ }),
3213
+ builtinTools: 'readonly',
3070
3214
  tools: [
3071
- defineMcpTool({
3072
- name: 'generate_image',
3073
- description: 'Render an image from a template',
3074
- inputSchema: z.object({ templateId: z.string(), data: z.record(z.string(), z.any()) }),
3075
- annotations: { readOnlyHint: false },
3076
- execute: async (input, { bb, workspaceId }) => {
3077
- await bb.usage.record(workspaceId!, { quotaSlug: 'images', quantity: 1 });
3078
- return renderTemplate(input.templateId, input.data);
3079
- },
3080
- }),
3215
+ /* defineMcpTool(...) */
3081
3216
  ],
3082
3217
  });
3083
3218
  ```
3084
3219
 
3085
3220
  ```ts
3086
- // app/api/mcp/route.ts (Next.js App Router)
3087
- import { mcp } from '@/lib/mcp';
3088
- export const POST = (req: Request) => mcp.fetch(req);
3089
- export const GET = (req: Request) => mcp.fetch(req); // 405 per spec (no SSE)
3090
- export const DELETE = (req: Request) => mcp.fetch(req); // 405 (stateless)
3091
- ```
3092
-
3093
- ```ts
3094
- // Express โ€” the pure form
3221
+ // Express / Fastify / Node โ€” the pure form
3095
3222
  app.post('/mcp', async (req, res) => {
3096
3223
  const r = await mcp.handle({ method: req.method, headers: req.headers, body: req.body });
3097
3224
  res.status(r.status).set(r.headers).send(r.body);
3098
3225
  });
3099
3226
  ```
3100
3227
 
3101
- Advertise it via the server card so agents find the endpoint:
3228
+ > **Copy-paste recipes for every framework** โ€” Next.js (App + Pages Router), Express, Fastify, Hono, Bun, Deno, Cloudflare Workers, and React/SPA (WebMCP) โ€” plus the per-framework mint route and a production checklist: [`docs/MCP-AND-AGENT-READINESS.md`](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md#framework-recipes). Two adapters cover them all: `mcp.fetch(Request)` (web standard โ€” App Router, Hono, Bun, Deno, edge) and `mcp.handle({method,headers,body})` (pure โ€” Express, Fastify, Pages Router).
3229
+
3230
+ Advertise it via the server card so agents find the endpoint (the stack sets this automatically):
3102
3231
 
3103
3232
  ```ts
3104
3233
  export const agentConfig: AgentReadyConfig = {
3105
3234
  // ...
3106
- mcpServerCard: mcp.serverCard({ endpoint: 'https://imejis.io/api/mcp' }),
3235
+ mcpServerCard: mcp.serverCard({ endpoint: 'https://example.com/api/mcp' }),
3107
3236
  };
3108
3237
  ```
3109
3238
 
@@ -3132,6 +3261,62 @@ The agent acts as an authenticated app user โ€” it knows your app, not BuildBase
3132
3261
 
3133
3262
  Want per-scope gating on top? Set `requiredScopes` on your own custom tools and return the granted `scopes` from `auth.verify` โ€” the handler hides a tool from `tools/list` (and refuses the call) when its `requiredScopes` aren't all granted. A token that carries **no** scopes sees only tools that require none (the built-ins), so a token minted without a `scope` claim can never unlock a scoped tool. Opt-in, using **your** scope names โ€” the SDK never imposes its own.
3134
3263
 
3264
+ ### Rich tool results (images, links, mixed content)
3265
+
3266
+ Return any JSON-serializable value and the handler wraps it (string โ†’ text block; object โ†’ JSON text + `structuredContent`). For full control โ€” images, audio, resource links, mixed blocks, or the `isError` flag โ€” return a wire-shaped `McpToolResult` built with the exported helpers:
3267
+
3268
+ ```ts
3269
+ import { mcpImage, mcpResourceLink, mcpText } from '@buildbase/sdk/mcp';
3270
+
3271
+ execute: async (input, ctx) => ({
3272
+ content: [
3273
+ mcpText('Revenue chart for Q2:'),
3274
+ mcpImage(chartPngBase64, 'image/png'),
3275
+ mcpResourceLink('https://app.example.com/reports/q2.pdf', 'q2-report'),
3276
+ ],
3277
+ structuredContent: { totalCents: 1_299_00, currency: 'usd' },
3278
+ });
3279
+ ```
3280
+
3281
+ ### Resources & prompts
3282
+
3283
+ Both are **opt-in**, and `initialize` capabilities only advertise what you actually configured โ€” existing servers are byte-identical until you opt in.
3284
+
3285
+ ```ts
3286
+ createMcpHandler({
3287
+ buildbase,
3288
+ // Lean built-in context catalog: buildbase://profile, buildbase://workspaces,
3289
+ // buildbase://workspace/{workspaceId}. Richer data stays tools-only.
3290
+ builtinResources: true,
3291
+ resources: [
3292
+ defineMcpResource({
3293
+ uri: 'app://docs/getting-started',
3294
+ name: 'getting-started',
3295
+ mimeType: 'text/markdown',
3296
+ read: () => gettingStartedMarkdown, // string | object (JSON) | { text } | { blob }
3297
+ }),
3298
+ ],
3299
+ resourceTemplates: [
3300
+ defineMcpResourceTemplate({
3301
+ uriTemplate: 'app://orders/{orderId}',
3302
+ name: 'order',
3303
+ read: (params, _uri, ctx) => ctx.custom.db.order.find(params.orderId),
3304
+ }),
3305
+ ],
3306
+ prompts: [
3307
+ defineMcpPrompt({
3308
+ name: 'analyze_usage',
3309
+ description: 'Review quota usage and suggest actions',
3310
+ arguments: [{ name: 'workspaceId', required: true }],
3311
+ get: async (args, ctx) =>
3312
+ `Review this workspace's quota usage:\n${JSON.stringify(await ctx.bb.usage.getAll(args.workspaceId))}`,
3313
+ }),
3314
+ ],
3315
+ });
3316
+ ```
3317
+
3318
+ `requiredScopes` gates resources and prompts exactly like tools. Deliberately out of scope (the stateless transport has no push channel): resource subscriptions, `listChanged`, sampling, elicitation.
3319
+
3135
3320
  ### Production hardening
3136
3321
 
3137
3322
  The handler ships with safe defaults; these are the knobs to review before going live:
@@ -3148,7 +3333,7 @@ export const mcp = createMcpHandler({
3148
3333
  buildbase,
3149
3334
  auth: { verify, resourceMetadataUrl },
3150
3335
  builtinTools: { include: ['get_quota_usage', 'record_usage'] },
3151
- allowedOrigins: ['https://app.imejis.io'],
3336
+ allowedOrigins: ['https://app.example.com'],
3152
3337
  maxRequestBytes: 512 * 1024,
3153
3338
  rateLimit: async auth => ({ ok: await limiter.allow(auth?.userId), retryAfter: 30 }),
3154
3339
  onError: (err, ctx) => logger.error({ err, ...ctx }, 'mcp error'),
@@ -3187,21 +3372,25 @@ The SDK accelerates; it never gates. Everything BuildBase-specific is optional:
3187
3372
 
3188
3373
  ### Auth in one line of plumbing
3189
3374
 
3190
- The OAuth2 app-bridge flow already mints your app's Bearer tokens (see [OAuth2 App Bridge](#oauth2-app-bridge)); `signClientJwt(payload, secret)` is the symmetric counterpart of `verifyClientJwt` for exactly that. The mint claims include `sessionId` โ€” a per-user BuildBase session bound to the grant (fresh on every mint, including refresh). Embed it **encrypted** (JWTs are signed, not encrypted โ€” the agent can read its own token) and keep it out of any storage, so it simply expires with the token; your MCP `auth.verify` decrypts it back into `McpAuthInfo.sessionId`:
3375
+ The OAuth2 app-bridge flow mints your app's Bearer tokens (see [OAuth2 App Bridge](#oauth2-app-bridge)). Use the presets and neither the mint nor the verify is hand-rolled โ€” the per-user BuildBase session rides as an **encrypted `sid`** claim (JWTs are signed, not encrypted), never stored, expiring with the token:
3191
3376
 
3192
3377
  ```ts
3193
- mintToken: (user) => ({
3194
- token: signClientJwt(
3195
- { sub: user.id, scope: user.scope, aud: user.resource, sid: encrypt(user.sessionId) },
3196
- process.env.BUILDBASE_CLIENT_SECRET!
3197
- ),
3198
- expiresIn: 3600,
3199
- }),
3378
+ // mint (applicationTokenUrl) โ€” HS256 with your secret, aud from the grant, encrypted sid
3379
+ import { mintAgentToken } from '@buildbase/sdk';
3380
+ mintToken: (claims) => mintAgentToken({ claims, secret: process.env.SYSTEM_SECRET! }),
3381
+
3382
+ // verify (MCP server) โ€” HS256 + RFC 8707 audience + sid decrypt โ†’ McpAuthInfo
3383
+ import { buildbaseAuth } from '@buildbase/sdk/mcp';
3384
+ auth: buildbaseAuth({ secret: process.env.SYSTEM_SECRET!, resource: 'https://example.com/mcp' }),
3200
3385
  ```
3201
3386
 
3202
- Set `auth: false` to disable auth entirely (local development only). Test with the MCP Inspector: `npx @modelcontextprotocol/inspector --cli http://localhost:3000/api/mcp --transport http --header "Authorization: Bearer <token>" --method tools/list`.
3387
+ Bringing your own token format? `auth.verify(token, req) โ†’ McpAuthInfo` accepts any Bearer token; set `auth.resourceMetadataUrl` so 401s carry the RFC 9728 challenge. Set `auth: false` to disable auth (local dev only). Debug audience mismatches with `MCP_AUTH_DEBUG=1`. Test with the MCP Inspector: `npx @modelcontextprotocol/inspector --cli http://localhost:3000/api/mcp --transport http --header "Authorization: Bearer <token>" --method tools/list`.
3388
+
3389
+ **Exports:** `createAgentStack`, `createMcpHandler`, `defineMcpTool`, `builtinMcpTools`, `selectBuiltinTools`, `buildbaseAuth`, `mintAgentToken`, `createSessionRefCrypto`, plus re-exported auth helpers (`signClientJwt`, `verifyClientJwt`, `extractBearerToken`, `bearerChallenge`, `AppBridgeError`). **Types:** `AgentStack`, `AgentStackConfig`, `CreateMcpHandlerConfig`, `McpHandler`, `McpToolDefinition`, `McpToolContext`, `McpAuthInfo`, `McpHttpRequest`, `McpHttpResponse`, `McpToolAnnotations`, `McpBuildBaseClient`, `BuiltinMcpToolName`, `BuildBaseAuthOptions`, `MintAgentTokenOptions`, `SessionRefCrypto`, `McpServerCard`, `ScopedActions`.
3390
+
3391
+ ### Scopes & resources โ€” restrict or open up
3203
3392
 
3204
- **Exports:** `createMcpHandler`, `defineMcpTool`, `builtinMcpTools`, `selectBuiltinTools`, plus re-exported auth helpers (`signClientJwt`, `verifyClientJwt`, `extractBearerToken`, `bearerChallenge`, `AppBridgeError`). **Types:** `CreateMcpHandlerConfig`, `McpHandler`, `McpToolDefinition`, `McpToolContext`, `McpAuthInfo`, `McpHttpRequest`, `McpHttpResponse`, `McpToolAnnotations`, `McpBuildBaseClient`, `BuiltinMcpToolName`, `McpServerCard`, `ScopedActions`.
3393
+ Scopes and resources are **app-owned** โ€” the shared BuildBase authorization server stays scope/resource-agnostic. Scopes have three levers: **declare** a catalog (`scopes: [{ name, description }]` โ†’ `scopes_supported` in your own RFC 9728 protected-resource metadata), **gate per tool** (`requiredScopes` on a custom tool โ†’ hidden/refused unless the token carries them), and the **floor** (every tool runs under the user's BuildBase session, so the platform enforces the user's real permissions โ€” an agent never exceeds the user). Resources have two: **declare** `protectedResources` (RFC 9728) and **bind** the token audience via `buildbaseAuth({ resource, requireAudience })` (RFC 8707) โ€” the audience check at your resource is the whole gate. Built-ins are restricted with `builtinTools`, not scopes. Public clients (Claude Desktop, Cursor, Inspector) self-register with PKCE and no secret. Full model: [the guide](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md#scopes--resources-restrict-or-open-up).
3205
3394
 
3206
3395
  ## OAuth2 App Bridge
3207
3396
 
@@ -3212,6 +3401,8 @@ BuildBase runs the full OAuth2 authorization flow (login, consent, code, PKCE, r
3212
3401
 
3213
3402
  Both requests carry `Authorization: Bearer <JWT>`, an HS256 JWT signed with your client secret. This toolkit verifies those requests (timing-safe, no `alg` confusion) and shapes the exact response body the platform expects, so you write only the part that's yours: minting/invalidating a token in your own format.
3214
3403
 
3404
+ > For the common case, `mintToken: (claims) => mintAgentToken({ claims, secret })` is the preset โ€” it signs HS256 with your secret, binds `aud` to the granted RFC 8707 resource, and embeds the encrypted `sid`. The examples below show the hand-rolled equivalent, for apps that mint their own token format (e.g. one shared with their web sessions). See [the guide](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md#auth-minting--verifying-the-token).
3405
+
3215
3406
  ```ts
3216
3407
  // applicationTokenUrl handler (Next.js Pages Router)
3217
3408
  import { handleAppTokenRequest } from '@buildbase/sdk';
@@ -3251,7 +3442,7 @@ When an agent calls your protected API without a valid token, reply with an RFC
3251
3442
  import { bearerChallenge } from '@buildbase/sdk';
3252
3443
 
3253
3444
  const c = bearerChallenge({
3254
- resourceMetadataUrl: 'https://imejis.io/.well-known/oauth-protected-resource',
3445
+ resourceMetadataUrl: 'https://example.com/.well-known/oauth-protected-resource',
3255
3446
  error: 'invalid_token',
3256
3447
  });
3257
3448
  res.writeHead(c.status, c.headers).end(c.body);
@@ -3295,7 +3486,9 @@ return res.json({ id: claims.id, email: claims.email /* โ€ฆ */ });
3295
3486
 
3296
3487
  The one-call handlers cover the common path; the underlying pieces are exported for custom flows: `verifyAppTokenRequest` / `verifyAppRevokeRequest` (verify โ†’ claims), `verifyClientJwt`, `extractBearerToken`, and the response builders `appTokenSuccess` / `appTokenFailure`. Verification throws `AppBridgeError` (with a machine-readable `code` like `invalid_signature`, `token_expired`, `invalid_algorithm`). HMAC verification uses the SDK's dependency-free pure-JS HMAC-SHA256, so it behaves identically under ESM, CJS, a bundler, or bare Node.
3297
3488
 
3298
- **Types:** `AppTokenRequestClaims`, `AppRevokeRequestClaims`, `AppTokenResult`, `AppTokenResponseBody`, `HandlerResult`.
3489
+ **Presets** (also on the core entry): `mintAgentToken` (the whole mint โ€” HS256 + `aud` + encrypted `sid`), `buildbaseAuth` (the whole verify), `createSessionRefCrypto` (the `sid` AES-256-GCM crypto). The platform relays the minted token but never sees your secret โ€” it can neither forge nor decode your tokens.
3490
+
3491
+ **Exports:** `handleAppTokenRequest`, `handleAppRevokeRequest`, `verifyAppTokenRequest`, `verifyAppRevokeRequest`, `verifyClientJwt`, `signClientJwt`, `extractBearerToken`, `bearerChallenge`, `appTokenSuccess`, `appTokenFailure`, `mintAgentToken`, `buildbaseAuth`, `createSessionRefCrypto`, `AppBridgeError`. **Types:** `AppTokenRequestClaims`, `AppRevokeRequestClaims`, `AppTokenResult`, `AppTokenResponseBody`, `HandlerResult`, `VerifyClientJwtOptions`, `BuildBaseAuthOptions`, `MintAgentTokenOptions`, `SessionRefCrypto`.
3299
3492
 
3300
3493
  ## ๐Ÿค Contributing
3301
3494