@solvapay/mcp-core 0.1.0

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.
@@ -0,0 +1,1167 @@
1
+ import { ZodTypeAny } from 'zod';
2
+ import { PurchaseCheckResult, PaymentMethodInfo, CustomerBalanceResult, GetUsageResult, SdkMerchantResponse, SdkProductResponse, components, PaywallStructuredContent, SolvaPay, PaywallError } from '@solvapay/server';
3
+
4
+ /**
5
+ * Canonical MCP tool names for the SolvaPay transport + bootstrap tools.
6
+ *
7
+ * Single source of truth for `@solvapay/mcp-core`, `@solvapay/mcp`,
8
+ * `@solvapay/react/mcp/adapter`, and any third-party adapter (fastmcp,
9
+ * raw JSON-RPC, etc.). Adding a new tool means editing exactly one file.
10
+ */
11
+ declare const MCP_TOOL_NAMES: {
12
+ readonly createPayment: "create_payment_intent";
13
+ readonly processPayment: "process_payment";
14
+ readonly createTopupPayment: "create_topup_payment_intent";
15
+ readonly cancelRenewal: "cancel_renewal";
16
+ readonly reactivateRenewal: "reactivate_renewal";
17
+ readonly activatePlan: "activate_plan";
18
+ readonly createCheckoutSession: "create_checkout_session";
19
+ readonly createCustomerSession: "create_customer_session";
20
+ readonly upgrade: "upgrade";
21
+ readonly manageAccount: "manage_account";
22
+ readonly topup: "topup";
23
+ };
24
+ type McpToolName = (typeof MCP_TOOL_NAMES)[keyof typeof MCP_TOOL_NAMES];
25
+
26
+ /**
27
+ * Framework-neutral MCP contracts shared across every SolvaPay MCP adapter.
28
+ *
29
+ * These types are intentionally free of `@modelcontextprotocol/*` imports
30
+ * so adapters for `fastmcp`, or raw JSON-RPC servers can consume them
31
+ * without pulling in the official SDK.
32
+ *
33
+ * The `ZodTypeAny`-shaped `inputSchema` keeps zod as an optional peer.
34
+ * Adapters that don't use zod can still pass equivalent shapes.
35
+ */
36
+
37
+ /**
38
+ * Merchant identity surfaced on every `BootstrapPayload`. Structural
39
+ * alias for the server's `SdkMerchantResponse` so the React shell can
40
+ * hydrate `<MandateText>` and the rest of the trust-signal surface
41
+ * without an extra fetch.
42
+ */
43
+ type BootstrapMerchant = SdkMerchantResponse;
44
+ /**
45
+ * Product projection surfaced on every `BootstrapPayload`. Structural
46
+ * alias for the server's `SdkProductResponse`.
47
+ */
48
+ type BootstrapProduct = SdkProductResponse;
49
+ /**
50
+ * Plan projection surfaced on every `BootstrapPayload`. Structural
51
+ * alias for the generated `Plan` schema so the embedded checkout can
52
+ * mount its plan picker from the snapshot.
53
+ */
54
+ type BootstrapPlan = components['schemas']['Plan'];
55
+ /**
56
+ * Per-customer snapshot surfaced on every `BootstrapPayload`. Null when
57
+ * unauthenticated; individual fields are null when the corresponding
58
+ * sub-read errored or doesn't apply.
59
+ */
60
+ interface BootstrapCustomer {
61
+ ref: string;
62
+ purchase: PurchaseCheckResult | null;
63
+ paymentMethod: PaymentMethodInfo | null;
64
+ balance: CustomerBalanceResult | null;
65
+ usage: GetUsageResult | null;
66
+ }
67
+ /**
68
+ * MCP tool call result — a structural subset of the official SDK's
69
+ * `CallToolResult` that every framework produces. Kept local to avoid
70
+ * coupling to `@modelcontextprotocol/sdk/types.js` type churn.
71
+ */
72
+ /**
73
+ * Routing hint surfaced on individual content blocks. Mirrors the MCP
74
+ * `Annotations.audience` field — hosts that honour it (ChatGPT Apps,
75
+ * Claude Desktop) hide `['assistant']`-tagged blocks from the user pane
76
+ * while still feeding them to the model. Hosts that don't honour it
77
+ * (e.g. MCP Inspector) render every block verbatim.
78
+ */
79
+ interface SolvaPayContentAnnotations {
80
+ audience?: Array<'user' | 'assistant'>;
81
+ priority?: number;
82
+ }
83
+ interface SolvaPayCallToolResult {
84
+ content: Array<{
85
+ type: 'text';
86
+ text: string;
87
+ annotations?: SolvaPayContentAnnotations;
88
+ } | {
89
+ type: 'image';
90
+ data: string;
91
+ mimeType: string;
92
+ annotations?: SolvaPayContentAnnotations;
93
+ } | {
94
+ type: 'resource';
95
+ resource: Record<string, unknown>;
96
+ annotations?: SolvaPayContentAnnotations;
97
+ }>;
98
+ structuredContent?: Record<string, unknown>;
99
+ isError?: boolean;
100
+ _meta?: Record<string, unknown>;
101
+ }
102
+ /**
103
+ * Extra context passed into MCP tool handlers. Mirrors the `extra`
104
+ * parameter shape used by the official SDK's `registerTool` callback.
105
+ */
106
+ interface McpToolExtra {
107
+ authInfo?: {
108
+ token?: string;
109
+ clientId?: string;
110
+ scopes?: string[];
111
+ expiresAt?: number;
112
+ extra?: Record<string, unknown>;
113
+ };
114
+ [key: string]: unknown;
115
+ }
116
+ /**
117
+ * Options for the MCP adapter's `formatResponse` / `getCustomerRef`
118
+ * hooks. Used by `@solvapay/server`'s `McpAdapter` (backing
119
+ * `payable().mcp()`) and any descriptor-level customisation.
120
+ */
121
+ interface McpAdapterOptions {
122
+ getCustomerRef?: (args: any, extra?: McpToolExtra) => string | Promise<string>;
123
+ transformResponse?: (result: any) => any;
124
+ }
125
+ /**
126
+ * Tool result shape returned by `payable().mcp(...)` when the paywall
127
+ * fires. Structurally compatible with `SolvaPayCallToolResult` so every
128
+ * framework adapter can return it directly.
129
+ */
130
+ interface PaywallToolResult {
131
+ content?: Array<{
132
+ type: 'text' | 'image' | 'resource';
133
+ text?: string;
134
+ data?: string;
135
+ mimeType?: string;
136
+ }>;
137
+ isError?: boolean;
138
+ structuredContent?: Record<string, unknown>;
139
+ _meta?: Record<string, unknown>;
140
+ }
141
+ /**
142
+ * Which view a SolvaPay MCP server knows how to bootstrap.
143
+ *
144
+ * Four kinds map to an intent `open_*`-style tool: `checkout`,
145
+ * `account`, `topup`, and `nudge` (opened implicitly when a successful
146
+ * paywalled tool response carries `options.nudge`). `paywall` has no
147
+ * dedicated tool — the gate response inlines the bootstrap payload on
148
+ * its `structuredContent`, and the React shell takes over the surface
149
+ * when it sees `view: 'paywall'`.
150
+ *
151
+ * The legacy `'about'`, `'activate'`, and `'usage'` surfaces were
152
+ * dropped with the three-mode refactor — About is now served by tool
153
+ * descriptions + docs resources, Activate merged into checkout's
154
+ * `PlanActivationDispatcher`, and Usage folds inline into the account
155
+ * view.
156
+ */
157
+ type SolvaPayMcpViewKind = 'checkout' | 'account' | 'topup' | 'paywall' | 'nudge';
158
+ declare const SOLVAPAY_MCP_VIEW_KINDS: readonly ["checkout", "account", "topup", "paywall", "nudge"];
159
+ /**
160
+ * Minimal `kind`-tagged paywall content passed through `BootstrapPayload`
161
+ * when the host opens the paywall view. The full
162
+ * `PaywallStructuredContent` type lives in `@solvapay/server` (it's also
163
+ * consumed by the non-MCP react paywall primitives); this shape is a
164
+ * structural superset that adapters can forward without importing it.
165
+ */
166
+ interface SolvaPayMcpPaywallContent {
167
+ kind: 'payment_required' | 'activation_required';
168
+ [key: string]: unknown;
169
+ }
170
+ /**
171
+ * Payload returned by every `open_*` bootstrap tool and consumed by the
172
+ * React MCP App shell to render the right view. Single source of truth —
173
+ * the react bootstrap (`@solvapay/react/mcp`) imports this type so field
174
+ * renames can't silently drift between server and client.
175
+ *
176
+ * Product-scoped fields (`merchant`, `product`, `plans`) are always
177
+ * present so the shell can render without firing follow-up read tools.
178
+ * `customer` is `null` when the call is unauthenticated; each nested
179
+ * field is `null` when the corresponding sub-read errored or doesn't
180
+ * apply (e.g. `paymentMethod: null` when no card is on file).
181
+ */
182
+ interface BootstrapPayload {
183
+ view: SolvaPayMcpViewKind;
184
+ productRef: string;
185
+ stripePublishableKey: string | null;
186
+ returnUrl: string;
187
+ /** Only set for the `open_paywall` branch. */
188
+ paywall?: SolvaPayMcpPaywallContent;
189
+ /**
190
+ * Upsell strip spec attached when `view: 'nudge'`. Rendered above
191
+ * the merchant tool result by `McpNudgeView`.
192
+ */
193
+ nudge?: NudgeSpec;
194
+ /**
195
+ * Merchant tool result data embedded alongside a nudge so the shell
196
+ * can surface it without a follow-up tool call. Only set when
197
+ * `view: 'nudge'`.
198
+ */
199
+ data?: unknown;
200
+ merchant: BootstrapMerchant;
201
+ product: BootstrapProduct;
202
+ plans: BootstrapPlan[];
203
+ customer: BootstrapCustomer | null;
204
+ }
205
+ /**
206
+ * Content Security Policy allow-list inputs merged with the Stripe
207
+ * baseline by `SOLVAPAY_DEFAULT_CSP` / `mergeCsp`.
208
+ */
209
+ interface SolvaPayMcpCsp {
210
+ resourceDomains?: string[];
211
+ connectDomains?: string[];
212
+ frameDomains?: string[];
213
+ }
214
+ /**
215
+ * MCP tool annotations — hints to hosts about the tool's behaviour.
216
+ * Structural subset of the official spec's `ToolAnnotations` so hosts
217
+ * can surface confirmation prompts (destructive actions) and filter
218
+ * tools appropriately (read-only vs. mutating).
219
+ *
220
+ * See https://modelcontextprotocol.io/specification for the full
221
+ * semantics. Hosts on pre-annotations SDK versions ignore the field
222
+ * without error — the wire shape is additive.
223
+ */
224
+ interface SolvaPayToolAnnotations {
225
+ /** Human-readable title override (prefer the descriptor's `title`). */
226
+ title?: string;
227
+ /** Tool only retrieves data — no side effects on SolvaPay state. */
228
+ readOnlyHint?: boolean;
229
+ /** Tool has destructive / non-reversible side effects (charges, cancellations). */
230
+ destructiveHint?: boolean;
231
+ /** Repeated calls with the same args produce the same effect. */
232
+ idempotentHint?: boolean;
233
+ /** Tool interacts with external systems (true for every SolvaPay tool). */
234
+ openWorldHint?: boolean;
235
+ }
236
+ /**
237
+ * Brand-icon descriptor — mirrors the MCP spec's per-tool / per-resource
238
+ * `icons[]` element so hosts can swap the default globe / placeholder
239
+ * in the chrome strip for the merchant's own mark.
240
+ *
241
+ * Shape tracks the zod schema exposed by `@modelcontextprotocol/ext-apps`
242
+ * (see `app.d.ts` icon definitions). Newer MCP SDKs may surface `icons`
243
+ * as a top-level Tool field; until then we advertise them via
244
+ * `_meta.ui.icons` where ext-apps-aware hosts can discover them.
245
+ */
246
+ interface SolvaPayToolIcon {
247
+ /** Absolute URL or `data:` URI for the icon asset. */
248
+ src: string;
249
+ /** MIME type, e.g. `'image/png'` / `'image/svg+xml'`. */
250
+ mimeType?: string;
251
+ /** Size hints, e.g. `['512x512']`. */
252
+ sizes?: string[];
253
+ /** Render only under the given host theme (defaults to both). */
254
+ theme?: 'light' | 'dark';
255
+ }
256
+ /**
257
+ * Merchant branding that hosts / iframes can use to replace the
258
+ * generic SolvaPay identity with the merchant's own mark. Pre-fetched
259
+ * by the integrator at server startup (e.g. via `getMerchantCore`) so
260
+ * `createSolvaPayMcpServer` stays synchronous.
261
+ */
262
+ interface SolvaPayMerchantBranding {
263
+ /** Display name used as the MCP `Implementation.name`. */
264
+ brandName?: string;
265
+ /**
266
+ * Absolute URL to a square logomark (recommended 512×512 PNG or SVG).
267
+ * Preferred input for MCP host-chrome icon slots.
268
+ */
269
+ iconUrl?: string;
270
+ /**
271
+ * Absolute URL to a landscape logo. Used as a fallback when
272
+ * `iconUrl` isn't available — hosts that can only render a square
273
+ * mark may letterbox it.
274
+ */
275
+ logoUrl?: string;
276
+ }
277
+ /**
278
+ * Framework-neutral tool descriptor. Adapters translate this to their
279
+ * own registration API (`registerAppTool` on the official SDK,
280
+ * `tool.define` on `fastmcp`, etc.).
281
+ */
282
+ interface SolvaPayToolDescriptor {
283
+ name: string;
284
+ title?: string;
285
+ description: string;
286
+ /**
287
+ * Zod raw shape — `{ fieldName: z.string() }`. Kept as `ZodTypeAny`
288
+ * valued so zod stays an optional peer. Empty object = no args.
289
+ */
290
+ inputSchema: Record<string, ZodTypeAny>;
291
+ meta?: Record<string, unknown>;
292
+ /**
293
+ * Portable MCP tool annotations surfaced on `tools/list`. Adapters
294
+ * that support the upstream `ToolAnnotations` field forward these
295
+ * verbatim; adapters that don't silently ignore them.
296
+ */
297
+ annotations?: SolvaPayToolAnnotations;
298
+ /**
299
+ * Brand icons surfaced on `tools/list`. Adapters include these on
300
+ * the tool advertisement so hosts can replace the default globe /
301
+ * placeholder in their chrome strip with the merchant's mark.
302
+ * Derived from `SolvaPayMerchantBranding` when the descriptor is
303
+ * built.
304
+ */
305
+ icons?: SolvaPayToolIcon[];
306
+ handler: (args: Record<string, unknown>, extra?: McpToolExtra) => Promise<SolvaPayCallToolResult>;
307
+ }
308
+ /**
309
+ * UI resource descriptor for the MCP App HTML bundle served alongside
310
+ * the tool surface.
311
+ */
312
+ interface SolvaPayResourceDescriptor {
313
+ uri: string;
314
+ mimeType: string;
315
+ csp: Required<SolvaPayMcpCsp>;
316
+ readHtml: () => Promise<string>;
317
+ }
318
+ /**
319
+ * Docs-style resource descriptor — a static markdown / text blob the
320
+ * agent can `resources/read` for narrated context (e.g. the
321
+ * `docs://solvapay/overview.md` "start here" guide). Kept separate from
322
+ * `SolvaPayResourceDescriptor` because it has no CSP metadata and its
323
+ * body is plain text, not the UI shell HTML.
324
+ */
325
+ interface SolvaPayDocsResourceDescriptor {
326
+ /** Stable URI — typically `docs://solvapay/<slug>.md`. */
327
+ uri: string;
328
+ /** Human-readable name surfaced in `resources/list`. */
329
+ name: string;
330
+ /** Optional short title for host UIs that distinguish it from `name`. */
331
+ title?: string;
332
+ /** Short one-liner surfaced in `resources/list` metadata. */
333
+ description: string;
334
+ /** MIME type, typically `text/markdown` or `text/plain`. */
335
+ mimeType: string;
336
+ /** Returns the body — sync or async. */
337
+ readBody: () => string | Promise<string>;
338
+ }
339
+ /**
340
+ * One MCP prompt — rendered as `/<name>` in hosts with slash-command
341
+ * support. Kept framework-neutral so every adapter (`@modelcontextprotocol/sdk`,
342
+ * `fastmcp`, raw JSON-RPC) can map it to their own `registerPrompt`
343
+ * shape.
344
+ *
345
+ * `argsSchema` matches the zod raw-shape shape the official SDK's
346
+ * `registerPrompt` accepts — a plain object of `z.*` fields. Adapters
347
+ * without zod-shape prompts can still call each field's `parse()`
348
+ * themselves.
349
+ */
350
+ interface SolvaPayPromptDescriptor {
351
+ name: string;
352
+ title?: string;
353
+ description: string;
354
+ argsSchema?: Record<string, ZodTypeAny>;
355
+ handler: (args: Record<string, unknown>) => SolvaPayPromptResult | Promise<SolvaPayPromptResult>;
356
+ }
357
+ /**
358
+ * Minimal `GetPromptResult` shape — structural subset of the official
359
+ * SDK's type so adapters can forward it without importing
360
+ * `@modelcontextprotocol/sdk/types.js`.
361
+ */
362
+ interface SolvaPayPromptResult {
363
+ messages: Array<{
364
+ role: 'user' | 'assistant';
365
+ content: {
366
+ type: 'text';
367
+ text: string;
368
+ };
369
+ }>;
370
+ }
371
+ /**
372
+ * View → intent-tool map, derived from `MCP_TOOL_NAMES` so a new view
373
+ * requires exactly one edit across the entire ecosystem.
374
+ *
375
+ * `paywall` has no dedicated intent tool — the paywall response carries
376
+ * the bootstrap payload directly (`paywallToolResult` merges it into
377
+ * `structuredContent`), so the shell renders the paywall view without
378
+ * re-invoking a tool.
379
+ */
380
+ declare const TOOL_FOR_VIEW: {
381
+ readonly checkout: "upgrade";
382
+ readonly account: "manage_account";
383
+ readonly topup: "topup";
384
+ };
385
+ /**
386
+ * Inverse of `TOOL_FOR_VIEW` — intent-tool name → view kind.
387
+ */
388
+ declare const VIEW_FOR_TOOL: Record<string, SolvaPayMcpViewKind>;
389
+ /**
390
+ * @deprecated Use `TOOL_FOR_VIEW`. Kept as an alias so the rename lands
391
+ * without a simultaneous import update across the ecosystem.
392
+ */
393
+ declare const OPEN_TOOL_FOR_VIEW: {
394
+ readonly checkout: "upgrade";
395
+ readonly account: "manage_account";
396
+ readonly topup: "topup";
397
+ };
398
+ /**
399
+ * @deprecated Use `VIEW_FOR_TOOL`.
400
+ */
401
+ declare const VIEW_FOR_OPEN_TOOL: Record<string, SolvaPayMcpViewKind>;
402
+ /**
403
+ * Inline upsell strip attached to a successful tool response. Rendered
404
+ * below the tool result by the host; dismissible, non-blocking.
405
+ *
406
+ * V1 ships three default kinds, each with a default CTA that opens the
407
+ * `upgrade` intent tool. `kind: 'custom'` is reserved for V1.1.
408
+ */
409
+ interface NudgeSpec {
410
+ kind: 'low-balance' | 'cycle-ending' | 'approaching-limit';
411
+ message: string;
412
+ }
413
+ /**
414
+ * Intermediate content block emitted via `ctx.emit(block)`. Structural
415
+ * subset of `SolvaPayCallToolResult.content` entries — text, image, or
416
+ * resource.
417
+ */
418
+ type ContentBlock = {
419
+ type: 'text';
420
+ text: string;
421
+ } | {
422
+ type: 'image';
423
+ data: string;
424
+ mimeType: string;
425
+ } | {
426
+ type: 'resource';
427
+ resource: Record<string, unknown>;
428
+ };
429
+ /**
430
+ * Options for `ctx.respond(data, options?)`.
431
+ *
432
+ * `text` overrides the SDK's default narrator output for this response.
433
+ * `nudge` attaches an inline upsell strip.
434
+ * `units` is reserved for V1.1 variable-unit billing; V1 silently
435
+ * ignores the field (billing stays at one credit per tool call).
436
+ */
437
+ interface ResponseOptions {
438
+ /** Override `content[0].text` with merchant-supplied text. */
439
+ text?: string;
440
+ /** Inline upsell strip rendered below the tool result. */
441
+ nudge?: NudgeSpec;
442
+ /**
443
+ * [V1.1] Units to bill for this call. Defaults to 1. Must be >= 0.
444
+ *
445
+ * V1 behaviour: field is accepted for forward compatibility but
446
+ * silently ignored. Billing stays fixed at one credit per tool call.
447
+ * V1.1 behaviour: threaded into `trackUsage` and applied by the backend.
448
+ */
449
+ units?: number;
450
+ }
451
+ /**
452
+ * Branded envelope returned by `ctx.respond(data, options?)`. The brand
453
+ * symbol is module-private — merchants never construct `ResponseResult`
454
+ * values directly. `buildPayableHandler` unwraps the envelope into a
455
+ * `SolvaPayCallToolResult` before shipping.
456
+ */
457
+ interface ResponseResult<TData = unknown> {
458
+ /**
459
+ * Opaque brand marker — typed as `true` so the envelope is
460
+ * structurally distinguishable from raw merchant data even without
461
+ * the runtime symbol.
462
+ */
463
+ readonly __solvapayResponse: true;
464
+ readonly data: TData;
465
+ readonly options?: ResponseOptions;
466
+ /**
467
+ * Content blocks queued via `ctx.emit(block)` before the terminal
468
+ * `respond()` call. V1 flushes these into `content[]` at respond
469
+ * time; V1.1 emits them over SSE.
470
+ */
471
+ readonly emittedBlocks?: ContentBlock[];
472
+ }
473
+ /**
474
+ * Cached snapshot of customer state at handler invocation.
475
+ *
476
+ * Populated from the existing `LimitResponse` returned by
477
+ * `payable().mcp()`'s pre-check — zero additional fetch cost.
478
+ *
479
+ * IMPORTANT: values here may be up to 10 seconds stale after mutations
480
+ * (topup, plan change, cancel) within the same process. For fresh
481
+ * state, call `.fresh()`.
482
+ */
483
+ interface CustomerSnapshot {
484
+ /** Backend customer ref (`cus_...`). */
485
+ readonly ref: string;
486
+ /** Credit balance in mils. 0 when the backend didn't surface a balance. */
487
+ readonly balance: number;
488
+ /** Remaining usage units before hitting the limit. `null` when unlimited. */
489
+ readonly remaining: number | null;
490
+ /** Whether the customer is within their usage limits at snapshot time. */
491
+ readonly withinLimits: boolean;
492
+ /**
493
+ * Active plan on the purchase. `null` when the customer has no
494
+ * active purchase or is on a free plan.
495
+ */
496
+ readonly plan: BootstrapPlan | null;
497
+ /**
498
+ * Force a fresh fetch bypassing the 10s limits cache.
499
+ * Returns a new snapshot; does NOT mutate the current one.
500
+ */
501
+ fresh(): Promise<CustomerSnapshot>;
502
+ }
503
+ /**
504
+ * Handler context passed as the second positional argument to merchant
505
+ * `registerPayable` handlers opting into the V1 `ctx` API.
506
+ *
507
+ * V1 surface: `customer`, `product`, `respond`, `gate`.
508
+ * Reserved (V1.1): `emit`, `progress`, `progressRaw`, `signal` — types
509
+ * ship in V1 so merchants can write forward-compatible code.
510
+ */
511
+ interface ResponseContext {
512
+ /**
513
+ * Customer snapshot at handler invocation. See `CustomerSnapshot`
514
+ * for staleness semantics.
515
+ */
516
+ customer: CustomerSnapshot;
517
+ /** Read-only product configuration from the bootstrap payload. */
518
+ product: BootstrapProduct;
519
+ /** Build a response. Two forms, both valid. */
520
+ respond<TData>(data: TData): ResponseResult<TData>;
521
+ respond<TData>(data: TData, options: ResponseOptions): ResponseResult<TData>;
522
+ /**
523
+ * Explicitly trigger a paywall response. Handler execution stops
524
+ * and the adapter routes the gate through `formatGate` — the MCP
525
+ * transport emits a clean narration + `structuredContent` payload
526
+ * with `isError: false`, same shape as a pre-check gate outcome.
527
+ *
528
+ * Implemented as `throw new PaywallError(reason)` for the compat
529
+ * window; the adapter's catch block at the boundary unwraps it
530
+ * and delivers the transport response. Merchants who catch the
531
+ * error themselves can still rely on `instanceof PaywallError`.
532
+ *
533
+ * Rare — normally the SDK fires the paywall automatically via
534
+ * `payable().mcp()` pre-check.
535
+ */
536
+ gate(reason?: string): never;
537
+ /**
538
+ * [V1.1] Emit an intermediate content block.
539
+ *
540
+ * V1 behaviour: queued and flushed at the terminal `respond()`. No SSE.
541
+ * V1.1 behaviour: emits immediately over Streamable HTTP + SSE.
542
+ *
543
+ * Reserved so merchants can write forward-compatible streaming code
544
+ * today.
545
+ */
546
+ emit(block: ContentBlock): Promise<void>;
547
+ /**
548
+ * [V1.1] Emit a progress notification with a percent.
549
+ *
550
+ * V1 behaviour: no-op.
551
+ * V1.1 behaviour: sends `notifications/progress` if the client
552
+ * supplied a `progressToken`; no-op otherwise.
553
+ */
554
+ progress(options: {
555
+ percent: number;
556
+ message?: string;
557
+ }): Promise<void>;
558
+ /**
559
+ * [V1.1] Emit a progress notification with non-percent units.
560
+ *
561
+ * V1 behaviour: no-op.
562
+ * V1.1 behaviour: sends `notifications/progress` with raw
563
+ * progress/total.
564
+ */
565
+ progressRaw(options: {
566
+ progress: number;
567
+ total?: number;
568
+ message?: string;
569
+ }): Promise<void>;
570
+ /**
571
+ * [V1.1] AbortSignal that fires when the client cancels the tool call.
572
+ *
573
+ * V1 behaviour: always an unaborted signal.
574
+ * V1.1 behaviour: wired to the underlying transport cancellation.
575
+ *
576
+ * Merchants pass this to their upstream fetch/LLM/image-gen calls to
577
+ * cancel expensive operations when the client goes away.
578
+ */
579
+ signal: AbortSignal;
580
+ }
581
+ /**
582
+ * Merchant handler signature for `registerPayable`. Receives the
583
+ * parsed input `args` (typed from the tool's `schema` when provided)
584
+ * and a `ResponseContext` with `ctx.respond(...)`, `ctx.customer`,
585
+ * `ctx.gate(...)`, and the reserved streaming surface (`ctx.emit`,
586
+ * `ctx.progress`, `ctx.signal`).
587
+ *
588
+ * Must return the branded envelope produced by `ctx.respond(data, options?)`.
589
+ * Returning a raw value is a type error at compile time and throws a
590
+ * merchant-actionable error at runtime.
591
+ */
592
+ type PayableHandler<TArgs = Record<string, unknown>, TData = unknown> = (args: TArgs, ctx: ResponseContext) => Promise<ResponseResult<TData>>;
593
+
594
+ /**
595
+ * Narrator map — one function per intent tool that renders a sparse,
596
+ * text-friendly markdown summary of the bootstrap payload.
597
+ *
598
+ * Style rules (see the discoverable-UX plan for rationale):
599
+ * 1. First line is a single `**bold title**` — no headings.
600
+ * 2. Body uses `Label: value` rows (one per line). Inline `·`
601
+ * separator for compound values. No bullet lists.
602
+ * 3. Commands on a single line as inline-code tokens.
603
+ * 4. External URLs go into `resource_link` blocks, not inline
604
+ * markdown links.
605
+ *
606
+ * Missing fields skip their row entirely — we never emit `Balance: —`
607
+ * or `Customer: unknown`. A narrator returning just `title + 1 row`
608
+ * is still well-formed.
609
+ */
610
+
611
+ interface NarratorOutput {
612
+ text: string;
613
+ links?: Array<{
614
+ uri: string;
615
+ name: string;
616
+ }>;
617
+ }
618
+ type IntentTool = 'upgrade' | 'manage_account' | 'topup' | 'activate_plan';
619
+ interface PlanShape {
620
+ name?: string;
621
+ planType?: string;
622
+ price?: number;
623
+ currency?: string;
624
+ billingCycle?: string | null;
625
+ meterRef?: string | null;
626
+ limit?: number | null;
627
+ }
628
+ interface PurchaseShape {
629
+ planSnapshot?: PlanShape | null;
630
+ amount?: number;
631
+ currency?: string;
632
+ endDate?: string;
633
+ }
634
+ interface CustomerShape {
635
+ ref?: string;
636
+ balance?: {
637
+ credits?: number | null;
638
+ displayCurrency?: string;
639
+ displayExchangeRate?: number;
640
+ } | null;
641
+ usage?: {
642
+ used?: number;
643
+ limit?: number;
644
+ resetsAt?: string;
645
+ } | null;
646
+ purchase?: {
647
+ purchases?: PurchaseShape[];
648
+ } | null;
649
+ }
650
+ /**
651
+ * Human-readable balance summary used by the `'ui'` mode placeholder.
652
+ * Returns `null` when no balance is available so the caller can skip
653
+ * the segment entirely.
654
+ */
655
+ declare function balanceSummary(customer: CustomerShape | null | undefined): string | null;
656
+ declare function narrateManageAccount(data: BootstrapPayload): NarratorOutput;
657
+ declare function narrateUpgrade(data: BootstrapPayload): NarratorOutput;
658
+ declare function narrateTopup(data: BootstrapPayload): NarratorOutput;
659
+ declare function narrateActivatePlan(data: BootstrapPayload): NarratorOutput;
660
+ declare const NARRATORS: Record<IntentTool, (data: BootstrapPayload) => NarratorOutput>;
661
+ /**
662
+ * One-line placeholder shown on UI-rendering hosts when the intent
663
+ * tool runs in `mode: 'ui'`. Gives the agent minimal grounding (what
664
+ * surface opened + balance when available) without flooding the user
665
+ * pane with the full narrated markdown that the iframe already covers.
666
+ */
667
+ declare function uiPlaceholder(tool: IntentTool, data: BootstrapPayload): string;
668
+
669
+ /**
670
+ * Shared building blocks for `buildSolvaPayDescriptors` and any hand-rolled
671
+ * SolvaPay MCP server that prefers to register tools directly.
672
+ *
673
+ * Lifted from the canonical example at `examples/mcp-checkout-app/src/server.ts`
674
+ * so every integrator gets the same behavior for price enrichment, synthetic
675
+ * `Request` construction, and tool-result wrapping.
676
+ */
677
+
678
+ /**
679
+ * Augment a purchase with human-readable price strings so callers (LLMs
680
+ * rendering the JSON directly) don't have to reason about minor units.
681
+ *
682
+ * Raw `amount` / `originalAmount` / `currency` fields are preserved for
683
+ * programmatic consumers (e.g. the React transport).
684
+ */
685
+ declare function enrichPurchase(purchase: Record<string, unknown>): Record<string, unknown>;
686
+ /**
687
+ * Default extractor for `customer_ref` out of the MCP OAuth bridge. Reads
688
+ * `extra.authInfo.extra.customer_ref` (what `auth-bridge.ts` populates) and
689
+ * trims it. Returns `null` when no ref is present.
690
+ */
691
+ declare function defaultGetCustomerRef(extra?: McpToolExtra): string | null;
692
+ interface BuildSolvaPayRequestOptions {
693
+ method?: string;
694
+ query?: Record<string, string | undefined>;
695
+ body?: unknown;
696
+ /**
697
+ * Override the customer ref that is forwarded as the `x-user-id` header.
698
+ * Defaults to reading `extra.authInfo.extra.customer_ref`.
699
+ */
700
+ getCustomerRef?: (extra?: McpToolExtra) => string | null;
701
+ /**
702
+ * Override the synthetic origin used in the request URL. Defaults to
703
+ * `http://solvapay-mcp-server.local/`.
704
+ */
705
+ origin?: string;
706
+ }
707
+ /**
708
+ * Build a synthetic Web `Request` the core `*Core` helpers can consume.
709
+ *
710
+ * The `x-user-id` header is what `getAuthenticatedUserCore` reads as the
711
+ * authoritative user identity, so forwarding the `customer_ref` from the
712
+ * MCP OAuth bridge keeps the entire flow headless.
713
+ */
714
+ declare function buildSolvaPayRequest(extra: McpToolExtra | undefined, options?: BuildSolvaPayRequestOptions): Request;
715
+ /**
716
+ * Wrap arbitrary data in a `SolvaPayCallToolResult`. Produces a `text`
717
+ * content block and `structuredContent` so both LLM-facing and tool-call
718
+ * consumers see a consistent shape.
719
+ */
720
+ declare function toolResult(data: unknown): SolvaPayCallToolResult;
721
+ /**
722
+ * Requested rendering mode per-call. Passed through the `mode` input
723
+ * arg of every intent tool.
724
+ *
725
+ * - `'ui'` (default) — emit a one-line placeholder in `content[0]`
726
+ * alongside the UI resource ref on `_meta.ui`. Keeps UI-rendering
727
+ * hosts (MCP Inspector, ChatGPT Apps, Claude Desktop) tidy — the
728
+ * iframe already carries the rich detail. Agents get the full
729
+ * `BootstrapPayload` on `structuredContent` for grounding.
730
+ * - `'text'` — strip the UI resource ref and emit the full narrated
731
+ * markdown so CLI / text-only hosts get a human summary.
732
+ * - `'auto'` — emit both the narrated markdown and the UI resource
733
+ * ref. The narrated block is annotated with `audience: ['assistant']`
734
+ * so audience-aware hosts pass it to the model without showing it in
735
+ * the user pane.
736
+ */
737
+ type SolvaPayToolMode = 'ui' | 'text' | 'auto';
738
+ declare function parseMode(raw: unknown): SolvaPayToolMode;
739
+ /**
740
+ * Build a `SolvaPayCallToolResult` that respects the requested `mode`:
741
+ *
742
+ * - `ui` (default) emits a one-line placeholder in `content[0]` and
743
+ * keeps `_meta.ui.*` so UI-rendering hosts open the iframe without
744
+ * a noisy narration beneath it. `structuredContent` still carries
745
+ * the raw bootstrap payload so agents have full grounding.
746
+ * - `text` emits the full narrated markdown (plus any
747
+ * `resource_link` blocks) and strips `_meta.ui.*` so UI-capable
748
+ * hosts render text-only for this call.
749
+ * - `auto` emits both. The narrated text block is annotated with
750
+ * `audience: ['assistant']` so audience-aware hosts still hide it
751
+ * from the user pane while feeding it to the model.
752
+ *
753
+ * The narrator is picked by the `tool` name; unknown tools fall back
754
+ * to the JSON dump that `toolResult` produces today.
755
+ */
756
+ declare function narratedToolResult(tool: IntentTool | string, data: BootstrapPayload, mode?: SolvaPayToolMode, baseMeta?: Record<string, unknown> | undefined): SolvaPayCallToolResult;
757
+ /**
758
+ * Wrap an error payload (typically the result of `handleRouteError`) in a
759
+ * `SolvaPayCallToolResult` with `isError: true`.
760
+ */
761
+ declare function toolErrorResult(error: {
762
+ error: string;
763
+ status: number;
764
+ details?: string;
765
+ }): SolvaPayCallToolResult;
766
+ /**
767
+ * Truncate a JSON preview to a max length so trace logs stay readable.
768
+ */
769
+ declare function previewJson(value: unknown, max?: number): string;
770
+
771
+ /**
772
+ * Canonical paywall `_meta.ui` envelope used by every SolvaPay MCP
773
+ * tool result. Centralising this shape means swapping the UI resource
774
+ * URI is a one-line builder call at every call site.
775
+ */
776
+ interface PaywallUiMetaInput {
777
+ /** UI resource URI the MCP host opens to render the paywall view. */
778
+ resourceUri: string;
779
+ }
780
+ interface PaywallUiMeta {
781
+ ui: {
782
+ resourceUri: string;
783
+ };
784
+ [key: string]: unknown;
785
+ }
786
+ /**
787
+ * Build the `_meta` envelope attached to paywall tool results. Consumed
788
+ * by `paywallToolResult`, `buildPayableHandler`, and the descriptor
789
+ * registration layer so the shape stays in lockstep.
790
+ *
791
+ * The bootstrap payload itself now travels on `structuredContent` — this
792
+ * envelope only tells the host which UI resource to open.
793
+ */
794
+ declare function buildPaywallUiMeta(input: PaywallUiMetaInput): PaywallUiMeta;
795
+
796
+ /**
797
+ * Standalone `buildBootstrapPayload` factory — same logic `buildSolvaPayDescriptors`
798
+ * wires under the `open_*` tools, exposed separately so the paywall
799
+ * envelope (`paywallToolResult`, `buildPayableHandler`) can embed the
800
+ * full `BootstrapPayload` in `structuredContent` without duplicating
801
+ * the parallel fetch layout.
802
+ */
803
+
804
+ interface CreateBuildBootstrapPayloadOptions {
805
+ solvaPay: SolvaPay;
806
+ productRef: string;
807
+ publicBaseUrl: string;
808
+ getCustomerRef?: (extra?: McpToolExtra) => string | null;
809
+ }
810
+ type BuildBootstrapPayloadFn = (view: SolvaPayMcpViewKind, extra: McpToolExtra | undefined, extras?: {
811
+ paywall?: PaywallStructuredContent;
812
+ }) => Promise<BootstrapPayload>;
813
+ /**
814
+ * Produce a reusable `buildBootstrapPayload(view, extra, extras?)` closure
815
+ * wired against the same SolvaPay instance + product as a
816
+ * `buildSolvaPayDescriptors` bundle.
817
+ *
818
+ * The returned function runs `getMerchant`, `getProduct`, `listPlans`,
819
+ * `checkPurchase`, `getPaymentMethod`, `getCustomerBalance`, `getUsage`
820
+ * in parallel, failing loudly when merchant or product can't load (the
821
+ * React shell can't render meaningfully without them) and degrading
822
+ * gracefully on per-customer sub-reads.
823
+ */
824
+ declare function createBuildBootstrapPayload(options: CreateBuildBootstrapPayloadOptions): BuildBootstrapPayloadFn;
825
+
826
+ /**
827
+ * Helper for hand-rolled MCP tool handlers that still want to attach the
828
+ * `_meta.ui` envelope + a full `BootstrapPayload` to paywall results
829
+ * without adopting `buildPayableHandler` / `registerPayableTool`
830
+ * wholesale.
831
+ */
832
+
833
+ interface PaywallToolResultContext {
834
+ /** UI resource URI the MCP host should open to render the paywall view. */
835
+ resourceUri: string;
836
+ /**
837
+ * Builds the full `BootstrapPayload` that rides on
838
+ * `structuredContent` so the React shell can mount the paywall view
839
+ * from the gate response directly — no follow-up `open_paywall` call.
840
+ * Wire this from `buildSolvaPayDescriptors(...).buildBootstrapPayload`.
841
+ */
842
+ buildBootstrap?: BuildBootstrapPayloadFn;
843
+ /** Forwarded to `buildBootstrap` so customer-scoped fields resolve. */
844
+ extra?: McpToolExtra;
845
+ }
846
+ /**
847
+ * Convert a paywall gate (either a `PaywallError` or the underlying
848
+ * `PaywallStructuredContent` returned by `paywall.decide()`) into a
849
+ * `PaywallToolResult` carrying a full `BootstrapPayload` (so the
850
+ * React shell can render the paywall view immediately) and the
851
+ * `_meta.ui` envelope telling the host which resource to open.
852
+ *
853
+ * Prefer the gate-first form when you already have a
854
+ * `PaywallDecision` in hand:
855
+ *
856
+ * ```ts
857
+ * const decision = await solvaPay.paywall.decide(args, { product })
858
+ * if (decision.outcome === 'gate') {
859
+ * return paywallToolResult(decision.gate, {
860
+ * resourceUri: 'ui://my-app/mcp-app.html',
861
+ * buildBootstrap,
862
+ * extra,
863
+ * })
864
+ * }
865
+ * ```
866
+ *
867
+ * The legacy `PaywallError`-first form continues to work for custom
868
+ * adapters that still `try/catch`:
869
+ *
870
+ * ```ts
871
+ * try {
872
+ * return await solvaPay.payable({ product }).mcp(handler)(args, extra)
873
+ * } catch (err) {
874
+ * if (err instanceof PaywallError) {
875
+ * return paywallToolResult(err, {
876
+ * resourceUri: 'ui://my-app/mcp-app.html',
877
+ * buildBootstrap,
878
+ * extra,
879
+ * })
880
+ * }
881
+ * throw err
882
+ * }
883
+ * ```
884
+ */
885
+ declare function paywallToolResult(errOrGate: PaywallError | PaywallStructuredContent, ctx: PaywallToolResultContext): Promise<PaywallToolResult>;
886
+
887
+ /**
888
+ * Default Content Security Policy allow-list for SolvaPay MCP Apps.
889
+ *
890
+ * The Stripe baseline covers `js.stripe.com`, `api.stripe.com`, and the
891
+ * `hooks.stripe.com` 3DS frame. Adapters merge integrator-provided
892
+ * overrides on top via `mergeCsp`.
893
+ */
894
+
895
+ declare const SOLVAPAY_DEFAULT_CSP: Required<SolvaPayMcpCsp>;
896
+ /**
897
+ * Merge integrator CSP overrides on top of `SOLVAPAY_DEFAULT_CSP`.
898
+ * Deduplicates per domain list so repeated entries don't balloon the
899
+ * resulting `_meta.ui.csp` envelope.
900
+ */
901
+ declare function mergeCsp(overrides: SolvaPayMcpCsp | undefined): Required<SolvaPayMcpCsp>;
902
+
903
+ /**
904
+ * `buildSolvaPayDescriptors(options)` — framework-neutral tool surface
905
+ * builder that every SolvaPay MCP adapter (`@solvapay/mcp`, future
906
+ * `@solvapay/mcp-fastmcp`, raw JSON-RPC adapters) maps onto its own
907
+ * registration API.
908
+ *
909
+ * Body is lifted from the original
910
+ * `packages/server/src/mcp/server.ts#createSolvaPayMcpServer`. The only
911
+ * mechanical difference: instead of calling `registerAppTool(server, ...)`,
912
+ * we push `{ name, handler, ... }` onto a `tools[]` array the adapter
913
+ * iterates.
914
+ */
915
+
916
+ interface BuildSolvaPayDescriptorsOptions {
917
+ /** Initialised SolvaPay instance. */
918
+ solvaPay: SolvaPay;
919
+ /** Default product ref for this MCP server (used when tool args omit it). */
920
+ productRef: string;
921
+ /** UI resource URI served by this server (e.g. `'ui://my-app/mcp-app.html'`). */
922
+ resourceUri: string;
923
+ /**
924
+ * Absolute filesystem path to the built HTML bundle referenced by
925
+ * `resourceUri`. Node-only convenience — dynamic-imports
926
+ * `node:fs/promises` internally. Provide `readHtml` instead for edge
927
+ * runtimes.
928
+ */
929
+ htmlPath?: string;
930
+ /**
931
+ * Edge-neutral alternative to `htmlPath`. One of `htmlPath` or
932
+ * `readHtml` must be provided.
933
+ */
934
+ readHtml?: () => Promise<string>;
935
+ /**
936
+ * Public `https://` origin used as `return_url` for Stripe confirmations.
937
+ * Required because MCP hosts set `window.location.origin` to `"null"`,
938
+ * which Stripe's `confirmPayment` validator rejects.
939
+ */
940
+ publicBaseUrl: string;
941
+ /** Which `open_*` tools to register. Defaults to every known view. */
942
+ views?: SolvaPayMcpViewKind[];
943
+ /** Additional CSP allow-lists merged with the Stripe baseline. */
944
+ csp?: SolvaPayMcpCsp;
945
+ /**
946
+ * Override customer-ref extraction. Defaults to reading
947
+ * `extra.authInfo.extra.customer_ref` (populated by the MCP OAuth
948
+ * bridge).
949
+ */
950
+ getCustomerRef?: (extra?: McpToolExtra) => string | null;
951
+ /**
952
+ * Fired for every tool call so integrators can add tracing / logging.
953
+ * Called before the core helper runs; the result is available on the
954
+ * `response` callback (`onToolResult`).
955
+ */
956
+ onToolCall?: (name: string, args: unknown, extra?: McpToolExtra) => void;
957
+ /** Fired after every tool call completes (success or error). */
958
+ onToolResult?: (name: string, result: SolvaPayCallToolResult, meta: {
959
+ durationMs: number;
960
+ }) => void;
961
+ /**
962
+ * Merchant branding used to personalise the MCP host chrome — when
963
+ * provided, every emitted tool descriptor carries an `icons[]` the
964
+ * adapter surfaces on `tools/list` so hosts can replace the default
965
+ * globe / placeholder with the merchant's mark. Prefer fetching the
966
+ * SDK merchant payload at server startup (`getMerchantCore` exposes
967
+ * `iconUrl` / `logoUrl` / `displayName`) and passing the result in.
968
+ */
969
+ branding?: SolvaPayMerchantBranding;
970
+ }
971
+ interface SolvaPayDescriptorBundle {
972
+ tools: SolvaPayToolDescriptor[];
973
+ resource: SolvaPayResourceDescriptor;
974
+ /**
975
+ * Slash-command prompts that hosts with prompt support (Claude
976
+ * Desktop, Cursor, etc.) surface as `/upgrade`, `/manage_account`,
977
+ * `/topup`, and `/activate_plan`. Hosts without prompt support
978
+ * silently ignore the list — registration is purely additive.
979
+ */
980
+ prompts: SolvaPayPromptDescriptor[];
981
+ /**
982
+ * Narrated docs resources — agent-facing "read me first" content
983
+ * served over `docs://solvapay/*`. Lives alongside the UI resource so
984
+ * agents can `resources/read` before trying a tool.
985
+ */
986
+ docsResources: SolvaPayDocsResourceDescriptor[];
987
+ /**
988
+ * Parallelised fetch of merchant + product + plans + (optional)
989
+ * customer snapshot that backs every `open_*` tool. Exposed so the
990
+ * paywall envelope (`paywallToolResult`, `buildPayableHandler`) can
991
+ * embed the full payload in its `structuredContent`.
992
+ */
993
+ buildBootstrapPayload: BuildBootstrapPayloadFn;
994
+ }
995
+ /**
996
+ * Build the framework-neutral SolvaPay tool + resource descriptors. The
997
+ * returned bundle is adapter-shaped — pass it to the registration helper
998
+ * exported by `@solvapay/mcp` (or any future adapter package).
999
+ */
1000
+ declare function buildSolvaPayDescriptors(options: BuildSolvaPayDescriptorsOptions): SolvaPayDescriptorBundle;
1001
+ /**
1002
+ * Build the framework-neutral slash-command prompt descriptors for the
1003
+ * five SolvaPay intent tools. Exposed standalone so adapters that don't
1004
+ * want the full descriptor bundle (or want to register prompts on an
1005
+ * already-built server) can still pick them up.
1006
+ *
1007
+ * Each prompt is intentionally one `user` message that mirrors how a
1008
+ * human would invoke the intent — this makes slash-commands feel like
1009
+ * natural shortcuts, and keeps the prompts compatible with text hosts
1010
+ * that don't expose the MCP UI shell.
1011
+ */
1012
+ declare function buildSolvaPayPrompts(options?: {
1013
+ enabledViews?: Set<SolvaPayMcpViewKind>;
1014
+ }): SolvaPayPromptDescriptor[];
1015
+
1016
+ /**
1017
+ * Narrated overview for the SolvaPay MCP server — served verbatim at
1018
+ * `docs://solvapay/overview.md` so agents can `resources/read` before
1019
+ * calling any tool.
1020
+ *
1021
+ * Inlined as a TS constant (not a standalone `.md` file) because the
1022
+ * package bundles via tsup — a markdown asset next to this file would
1023
+ * need copy-on-build and runtime `fs` access, neither of which the
1024
+ * framework-neutral `@solvapay/mcp` package should take on.
1025
+ */
1026
+ declare const SOLVAPAY_OVERVIEW_URI = "docs://solvapay/overview.md";
1027
+ declare const SOLVAPAY_OVERVIEW_MIME_TYPE = "text/markdown";
1028
+ declare const SOLVAPAY_OVERVIEW_MARKDOWN = "# SolvaPay MCP server \u2014 overview\n\nThis MCP server connects a SolvaPay-protected product to your host so users can\nmanage their plan, usage, and billing **without leaving the chat**. It is\ndual-audience: every tool returns a UI bootstrap for hosts that render MCP UI\nresources (`basic-host`, Claude Desktop, ChatGPT, etc.) and a markdown summary\nwith clickable URLs for text-only hosts.\n\n## What the user can do\n\n- **Upgrade** \u2014 start or change a paid plan. `/upgrade` opens the embedded\n checkout (Stripe Elements inline) on UI hosts and returns a hosted-checkout\n URL on text hosts.\n- **Manage account** \u2014 current plan, balance, usage, payment method, cancel\n or reactivate auto-renewal. Credits + usage are folded inline into the\n account view. `/manage_account`.\n- **Top up credits** \u2014 add SolvaPay credits for usage-based plans.\n `/topup`.\n- **Activate plan** \u2014 pick a plan from the list or activate a specific plan\n by `planRef`. Free plans activate immediately, usage-based plans activate\n when balance covers the configured usage, paid plans return the embedded\n checkout or a hosted-checkout URL. `/activate_plan`.\n\n## How it fits together\n\nEach intent tool returns a full `BootstrapPayload` (merchant + product + plans\n+ customer snapshot) so the embedded UI never fires per-view read calls. When\na paywalled data tool hits the usage limit, its response carries the same\npayload with `view: \"paywall\"`, letting the host open the UI directly on the\npaywall screen \u2014 no second tool call required.\n\nAuth is handled by the SolvaPay OAuth bridge (see `createMcpOAuthBridge`). The\nbridge injects `customer_ref` onto every authenticated request; tools that\nneed an authenticated caller return `Unauthorized` when it is missing.\n\n## Also see\n\n- `docs://solvapay/overview.md` (this resource) \u2014 agent-facing narration.\n- `ui://<app>/mcp-app.html` \u2014 the embedded UI shell.\n- `tools/list` + `prompts/list` \u2014 programmatic discovery of the intent tools\n and their slash-command shortcuts.\n- Documentation: https://docs.solvapay.com/sdks/typescript/guides/mcp-app.\n";
1029
+
1030
+ /**
1031
+ * `buildPayableHandler(solvaPay, ctx, handler)` — framework-neutral
1032
+ * wrapper that produces an MCP tool handler enforcing the SolvaPay
1033
+ * paywall, auto-attaching `_meta.ui` to paywall results, and (when a
1034
+ * `buildBootstrap` is provided) embedding the full `BootstrapPayload`
1035
+ * in `structuredContent` so the React shell can render the paywall
1036
+ * view without a follow-up tool call.
1037
+ *
1038
+ * Merchant handlers receive a `ResponseContext` as their second
1039
+ * argument and return the `ResponseResult` envelope produced by
1040
+ * `ctx.respond(data, options?)`. `buildPayableHandler` unwraps the
1041
+ * envelope — overlaying `options.text` / `options.nudge` and flushing
1042
+ * queued `ctx.emit(...)` blocks into the terminal response.
1043
+ *
1044
+ * Every SolvaPay MCP adapter (`@solvapay/mcp`, future `fastmcp` /
1045
+ * `fastmcp` adapters) wraps this in its framework-specific
1046
+ * `registerTool` / `registerAppTool` call.
1047
+ */
1048
+
1049
+ interface BuildPayableHandlerContext {
1050
+ /** SolvaPay product ref the tool is protected against. */
1051
+ product: string;
1052
+ /** UI resource URI the MCP host should open to render the paywall view. */
1053
+ resourceUri: string;
1054
+ /**
1055
+ * Builds the full `BootstrapPayload` to embed on paywall results.
1056
+ * Wire from `buildSolvaPayDescriptors(...).buildBootstrapPayload`.
1057
+ */
1058
+ buildBootstrap?: BuildBootstrapPayloadFn;
1059
+ /**
1060
+ * Override customer-ref extraction. Defaults to the MCP adapter's
1061
+ * behavior (reads `extra.authInfo.extra.customer_ref`).
1062
+ */
1063
+ getCustomerRef?: (args: Record<string, unknown>, extra?: McpToolExtra) => string | Promise<string>;
1064
+ }
1065
+ /**
1066
+ * Merchant handler contract: `(args, ctx) => ctx.respond(data, options?)`.
1067
+ * `buildPayableHandler` unwraps the returned `ResponseResult` envelope
1068
+ * into the adapter-facing `SolvaPayCallToolResult`.
1069
+ */
1070
+ type MerchantHandler<TArgs, TResult> = (args: TArgs, ctx: ResponseContext) => Promise<ResponseResult<TResult>>;
1071
+ /**
1072
+ * Build a paywall-protected MCP tool handler. Returned function is a
1073
+ * `(args, extra) => Promise<SolvaPayCallToolResult>` that any MCP
1074
+ * adapter can register directly.
1075
+ *
1076
+ * The handler:
1077
+ * 1. Builds a `ResponseContext` from the pre-check `LimitResponseWithPlan`
1078
+ * and passes it as the second arg to the merchant handler.
1079
+ * 2. Routes the call through `solvaPay.payable({ product }).mcp(wrappedBusinessLogic)`.
1080
+ * 3. Detects paywall results via `isPaywallStructuredContent`.
1081
+ * 4. Rewrites `structuredContent` as a full `BootstrapPayload` with
1082
+ * `view: 'paywall'` + the original gate content on `paywall`
1083
+ * (when `buildBootstrap` is provided — otherwise leaves the raw
1084
+ * gate content intact).
1085
+ * 5. Stamps `_meta.ui = { resourceUri }` so the host knows which UI
1086
+ * resource to open.
1087
+ * 6. Unwraps the merchant's `ResponseResult` envelope into the
1088
+ * terminal `SolvaPayCallToolResult`: applies `options.text` /
1089
+ * `options.nudge` overlays and flushes `ctx.emit(...)` blocks into
1090
+ * `content[]`.
1091
+ * 7. Silently ignores `options.units` (V1 billing stays at one credit
1092
+ * per call; V1.1 will thread it into `trackUsage`).
1093
+ */
1094
+ declare function buildPayableHandler<TArgs extends Record<string, unknown>, TResult>(solvaPay: SolvaPay, ctx: BuildPayableHandlerContext, handler: MerchantHandler<TArgs, TResult>): (args: Record<string, unknown>, extra?: McpToolExtra) => Promise<SolvaPayCallToolResult>;
1095
+
1096
+ /**
1097
+ * Framework-neutral OAuth discovery JSON builders. These are runtime-agnostic
1098
+ * (no Node, no fetch, no Express) — both `@solvapay/mcp-express` and
1099
+ * `@solvapay/mcp-fetch` import them to produce the well-known responses.
1100
+ *
1101
+ * Kept in `@solvapay/mcp-core` so third-party adapter authors (raw JSON-RPC,
1102
+ * `fastmcp`, …) can reuse the exact same shapes with zero transitive deps.
1103
+ */
1104
+ interface OAuthBridgePaths {
1105
+ register?: string;
1106
+ authorize?: string;
1107
+ token?: string;
1108
+ revoke?: string;
1109
+ }
1110
+ interface OAuthAuthorizationServerOptions {
1111
+ publicBaseUrl: string;
1112
+ paths?: OAuthBridgePaths;
1113
+ }
1114
+ declare const DEFAULT_OAUTH_PATHS: Required<OAuthBridgePaths>;
1115
+ declare function withoutTrailingSlash(value: string): string;
1116
+ declare function resolveOAuthPaths(paths?: OAuthBridgePaths): Required<OAuthBridgePaths>;
1117
+ declare function getOAuthProtectedResourceResponse(publicBaseUrl: string): {
1118
+ resource: string;
1119
+ authorization_servers: string[];
1120
+ scopes_supported: string[];
1121
+ };
1122
+ declare function getOAuthAuthorizationServerResponse({ publicBaseUrl, paths, }: OAuthAuthorizationServerOptions): {
1123
+ issuer: string;
1124
+ authorization_endpoint: string;
1125
+ token_endpoint: string;
1126
+ registration_endpoint: string;
1127
+ revocation_endpoint: string;
1128
+ token_endpoint_auth_methods_supported: string[];
1129
+ response_types_supported: string[];
1130
+ grant_types_supported: string[];
1131
+ scopes_supported: string[];
1132
+ code_challenge_methods_supported: string[];
1133
+ };
1134
+
1135
+ /**
1136
+ * MCP OAuth bearer-token helper utilities.
1137
+ *
1138
+ * These helpers are intentionally lightweight and do not verify JWT
1139
+ * signatures. Use them after token validation (for example via
1140
+ * `/v1/customer/auth/userinfo`).
1141
+ */
1142
+ declare class McpBearerAuthError extends Error {
1143
+ constructor(message: string);
1144
+ }
1145
+ type McpBearerCustomerRefOptions = {
1146
+ claimPriority?: string[];
1147
+ };
1148
+ declare function extractBearerToken(authorization?: string | null): string | null;
1149
+ declare function decodeJwtPayload(token: string): Record<string, unknown>;
1150
+ declare function getCustomerRefFromJwtPayload(payload: Record<string, unknown>, options?: McpBearerCustomerRefOptions): string;
1151
+ declare function getCustomerRefFromBearerAuthHeader(authorization?: string | null, options?: McpBearerCustomerRefOptions): string;
1152
+
1153
+ /**
1154
+ * Build an MCP `authInfo` envelope from an `Authorization: Bearer <jwt>`
1155
+ * header. Populates `authInfo.extra.customer_ref` so downstream
1156
+ * `getCustomerRef` extractors (adapter + descriptor handlers) can read
1157
+ * the caller identity without re-parsing the token.
1158
+ */
1159
+
1160
+ interface BuildAuthInfoFromBearerOptions extends McpBearerCustomerRefOptions {
1161
+ clientId?: string;
1162
+ defaultScopes?: string[];
1163
+ includePayload?: boolean;
1164
+ }
1165
+ declare function buildAuthInfoFromBearer(authorization?: string | null, options?: BuildAuthInfoFromBearerOptions): McpToolExtra['authInfo'] | null;
1166
+
1167
+ export { type BootstrapCustomer, type BootstrapMerchant, type BootstrapPayload, type BootstrapPlan, type BootstrapProduct, type BuildAuthInfoFromBearerOptions, type BuildBootstrapPayloadFn, type BuildPayableHandlerContext, type BuildSolvaPayDescriptorsOptions, type BuildSolvaPayRequestOptions, type ContentBlock, type CreateBuildBootstrapPayloadOptions, type CustomerSnapshot, DEFAULT_OAUTH_PATHS, type IntentTool, MCP_TOOL_NAMES, type McpAdapterOptions, McpBearerAuthError, type McpBearerCustomerRefOptions, type McpToolExtra, type McpToolName, NARRATORS, type NarratorOutput, type NudgeSpec, type OAuthAuthorizationServerOptions, type OAuthBridgePaths, OPEN_TOOL_FOR_VIEW, type PayableHandler, type PaywallToolResult, type PaywallToolResultContext, type PaywallUiMeta, type PaywallUiMetaInput, type ResponseContext, type ResponseOptions, type ResponseResult, SOLVAPAY_DEFAULT_CSP, SOLVAPAY_MCP_VIEW_KINDS, SOLVAPAY_OVERVIEW_MARKDOWN, SOLVAPAY_OVERVIEW_MIME_TYPE, SOLVAPAY_OVERVIEW_URI, type SolvaPayCallToolResult, type SolvaPayDescriptorBundle, type SolvaPayDocsResourceDescriptor, type SolvaPayMcpCsp, type SolvaPayMcpPaywallContent, type SolvaPayMcpViewKind, type SolvaPayMerchantBranding, type SolvaPayPromptDescriptor, type SolvaPayPromptResult, type SolvaPayResourceDescriptor, type SolvaPayToolAnnotations, type SolvaPayToolDescriptor, type SolvaPayToolIcon, type SolvaPayToolMode, TOOL_FOR_VIEW, VIEW_FOR_OPEN_TOOL, VIEW_FOR_TOOL, balanceSummary, buildAuthInfoFromBearer, buildPayableHandler, buildPaywallUiMeta, buildSolvaPayDescriptors, buildSolvaPayPrompts, buildSolvaPayRequest, createBuildBootstrapPayload, decodeJwtPayload, defaultGetCustomerRef, enrichPurchase, extractBearerToken, getCustomerRefFromBearerAuthHeader, getCustomerRefFromJwtPayload, getOAuthAuthorizationServerResponse, getOAuthProtectedResourceResponse, mergeCsp, narrateActivatePlan, narrateManageAccount, narrateTopup, narrateUpgrade, narratedToolResult, parseMode, paywallToolResult, previewJson, resolveOAuthPaths, toolErrorResult, toolResult, uiPlaceholder, withoutTrailingSlash };