@solvapay/mcp-core 0.2.5 → 0.2.6-preview-e89fa52f99b6d0c7bf9834fcf2d1403141051fa0

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.
package/dist/index.cjs CHANGED
@@ -35,6 +35,8 @@ __export(index_exports, {
35
35
  McpBearerAuthError: () => McpBearerAuthError,
36
36
  NARRATORS: () => NARRATORS,
37
37
  OPEN_TOOL_FOR_VIEW: () => OPEN_TOOL_FOR_VIEW,
38
+ SOLVAPAY_BOOTSTRAP_MIME_TYPE: () => SOLVAPAY_BOOTSTRAP_MIME_TYPE,
39
+ SOLVAPAY_BOOTSTRAP_URI: () => SOLVAPAY_BOOTSTRAP_URI,
38
40
  SOLVAPAY_DEFAULT_CSP: () => SOLVAPAY_DEFAULT_CSP,
39
41
  SOLVAPAY_MCP_VIEW_KINDS: () => SOLVAPAY_MCP_VIEW_KINDS,
40
42
  SOLVAPAY_OVERVIEW_MARKDOWN: () => SOLVAPAY_OVERVIEW_MARKDOWN,
@@ -183,10 +185,14 @@ function costPerCallRow(creditsPerUnit) {
183
185
  function commandsLine(commands) {
184
186
  return `Commands: ${commands.map((c) => `\`/${c}\``).join(" ")}`;
185
187
  }
188
+ function formatPlanPrices(p) {
189
+ const options = p.pricingOptions && p.pricingOptions.length > 0 ? p.pricingOptions : [{ currency: p.currency, price: p.price, default: true }];
190
+ return options.map((option) => formatMoney(option.price, option.currency)).filter((value) => value != null).join(" \xB7 ");
191
+ }
186
192
  function plansListLines(plans) {
187
193
  return plans.map((p) => {
188
194
  const name = p.name ?? "Plan";
189
- const price = formatMoney(p.price, p.currency);
195
+ const price = formatPlanPrices(p);
190
196
  const cycle = p.billingCycle ? `/${p.billingCycle}` : "";
191
197
  const type = p.planType === "free" ? "no payment required" : p.planType === "usage-based" ? "pay as you go" : p.planType === "trial" ? "trial" : "recurring";
192
198
  if (price && p.planType !== "free") {
@@ -300,13 +306,19 @@ var UI_OPENED_VERB = {
300
306
  manage_account: (p) => `Opened your ${p} account.`,
301
307
  activate_plan: (p) => `Opened ${p} plan picker.`
302
308
  };
309
+ var UI_PANEL_SHOWN = {
310
+ topup: "Top-up options are shown in the panel.",
311
+ upgrade: "Plans and checkout are shown in the panel.",
312
+ manage_account: "Account details are shown in the panel.",
313
+ activate_plan: "Plan options are shown in the panel."
314
+ };
303
315
  function uiPlaceholder(tool, data) {
304
316
  const name = productName(data);
305
317
  const opened = UI_OPENED_VERB[tool](name);
306
318
  const balance = balanceSummary(data.customer);
307
319
  const parts = [opened];
308
320
  if (balance) parts.push(`Balance: ${balance}.`);
309
- parts.push("Pass `mode: 'text'` for a markdown summary.");
321
+ parts.push(UI_PANEL_SHOWN[tool]);
310
322
  return parts.join(" ");
311
323
  }
312
324
 
@@ -439,7 +451,7 @@ function narratedToolResult(tool, data, mode = "ui", baseMeta = void 0) {
439
451
  type: "text",
440
452
  text: uiPlaceholder(tool, data)
441
453
  };
442
- const content = mode === "ui" ? [placeholderBlock] : mode === "text" ? [narratedBlock, ...resourceLinkBlocks] : [narratedBlock, ...resourceLinkBlocks];
454
+ const content = mode === "ui" ? [placeholderBlock, narratedBlock] : mode === "text" ? [narratedBlock, ...resourceLinkBlocks] : [narratedBlock, ...resourceLinkBlocks];
443
455
  const meta = mode === "text" && baseMeta && "ui" in baseMeta ? Object.fromEntries(Object.entries(baseMeta).filter(([k]) => k !== "ui")) : baseMeta;
444
456
  return {
445
457
  content,
@@ -692,6 +704,10 @@ function createBuildBootstrapPayload(options) {
692
704
  };
693
705
  }
694
706
 
707
+ // src/resources/bootstrap.ts
708
+ var SOLVAPAY_BOOTSTRAP_URI = "solvapay://bootstrap.json";
709
+ var SOLVAPAY_BOOTSTRAP_MIME_TYPE = "application/json";
710
+
695
711
  // src/resources/overview.ts
696
712
  var SOLVAPAY_OVERVIEW_URI = "docs://solvapay/overview.md";
697
713
  var SOLVAPAY_OVERVIEW_MIME_TYPE = "text/markdown";
@@ -757,8 +773,8 @@ function deriveIcons(branding) {
757
773
  var solvapayTool = (hints) => ({ openWorldHint: true, ...hints });
758
774
  var INTENT_TOOL_ANNOTATIONS = {
759
775
  account: solvapayTool({ readOnlyHint: true, idempotentHint: true }),
760
- topup: solvapayTool({ destructiveHint: true }),
761
- checkout: solvapayTool({ destructiveHint: true })
776
+ topup: solvapayTool({ readOnlyHint: true, idempotentHint: true }),
777
+ checkout: solvapayTool({ readOnlyHint: true, idempotentHint: true })
762
778
  };
763
779
  var DEFAULT_VIEWS = [...SOLVAPAY_MCP_VIEW_KINDS];
764
780
  function buildSolvaPayDescriptors(options) {
@@ -789,7 +805,13 @@ function buildSolvaPayDescriptors(options) {
789
805
  );
790
806
  }
791
807
  const toolMeta = { ui: { resourceUri } };
792
- const uiToolMeta = { ...toolMeta, audience: "ui" };
808
+ const uiToolMeta = {
809
+ ui: { resourceUri, visibility: ["app"] },
810
+ audience: "ui",
811
+ // ChatGPT Apps SDK rejects iframe `callTool` unless this flag is set.
812
+ // Dual-stamp with `ui.visibility: ['app']` for MCP Apps hosts.
813
+ "openai/widgetAccessible": true
814
+ };
793
815
  const enabledViews = new Set(views);
794
816
  const tools = [];
795
817
  const pushTool = (descriptor) => {
@@ -863,7 +885,7 @@ function buildSolvaPayDescriptors(options) {
863
885
  pushIntentTool(
864
886
  "checkout",
865
887
  "Upgrade plan",
866
- "Start or change a paid plan for the current customer. On UI hosts this opens the embedded checkout; on text hosts returns a markdown summary with a checkout URL. Also available: manage_account (current plan + cancel/reactivate), activate_plan (pick or activate a specific plan), topup (add credits)." + MODE_HINT
888
+ "Start or change a paid plan for the current customer. On UI hosts this opens the embedded checkout; on text hosts returns a markdown summary with a checkout URL. This tool only returns a read-only snapshot or opens the UI \u2014 actual charges happen later in the embedded checkout after the customer confirms. Also available: manage_account (current plan + cancel/reactivate), activate_plan (pick or activate a specific plan), topup (add credits)." + MODE_HINT
867
889
  );
868
890
  pushIntentTool(
869
891
  "account",
@@ -873,7 +895,7 @@ function buildSolvaPayDescriptors(options) {
873
895
  pushIntentTool(
874
896
  "topup",
875
897
  "Top up credits",
876
- "Add SolvaPay credits for the current customer. On UI hosts this opens the embedded top-up flow; on text hosts returns a markdown summary with a top-up URL. Also available: manage_account (current plan + balance + usage), upgrade (switch to a recurring plan)." + MODE_HINT
898
+ "Add SolvaPay credits for the current customer. On UI hosts this opens the embedded top-up flow; on text hosts returns a markdown summary with a top-up URL. This tool only returns a read-only snapshot or opens the UI \u2014 credits are not charged until the customer confirms payment in the embedded flow. Also available: manage_account (current plan + balance + usage), upgrade (switch to a recurring plan)." + MODE_HINT
877
899
  );
878
900
  pushTool({
879
901
  name: MCP_TOOL_NAMES.createCheckoutSession,
@@ -903,7 +925,8 @@ function buildSolvaPayDescriptors(options) {
903
925
  description: UI_ONLY_PREFIX + "Create a Stripe payment intent for the authenticated customer to purchase a plan. Returns { clientSecret, publishableKey, accountId?, customerRef } for confirmation with Stripe Elements in the app UI.",
904
926
  inputSchema: {
905
927
  planRef: import_zod.z.string(),
906
- productRef: import_zod.z.string()
928
+ productRef: import_zod.z.string(),
929
+ currency: import_zod.z.string().optional()
907
930
  },
908
931
  meta: uiToolMeta,
909
932
  annotations: solvapayTool({}),
@@ -912,9 +935,10 @@ function buildSolvaPayDescriptors(options) {
912
935
  if (typeof auth !== "string") return auth;
913
936
  const planRef = typeof args.planRef === "string" ? args.planRef : "";
914
937
  const effectiveProduct = typeof args.productRef === "string" && args.productRef ? args.productRef : productRef;
938
+ const currency = typeof args.currency === "string" && args.currency ? args.currency : void 0;
915
939
  const result = await (0, import_server3.createPaymentIntentCore)(
916
940
  buildRequest(extra, { method: "POST" }),
917
- { planRef, productRef: effectiveProduct },
941
+ { planRef, productRef: effectiveProduct, ...currency && { currency } },
918
942
  { solvaPay }
919
943
  );
920
944
  if ((0, import_server3.isErrorResult)(result)) return toolErrorResult(result);
@@ -1091,7 +1115,18 @@ function buildSolvaPayDescriptors(options) {
1091
1115
  readBody: () => SOLVAPAY_OVERVIEW_MARKDOWN
1092
1116
  }
1093
1117
  ];
1094
- return { tools, resource, prompts, docsResources, buildBootstrapPayload };
1118
+ const bootstrapResource = {
1119
+ uri: SOLVAPAY_BOOTSTRAP_URI,
1120
+ name: "SolvaPay bootstrap",
1121
+ title: "SolvaPay bootstrap",
1122
+ description: "Current merchant/product/plans/customer snapshot for the embedded UI. Widgets read this idempotently when the host scrubs structuredContent from tool results.",
1123
+ mimeType: SOLVAPAY_BOOTSTRAP_MIME_TYPE,
1124
+ // View is an echoed routing label — the widget resolves the actual
1125
+ // surface from host context (`inferViewFromHost`), so any view kind
1126
+ // produces identical merchant/product/plans/customer data.
1127
+ readPayload: (extra) => buildBootstrapPayload("account", extra)
1128
+ };
1129
+ return { tools, resource, prompts, docsResources, bootstrapResource, buildBootstrapPayload };
1095
1130
  }
1096
1131
  function buildSolvaPayPrompts(options = {}) {
1097
1132
  const enabled = options.enabledViews ?? new Set(DEFAULT_VIEWS);
@@ -1455,6 +1490,8 @@ function buildAuthInfoFromBearer(authorization, options = {}) {
1455
1490
  McpBearerAuthError,
1456
1491
  NARRATORS,
1457
1492
  OPEN_TOOL_FOR_VIEW,
1493
+ SOLVAPAY_BOOTSTRAP_MIME_TYPE,
1494
+ SOLVAPAY_BOOTSTRAP_URI,
1458
1495
  SOLVAPAY_DEFAULT_CSP,
1459
1496
  SOLVAPAY_MCP_VIEW_KINDS,
1460
1497
  SOLVAPAY_OVERVIEW_MARKDOWN,
package/dist/index.d.cts CHANGED
@@ -318,6 +318,19 @@ interface SolvaPayDocsResourceDescriptor {
318
318
  /** Returns the body — sync or async. */
319
319
  readBody: () => string | Promise<string>;
320
320
  }
321
+ /**
322
+ * Bootstrap snapshot resource — a JSON `BootstrapPayload` the widget can
323
+ * `resources/read` when the host scrubs `structuredContent` from the
324
+ * opening tool-result notification. Auth-aware via `readPayload(extra)`.
325
+ */
326
+ interface SolvaPayBootstrapResourceDescriptor {
327
+ uri: string;
328
+ name: string;
329
+ title?: string;
330
+ description: string;
331
+ mimeType: string;
332
+ readPayload: (extra?: McpToolExtra) => Promise<BootstrapPayload>;
333
+ }
321
334
  /**
322
335
  * One MCP prompt — rendered as `/<name>` in hosts with slash-command
323
336
  * support. Kept framework-neutral so every adapter (`@modelcontextprotocol/sdk`,
@@ -605,6 +618,11 @@ interface PlanShape {
605
618
  planType?: string;
606
619
  price?: number;
607
620
  currency?: string;
621
+ pricingOptions?: Array<{
622
+ currency?: string;
623
+ price?: number;
624
+ default?: boolean;
625
+ }>;
608
626
  billingCycle?: string | null;
609
627
  meterRef?: string | null;
610
628
  limit?: number | null;
@@ -1126,6 +1144,12 @@ interface SolvaPayDescriptorBundle {
1126
1144
  * agents can `resources/read` before trying a tool.
1127
1145
  */
1128
1146
  docsResources: SolvaPayDocsResourceDescriptor[];
1147
+ /**
1148
+ * Idempotent bootstrap snapshot at `solvapay://bootstrap.json` — the
1149
+ * widget reads this when the host scrubs `structuredContent` from the
1150
+ * opening tool-result notification.
1151
+ */
1152
+ bootstrapResource: SolvaPayBootstrapResourceDescriptor;
1129
1153
  /**
1130
1154
  * Parallelised fetch of merchant + product + plans + (optional)
1131
1155
  * customer snapshot that backs every `open_*` tool. Exposed so the
@@ -1155,6 +1179,17 @@ declare function buildSolvaPayPrompts(options?: {
1155
1179
  enabledViews?: Set<SolvaPayMcpViewKind>;
1156
1180
  }): SolvaPayPromptDescriptor[];
1157
1181
 
1182
+ /**
1183
+ * Idempotent bootstrap snapshot served at `solvapay://bootstrap.json`.
1184
+ *
1185
+ * Widgets read this via `app.readServerResource` when the host scrubs
1186
+ * `structuredContent` from the opening `toolresult` notification (e.g.
1187
+ * MCPJam's AI-SDK `toModelOutput` path). Resource reads bypass chat
1188
+ * cards and model-output scrubbing — same auth context as tool calls.
1189
+ */
1190
+ declare const SOLVAPAY_BOOTSTRAP_URI = "solvapay://bootstrap.json";
1191
+ declare const SOLVAPAY_BOOTSTRAP_MIME_TYPE = "application/json";
1192
+
1158
1193
  /**
1159
1194
  * Narrated overview for the SolvaPay MCP server — served verbatim at
1160
1195
  * `docs://solvapay/overview.md` so agents can `resources/read` before
@@ -1319,4 +1354,4 @@ interface BuildAuthInfoFromBearerOptions extends McpBearerCustomerRefOptions {
1319
1354
  }
1320
1355
  declare function buildAuthInfoFromBearer(authorization?: string | null, options?: BuildAuthInfoFromBearerOptions): McpToolExtra['authInfo'] | null;
1321
1356
 
1322
- export { type ApplyHideToolsByAudienceContext, type ApplyHideToolsByAudienceExtra, type ApplyHideToolsByAudienceOptions, 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 HideToolsByAudienceBypass, 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 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 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, applyHideToolsByAudience, balanceSummary, buildAuthInfoFromBearer, buildPayableHandler, buildSolvaPayDescriptors, buildSolvaPayPrompts, buildSolvaPayRequest, createBuildBootstrapPayload, decodeJwtPayload, defaultGetCustomerRef, defaultIsChatGptRequest, deriveIcons, enrichPurchase, extractBearerToken, getCustomerRefFromBearerAuthHeader, getCustomerRefFromJwtPayload, getOAuthAuthorizationServerResponse, getOAuthProtectedResourceResponse, mergeCsp, narrateActivatePlan, narrateManageAccount, narrateTopup, narrateUpgrade, narratedToolResult, parseMode, paywallToolResult, previewJson, resolveOAuthPaths, toolErrorResult, toolResult, uiPlaceholder, withoutTrailingSlash };
1357
+ export { type ApplyHideToolsByAudienceContext, type ApplyHideToolsByAudienceExtra, type ApplyHideToolsByAudienceOptions, 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 HideToolsByAudienceBypass, 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 ResponseContext, type ResponseOptions, type ResponseResult, SOLVAPAY_BOOTSTRAP_MIME_TYPE, SOLVAPAY_BOOTSTRAP_URI, SOLVAPAY_DEFAULT_CSP, SOLVAPAY_MCP_VIEW_KINDS, SOLVAPAY_OVERVIEW_MARKDOWN, SOLVAPAY_OVERVIEW_MIME_TYPE, SOLVAPAY_OVERVIEW_URI, type SolvaPayBootstrapResourceDescriptor, type SolvaPayCallToolResult, type SolvaPayDescriptorBundle, type SolvaPayDocsResourceDescriptor, type SolvaPayMcpCsp, 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, applyHideToolsByAudience, balanceSummary, buildAuthInfoFromBearer, buildPayableHandler, buildSolvaPayDescriptors, buildSolvaPayPrompts, buildSolvaPayRequest, createBuildBootstrapPayload, decodeJwtPayload, defaultGetCustomerRef, defaultIsChatGptRequest, deriveIcons, enrichPurchase, extractBearerToken, getCustomerRefFromBearerAuthHeader, getCustomerRefFromJwtPayload, getOAuthAuthorizationServerResponse, getOAuthProtectedResourceResponse, mergeCsp, narrateActivatePlan, narrateManageAccount, narrateTopup, narrateUpgrade, narratedToolResult, parseMode, paywallToolResult, previewJson, resolveOAuthPaths, toolErrorResult, toolResult, uiPlaceholder, withoutTrailingSlash };
package/dist/index.d.ts CHANGED
@@ -318,6 +318,19 @@ interface SolvaPayDocsResourceDescriptor {
318
318
  /** Returns the body — sync or async. */
319
319
  readBody: () => string | Promise<string>;
320
320
  }
321
+ /**
322
+ * Bootstrap snapshot resource — a JSON `BootstrapPayload` the widget can
323
+ * `resources/read` when the host scrubs `structuredContent` from the
324
+ * opening tool-result notification. Auth-aware via `readPayload(extra)`.
325
+ */
326
+ interface SolvaPayBootstrapResourceDescriptor {
327
+ uri: string;
328
+ name: string;
329
+ title?: string;
330
+ description: string;
331
+ mimeType: string;
332
+ readPayload: (extra?: McpToolExtra) => Promise<BootstrapPayload>;
333
+ }
321
334
  /**
322
335
  * One MCP prompt — rendered as `/<name>` in hosts with slash-command
323
336
  * support. Kept framework-neutral so every adapter (`@modelcontextprotocol/sdk`,
@@ -605,6 +618,11 @@ interface PlanShape {
605
618
  planType?: string;
606
619
  price?: number;
607
620
  currency?: string;
621
+ pricingOptions?: Array<{
622
+ currency?: string;
623
+ price?: number;
624
+ default?: boolean;
625
+ }>;
608
626
  billingCycle?: string | null;
609
627
  meterRef?: string | null;
610
628
  limit?: number | null;
@@ -1126,6 +1144,12 @@ interface SolvaPayDescriptorBundle {
1126
1144
  * agents can `resources/read` before trying a tool.
1127
1145
  */
1128
1146
  docsResources: SolvaPayDocsResourceDescriptor[];
1147
+ /**
1148
+ * Idempotent bootstrap snapshot at `solvapay://bootstrap.json` — the
1149
+ * widget reads this when the host scrubs `structuredContent` from the
1150
+ * opening tool-result notification.
1151
+ */
1152
+ bootstrapResource: SolvaPayBootstrapResourceDescriptor;
1129
1153
  /**
1130
1154
  * Parallelised fetch of merchant + product + plans + (optional)
1131
1155
  * customer snapshot that backs every `open_*` tool. Exposed so the
@@ -1155,6 +1179,17 @@ declare function buildSolvaPayPrompts(options?: {
1155
1179
  enabledViews?: Set<SolvaPayMcpViewKind>;
1156
1180
  }): SolvaPayPromptDescriptor[];
1157
1181
 
1182
+ /**
1183
+ * Idempotent bootstrap snapshot served at `solvapay://bootstrap.json`.
1184
+ *
1185
+ * Widgets read this via `app.readServerResource` when the host scrubs
1186
+ * `structuredContent` from the opening `toolresult` notification (e.g.
1187
+ * MCPJam's AI-SDK `toModelOutput` path). Resource reads bypass chat
1188
+ * cards and model-output scrubbing — same auth context as tool calls.
1189
+ */
1190
+ declare const SOLVAPAY_BOOTSTRAP_URI = "solvapay://bootstrap.json";
1191
+ declare const SOLVAPAY_BOOTSTRAP_MIME_TYPE = "application/json";
1192
+
1158
1193
  /**
1159
1194
  * Narrated overview for the SolvaPay MCP server — served verbatim at
1160
1195
  * `docs://solvapay/overview.md` so agents can `resources/read` before
@@ -1319,4 +1354,4 @@ interface BuildAuthInfoFromBearerOptions extends McpBearerCustomerRefOptions {
1319
1354
  }
1320
1355
  declare function buildAuthInfoFromBearer(authorization?: string | null, options?: BuildAuthInfoFromBearerOptions): McpToolExtra['authInfo'] | null;
1321
1356
 
1322
- export { type ApplyHideToolsByAudienceContext, type ApplyHideToolsByAudienceExtra, type ApplyHideToolsByAudienceOptions, 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 HideToolsByAudienceBypass, 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 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 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, applyHideToolsByAudience, balanceSummary, buildAuthInfoFromBearer, buildPayableHandler, buildSolvaPayDescriptors, buildSolvaPayPrompts, buildSolvaPayRequest, createBuildBootstrapPayload, decodeJwtPayload, defaultGetCustomerRef, defaultIsChatGptRequest, deriveIcons, enrichPurchase, extractBearerToken, getCustomerRefFromBearerAuthHeader, getCustomerRefFromJwtPayload, getOAuthAuthorizationServerResponse, getOAuthProtectedResourceResponse, mergeCsp, narrateActivatePlan, narrateManageAccount, narrateTopup, narrateUpgrade, narratedToolResult, parseMode, paywallToolResult, previewJson, resolveOAuthPaths, toolErrorResult, toolResult, uiPlaceholder, withoutTrailingSlash };
1357
+ export { type ApplyHideToolsByAudienceContext, type ApplyHideToolsByAudienceExtra, type ApplyHideToolsByAudienceOptions, 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 HideToolsByAudienceBypass, 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 ResponseContext, type ResponseOptions, type ResponseResult, SOLVAPAY_BOOTSTRAP_MIME_TYPE, SOLVAPAY_BOOTSTRAP_URI, SOLVAPAY_DEFAULT_CSP, SOLVAPAY_MCP_VIEW_KINDS, SOLVAPAY_OVERVIEW_MARKDOWN, SOLVAPAY_OVERVIEW_MIME_TYPE, SOLVAPAY_OVERVIEW_URI, type SolvaPayBootstrapResourceDescriptor, type SolvaPayCallToolResult, type SolvaPayDescriptorBundle, type SolvaPayDocsResourceDescriptor, type SolvaPayMcpCsp, 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, applyHideToolsByAudience, balanceSummary, buildAuthInfoFromBearer, buildPayableHandler, buildSolvaPayDescriptors, buildSolvaPayPrompts, buildSolvaPayRequest, createBuildBootstrapPayload, decodeJwtPayload, defaultGetCustomerRef, defaultIsChatGptRequest, deriveIcons, enrichPurchase, extractBearerToken, getCustomerRefFromBearerAuthHeader, getCustomerRefFromJwtPayload, getOAuthAuthorizationServerResponse, getOAuthProtectedResourceResponse, mergeCsp, narrateActivatePlan, narrateManageAccount, narrateTopup, narrateUpgrade, narratedToolResult, parseMode, paywallToolResult, previewJson, resolveOAuthPaths, toolErrorResult, toolResult, uiPlaceholder, withoutTrailingSlash };
package/dist/index.js CHANGED
@@ -103,10 +103,14 @@ function costPerCallRow(creditsPerUnit) {
103
103
  function commandsLine(commands) {
104
104
  return `Commands: ${commands.map((c) => `\`/${c}\``).join(" ")}`;
105
105
  }
106
+ function formatPlanPrices(p) {
107
+ const options = p.pricingOptions && p.pricingOptions.length > 0 ? p.pricingOptions : [{ currency: p.currency, price: p.price, default: true }];
108
+ return options.map((option) => formatMoney(option.price, option.currency)).filter((value) => value != null).join(" \xB7 ");
109
+ }
106
110
  function plansListLines(plans) {
107
111
  return plans.map((p) => {
108
112
  const name = p.name ?? "Plan";
109
- const price = formatMoney(p.price, p.currency);
113
+ const price = formatPlanPrices(p);
110
114
  const cycle = p.billingCycle ? `/${p.billingCycle}` : "";
111
115
  const type = p.planType === "free" ? "no payment required" : p.planType === "usage-based" ? "pay as you go" : p.planType === "trial" ? "trial" : "recurring";
112
116
  if (price && p.planType !== "free") {
@@ -220,13 +224,19 @@ var UI_OPENED_VERB = {
220
224
  manage_account: (p) => `Opened your ${p} account.`,
221
225
  activate_plan: (p) => `Opened ${p} plan picker.`
222
226
  };
227
+ var UI_PANEL_SHOWN = {
228
+ topup: "Top-up options are shown in the panel.",
229
+ upgrade: "Plans and checkout are shown in the panel.",
230
+ manage_account: "Account details are shown in the panel.",
231
+ activate_plan: "Plan options are shown in the panel."
232
+ };
223
233
  function uiPlaceholder(tool, data) {
224
234
  const name = productName(data);
225
235
  const opened = UI_OPENED_VERB[tool](name);
226
236
  const balance = balanceSummary(data.customer);
227
237
  const parts = [opened];
228
238
  if (balance) parts.push(`Balance: ${balance}.`);
229
- parts.push("Pass `mode: 'text'` for a markdown summary.");
239
+ parts.push(UI_PANEL_SHOWN[tool]);
230
240
  return parts.join(" ");
231
241
  }
232
242
 
@@ -359,7 +369,7 @@ function narratedToolResult(tool, data, mode = "ui", baseMeta = void 0) {
359
369
  type: "text",
360
370
  text: uiPlaceholder(tool, data)
361
371
  };
362
- const content = mode === "ui" ? [placeholderBlock] : mode === "text" ? [narratedBlock, ...resourceLinkBlocks] : [narratedBlock, ...resourceLinkBlocks];
372
+ const content = mode === "ui" ? [placeholderBlock, narratedBlock] : mode === "text" ? [narratedBlock, ...resourceLinkBlocks] : [narratedBlock, ...resourceLinkBlocks];
363
373
  const meta = mode === "text" && baseMeta && "ui" in baseMeta ? Object.fromEntries(Object.entries(baseMeta).filter(([k]) => k !== "ui")) : baseMeta;
364
374
  return {
365
375
  content,
@@ -631,6 +641,10 @@ function createBuildBootstrapPayload(options) {
631
641
  };
632
642
  }
633
643
 
644
+ // src/resources/bootstrap.ts
645
+ var SOLVAPAY_BOOTSTRAP_URI = "solvapay://bootstrap.json";
646
+ var SOLVAPAY_BOOTSTRAP_MIME_TYPE = "application/json";
647
+
634
648
  // src/resources/overview.ts
635
649
  var SOLVAPAY_OVERVIEW_URI = "docs://solvapay/overview.md";
636
650
  var SOLVAPAY_OVERVIEW_MIME_TYPE = "text/markdown";
@@ -696,8 +710,8 @@ function deriveIcons(branding) {
696
710
  var solvapayTool = (hints) => ({ openWorldHint: true, ...hints });
697
711
  var INTENT_TOOL_ANNOTATIONS = {
698
712
  account: solvapayTool({ readOnlyHint: true, idempotentHint: true }),
699
- topup: solvapayTool({ destructiveHint: true }),
700
- checkout: solvapayTool({ destructiveHint: true })
713
+ topup: solvapayTool({ readOnlyHint: true, idempotentHint: true }),
714
+ checkout: solvapayTool({ readOnlyHint: true, idempotentHint: true })
701
715
  };
702
716
  var DEFAULT_VIEWS = [...SOLVAPAY_MCP_VIEW_KINDS];
703
717
  function buildSolvaPayDescriptors(options) {
@@ -728,7 +742,13 @@ function buildSolvaPayDescriptors(options) {
728
742
  );
729
743
  }
730
744
  const toolMeta = { ui: { resourceUri } };
731
- const uiToolMeta = { ...toolMeta, audience: "ui" };
745
+ const uiToolMeta = {
746
+ ui: { resourceUri, visibility: ["app"] },
747
+ audience: "ui",
748
+ // ChatGPT Apps SDK rejects iframe `callTool` unless this flag is set.
749
+ // Dual-stamp with `ui.visibility: ['app']` for MCP Apps hosts.
750
+ "openai/widgetAccessible": true
751
+ };
732
752
  const enabledViews = new Set(views);
733
753
  const tools = [];
734
754
  const pushTool = (descriptor) => {
@@ -802,7 +822,7 @@ function buildSolvaPayDescriptors(options) {
802
822
  pushIntentTool(
803
823
  "checkout",
804
824
  "Upgrade plan",
805
- "Start or change a paid plan for the current customer. On UI hosts this opens the embedded checkout; on text hosts returns a markdown summary with a checkout URL. Also available: manage_account (current plan + cancel/reactivate), activate_plan (pick or activate a specific plan), topup (add credits)." + MODE_HINT
825
+ "Start or change a paid plan for the current customer. On UI hosts this opens the embedded checkout; on text hosts returns a markdown summary with a checkout URL. This tool only returns a read-only snapshot or opens the UI \u2014 actual charges happen later in the embedded checkout after the customer confirms. Also available: manage_account (current plan + cancel/reactivate), activate_plan (pick or activate a specific plan), topup (add credits)." + MODE_HINT
806
826
  );
807
827
  pushIntentTool(
808
828
  "account",
@@ -812,7 +832,7 @@ function buildSolvaPayDescriptors(options) {
812
832
  pushIntentTool(
813
833
  "topup",
814
834
  "Top up credits",
815
- "Add SolvaPay credits for the current customer. On UI hosts this opens the embedded top-up flow; on text hosts returns a markdown summary with a top-up URL. Also available: manage_account (current plan + balance + usage), upgrade (switch to a recurring plan)." + MODE_HINT
835
+ "Add SolvaPay credits for the current customer. On UI hosts this opens the embedded top-up flow; on text hosts returns a markdown summary with a top-up URL. This tool only returns a read-only snapshot or opens the UI \u2014 credits are not charged until the customer confirms payment in the embedded flow. Also available: manage_account (current plan + balance + usage), upgrade (switch to a recurring plan)." + MODE_HINT
816
836
  );
817
837
  pushTool({
818
838
  name: MCP_TOOL_NAMES.createCheckoutSession,
@@ -842,7 +862,8 @@ function buildSolvaPayDescriptors(options) {
842
862
  description: UI_ONLY_PREFIX + "Create a Stripe payment intent for the authenticated customer to purchase a plan. Returns { clientSecret, publishableKey, accountId?, customerRef } for confirmation with Stripe Elements in the app UI.",
843
863
  inputSchema: {
844
864
  planRef: z.string(),
845
- productRef: z.string()
865
+ productRef: z.string(),
866
+ currency: z.string().optional()
846
867
  },
847
868
  meta: uiToolMeta,
848
869
  annotations: solvapayTool({}),
@@ -851,9 +872,10 @@ function buildSolvaPayDescriptors(options) {
851
872
  if (typeof auth !== "string") return auth;
852
873
  const planRef = typeof args.planRef === "string" ? args.planRef : "";
853
874
  const effectiveProduct = typeof args.productRef === "string" && args.productRef ? args.productRef : productRef;
875
+ const currency = typeof args.currency === "string" && args.currency ? args.currency : void 0;
854
876
  const result = await createPaymentIntentCore(
855
877
  buildRequest(extra, { method: "POST" }),
856
- { planRef, productRef: effectiveProduct },
878
+ { planRef, productRef: effectiveProduct, ...currency && { currency } },
857
879
  { solvaPay }
858
880
  );
859
881
  if (isErrorResult2(result)) return toolErrorResult(result);
@@ -1030,7 +1052,18 @@ function buildSolvaPayDescriptors(options) {
1030
1052
  readBody: () => SOLVAPAY_OVERVIEW_MARKDOWN
1031
1053
  }
1032
1054
  ];
1033
- return { tools, resource, prompts, docsResources, buildBootstrapPayload };
1055
+ const bootstrapResource = {
1056
+ uri: SOLVAPAY_BOOTSTRAP_URI,
1057
+ name: "SolvaPay bootstrap",
1058
+ title: "SolvaPay bootstrap",
1059
+ description: "Current merchant/product/plans/customer snapshot for the embedded UI. Widgets read this idempotently when the host scrubs structuredContent from tool results.",
1060
+ mimeType: SOLVAPAY_BOOTSTRAP_MIME_TYPE,
1061
+ // View is an echoed routing label — the widget resolves the actual
1062
+ // surface from host context (`inferViewFromHost`), so any view kind
1063
+ // produces identical merchant/product/plans/customer data.
1064
+ readPayload: (extra) => buildBootstrapPayload("account", extra)
1065
+ };
1066
+ return { tools, resource, prompts, docsResources, bootstrapResource, buildBootstrapPayload };
1034
1067
  }
1035
1068
  function buildSolvaPayPrompts(options = {}) {
1036
1069
  const enabled = options.enabledViews ?? new Set(DEFAULT_VIEWS);
@@ -1393,6 +1426,8 @@ export {
1393
1426
  McpBearerAuthError,
1394
1427
  NARRATORS,
1395
1428
  OPEN_TOOL_FOR_VIEW,
1429
+ SOLVAPAY_BOOTSTRAP_MIME_TYPE,
1430
+ SOLVAPAY_BOOTSTRAP_URI,
1396
1431
  SOLVAPAY_DEFAULT_CSP,
1397
1432
  SOLVAPAY_MCP_VIEW_KINDS,
1398
1433
  SOLVAPAY_OVERVIEW_MARKDOWN,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solvapay/mcp-core",
3
- "version": "0.2.5",
3
+ "version": "0.2.6-preview-e89fa52f99b6d0c7bf9834fcf2d1403141051fa0",
4
4
  "description": "Framework-neutral MCP contracts for the SolvaPay SDK (tool names, descriptors, payable handler, paywall meta, CSP, bootstrap payload, OAuth discovery JSON builders, bearer/JWT helpers).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -34,14 +34,14 @@
34
34
  },
35
35
  "peerDependencies": {
36
36
  "zod": "^3.25.0 || ^4.0.0",
37
- "@solvapay/server": "^1.2.0"
37
+ "@solvapay/server": "^1.2.1-preview-e89fa52f99b6d0c7bf9834fcf2d1403141051fa0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "tsup": "^8.5.1",
41
41
  "typescript": "^5.9.3",
42
42
  "vitest": "^4.1.2",
43
43
  "zod": "^4.3.6",
44
- "@solvapay/server": "1.2.0",
44
+ "@solvapay/server": "1.2.1-preview-e89fa52f99b6d0c7bf9834fcf2d1403141051fa0",
45
45
  "@solvapay/test-utils": "^0.0.0"
46
46
  },
47
47
  "scripts": {