@solvapay/mcp 0.1.0 → 0.2.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.
package/dist/index.cjs CHANGED
@@ -25,73 +25,15 @@ __export(index_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(index_exports);
27
27
 
28
- // src/server.ts
29
- var import_server2 = require("@modelcontextprotocol/ext-apps/server");
30
- var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
31
- var import_mcp_core2 = require("@solvapay/mcp-core");
32
-
33
- // src/registerPayableTool.ts
28
+ // src/internal/buildMcpServer.ts
34
29
  var import_server = require("@modelcontextprotocol/ext-apps/server");
30
+ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
35
31
  var import_mcp_core = require("@solvapay/mcp-core");
36
- function registerPayableTool(server, name, options) {
37
- const {
38
- solvaPay,
39
- resourceUri,
40
- schema,
41
- product,
42
- title,
43
- description,
44
- handler,
45
- buildBootstrap,
46
- getCustomerRef,
47
- meta,
48
- annotations,
49
- icons
50
- } = options;
51
- const protectedHandler = (0, import_mcp_core.buildPayableHandler)(
52
- solvaPay,
53
- { product, resourceUri, buildBootstrap, getCustomerRef },
54
- handler
55
- );
56
- const baseMeta = meta ?? {};
57
- const baseUi = baseMeta.ui ?? {};
58
- const hasIcons = icons !== void 0 && icons.length > 0;
59
- const mergedUi = {
60
- resourceUri,
61
- ...baseUi,
62
- ...hasIcons ? { icons } : {}
63
- };
64
- const toolMeta = { ...baseMeta, ui: mergedUi };
65
- const effectiveAnnotations = {
66
- readOnlyHint: true,
67
- openWorldHint: true,
68
- ...annotations
69
- };
70
- return (0, import_server.registerAppTool)(
71
- server,
72
- name,
73
- // Note: `registerAppTool`'s config type is stricter than ours —
74
- // casting so `title` / `description` stay optional and the input
75
- // schema flows through correctly at the registration layer.
76
- {
77
- ...title !== void 0 ? { title } : {},
78
- ...description !== void 0 ? { description } : {},
79
- ...schema !== void 0 ? { inputSchema: schema } : {},
80
- _meta: toolMeta,
81
- annotations: effectiveAnnotations,
82
- ...icons !== void 0 && icons.length > 0 ? { icons } : {}
83
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
- },
85
- async (args, extra) => await protectedHandler(args, extra)
86
- );
87
- }
88
-
89
- // src/server.ts
90
32
  function registerDescriptor(server, tool) {
91
33
  const baseMeta = tool.meta ?? {};
92
34
  const baseUi = baseMeta.ui ?? {};
93
35
  const metaWithIcons = tool.icons && tool.icons.length > 0 ? { ...baseMeta, ui: { ...baseUi, icons: tool.icons } } : baseMeta;
94
- (0, import_server2.registerAppTool)(
36
+ (0, import_server.registerAppTool)(
95
37
  server,
96
38
  tool.name,
97
39
  {
@@ -144,41 +86,55 @@ function registerDocsResource(server, docs) {
144
86
  })
145
87
  );
146
88
  }
147
- function createSolvaPayMcpServer(options) {
89
+ function buildSolvaPayMcpServer(options) {
148
90
  const {
149
- additionalTools,
150
91
  registerPrompts = true,
151
92
  registerDocsResources = true,
152
93
  serverName,
153
94
  serverVersion = "1.0.0",
95
+ hideToolsByAudience: _hideToolsByAudience,
154
96
  ...descriptorOptions
155
97
  } = options;
156
- const { tools, resource, prompts, docsResources, buildBootstrapPayload } = (0, import_mcp_core2.buildSolvaPayDescriptors)(descriptorOptions);
98
+ const descriptors = (0, import_mcp_core.buildSolvaPayDescriptors)(descriptorOptions);
157
99
  const effectiveServerName = serverName ?? descriptorOptions.branding?.brandName ?? "solvapay-mcp-server";
158
- const server = new import_mcp.McpServer({ name: effectiveServerName, version: serverVersion });
159
- for (const tool of tools) {
100
+ const serverIcons = (0, import_mcp_core.deriveIcons)(descriptorOptions.branding);
101
+ const server = new import_mcp.McpServer({
102
+ name: effectiveServerName,
103
+ version: serverVersion,
104
+ ...serverIcons ? { icons: serverIcons } : {}
105
+ });
106
+ for (const tool of descriptors.tools) {
160
107
  registerDescriptor(server, tool);
161
108
  }
162
109
  if (registerPrompts) {
163
- for (const prompt of prompts) {
110
+ for (const prompt of descriptors.prompts) {
164
111
  registerPromptDescriptor(server, prompt);
165
112
  }
166
113
  }
167
114
  if (registerDocsResources) {
168
- for (const docs of docsResources) {
115
+ for (const docs of descriptors.docsResources) {
169
116
  registerDocsResource(server, docs);
170
117
  }
171
118
  }
172
- (0, import_server2.registerAppResource)(
119
+ const resource = descriptors.resource;
120
+ (0, import_server.registerAppResource)(
173
121
  server,
174
122
  resource.uri,
175
123
  resource.uri,
176
124
  {
177
- mimeType: import_server2.RESOURCE_MIME_TYPE,
125
+ mimeType: import_server.RESOURCE_MIME_TYPE,
178
126
  _meta: {
179
127
  ui: {
180
128
  csp: resource.csp,
181
- prefersBorder: true
129
+ // `false` asks the host to skip painting its own outer card /
130
+ // border around the iframe. The widget paints its own frame
131
+ // via `.solvapay-mcp-card`, and `<AppHeader>` renders the
132
+ // merchant mark at the top; a host-painted card on top of
133
+ // that produced a nested-container look (visible on MCP Jam
134
+ // with the earlier `true` default). Hosts that honour the
135
+ // preference (per the MCP Apps spec) now render us flush
136
+ // inside their conversation surface.
137
+ prefersBorder: false
182
138
  }
183
139
  }
184
140
  },
@@ -186,32 +142,117 @@ function createSolvaPayMcpServer(options) {
186
142
  contents: [
187
143
  {
188
144
  uri: resource.uri,
189
- mimeType: import_server2.RESOURCE_MIME_TYPE,
145
+ mimeType: import_server.RESOURCE_MIME_TYPE,
190
146
  text: await resource.readHtml(),
191
147
  _meta: {
192
148
  ui: {
193
149
  csp: resource.csp,
194
- prefersBorder: true
150
+ prefersBorder: false
195
151
  }
196
152
  }
197
153
  }
198
154
  ]
199
155
  })
200
156
  );
157
+ return { server, descriptors };
158
+ }
159
+
160
+ // src/registerPayableTool.ts
161
+ var import_server2 = require("@modelcontextprotocol/ext-apps/server");
162
+ var import_mcp_core2 = require("@solvapay/mcp-core");
163
+ function registerPayableTool(server, name, options) {
164
+ const {
165
+ solvaPay,
166
+ schema,
167
+ product,
168
+ title,
169
+ description,
170
+ handler,
171
+ buildBootstrap,
172
+ getCustomerRef,
173
+ meta,
174
+ annotations,
175
+ icons
176
+ } = options;
177
+ const protectedHandler = (0, import_mcp_core2.buildPayableHandler)(
178
+ solvaPay,
179
+ { product, buildBootstrap, getCustomerRef },
180
+ handler
181
+ );
182
+ const baseMeta = meta ?? {};
183
+ const baseUi = baseMeta.ui ?? {};
184
+ const hasIcons = icons !== void 0 && icons.length > 0;
185
+ const mergedUi = {
186
+ ...baseUi,
187
+ ...hasIcons ? { icons } : {}
188
+ };
189
+ const hasUi = Object.keys(mergedUi).length > 0;
190
+ const toolMeta = hasUi ? { ...baseMeta, ui: mergedUi } : { ...baseMeta };
191
+ const effectiveAnnotations = {
192
+ readOnlyHint: true,
193
+ openWorldHint: true,
194
+ ...annotations
195
+ };
196
+ const hasUiResource = hasUi && typeof mergedUi.resourceUri === "string";
197
+ const toolConfig = {
198
+ ...title !== void 0 ? { title } : {},
199
+ ...description !== void 0 ? { description } : {},
200
+ ...schema !== void 0 ? { inputSchema: schema } : {},
201
+ ...Object.keys(toolMeta).length > 0 ? { _meta: toolMeta } : {},
202
+ annotations: effectiveAnnotations,
203
+ ...icons !== void 0 && icons.length > 0 ? { icons } : {}
204
+ };
205
+ const toolCallback = async (args, extra) => await protectedHandler(args, extra);
206
+ if (hasUiResource) {
207
+ return (0, import_server2.registerAppTool)(
208
+ server,
209
+ name,
210
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
211
+ toolConfig,
212
+ toolCallback
213
+ );
214
+ }
215
+ return server.registerTool(
216
+ name,
217
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
218
+ toolConfig,
219
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
220
+ toolCallback
221
+ );
222
+ }
223
+
224
+ // src/server.ts
225
+ function createSolvaPayMcpServer(options) {
226
+ const {
227
+ additionalTools,
228
+ registerPrompts = true,
229
+ registerDocsResources = true,
230
+ serverName,
231
+ serverVersion = "1.0.0",
232
+ hideToolsByAudience,
233
+ ...descriptorOptions
234
+ } = options;
235
+ const { server, descriptors } = buildSolvaPayMcpServer({
236
+ ...descriptorOptions,
237
+ registerPrompts,
238
+ registerDocsResources,
239
+ ...serverName !== void 0 ? { serverName } : {},
240
+ serverVersion
241
+ });
201
242
  if (additionalTools) {
202
243
  const { solvaPay, productRef, resourceUri } = descriptorOptions;
203
244
  const registerPayable = (name, opts) => {
204
245
  registerPayableTool(server, name, {
205
246
  solvaPay,
206
- resourceUri,
207
247
  ...opts,
208
248
  product: opts.product ?? productRef,
209
- buildBootstrap: opts.buildBootstrap ?? buildBootstrapPayload
249
+ buildBootstrap: opts.buildBootstrap ?? descriptors.buildBootstrapPayload
210
250
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
211
251
  });
212
252
  };
213
253
  additionalTools({ server, solvaPay, resourceUri, productRef, registerPayable });
214
254
  }
255
+ (0, import_mcp_core.applyHideToolsByAudience)(server, hideToolsByAudience);
215
256
  return server;
216
257
  }
217
258
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.d.cts CHANGED
@@ -9,12 +9,19 @@ import { SolvaPay } from '@solvapay/server';
9
9
  * a paywall-protected MCP tool on the official `@modelcontextprotocol/sdk`
10
10
  * `McpServer`.
11
11
  *
12
- * Always advertises `_meta.ui.resourceUri` at the descriptor level so
13
- * descriptor-reading hosts (MCPJam's `ResultsPanel`, MCP App inspector)
14
- * learn the widget exists and open the MCP App iframe when a paywall or
15
- * nudge response lands. `buildPayableHandler` stamps the same metadata
16
- * on the result envelope as a secondary signal for hosts that key off
17
- * tool-call results (Claude Desktop, mcp-ui, ChatGPT Apps).
12
+ * Payable data tools do NOT advertise `_meta.ui.resourceUri` at the
13
+ * descriptor level by default. Per SEP-1865 / MCP Apps (2026-01-26),
14
+ * descriptor-advertising means the host MUST open the iframe on every
15
+ * call so auto-stamping would flash an empty widget next to every
16
+ * successful `search_knowledge` / `predict_direction` result. Paywall
17
+ * / nudge / activation responses are text-only narrations instead,
18
+ * with the recovery intent tool (`upgrade` / `topup` / `activate_plan`)
19
+ * named in `content[0].text` and `checkoutUrl` inlined for
20
+ * terminal-first hosts.
21
+ *
22
+ * Merchants who deliberately want the widget opened on every call
23
+ * (e.g. the tool's UX genuinely is the iframe — rare) can opt in with
24
+ * `meta: { ui: { resourceUri } }`.
18
25
  *
19
26
  * Mirrors the positional-`name` shape of `registerAppTool` to keep the
20
27
  * convention consistent across the ecosystem.
@@ -30,11 +37,6 @@ type InferHandlerArgs<InputSchema> = [InputSchema] extends [undefined] ? Record<
30
37
  interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | AnySchema | undefined = undefined, TData = unknown> {
31
38
  /** The initialised SolvaPay instance used to build `payable({ product }).mcp(handler)`. */
32
39
  solvaPay: SolvaPay;
33
- /**
34
- * UI resource URI the MCP host should open to render the paywall view.
35
- * Typically `'ui://<app>/<resource>.html'`.
36
- */
37
- resourceUri: string;
38
40
  /** Zod-compatible input schema (raw shape or discriminated schema). */
39
41
  schema?: InputSchema;
40
42
  /** SolvaPay product ref to protect this tool against. */
@@ -55,8 +57,8 @@ interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | Any
55
57
  * - `ctx.product` — bootstrap product projection.
56
58
  * - `ctx.respond(data, options?)` — return an envelope. `options`
57
59
  * carries `text` (override `content[0].text`), `nudge` (inline
58
- * upsell strip), and the reserved `units` (V1.1 variable billing —
59
- * V1 silently ignores).
60
+ * text-suffix upsell copy), and the reserved `units` (V1.1
61
+ * variable billing — V1 silently ignores).
60
62
  * - `ctx.gate(reason?)` — stops handler execution and emits a
61
63
  * paywall response through the adapter's `formatGate` channel.
62
64
  * Rare — the SDK normally fires the paywall automatically via
@@ -70,10 +72,10 @@ interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | Any
70
72
  */
71
73
  handler: PayableHandler<InferHandlerArgs<InputSchema>, TData>;
72
74
  /**
73
- * Builds the full `BootstrapPayload` embedded on paywall results so
74
- * the React shell renders the paywall view directly from the gate
75
- * response. Wire from
76
- * `buildSolvaPayDescriptors(...).buildBootstrapPayload`.
75
+ * Builds the full `BootstrapPayload`. Accepted for forward
76
+ * compatibility with intent-tool reuse, but the text-only payable
77
+ * branch does NOT invoke it — gate responses ride through as
78
+ * `structuredContent = gate` + `content[0].text = gate.message`.
77
79
  */
78
80
  buildBootstrap?: BuildBootstrapPayloadFn;
79
81
  /**
@@ -85,12 +87,12 @@ interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | Any
85
87
  * Additional `_meta` merged onto the tool **descriptor** (the tool
86
88
  * advertisement returned by `tools/list`).
87
89
  *
88
- * `registerPayableTool` always injects `ui.resourceUri` at the
89
- * descriptor level so hosts that read widget metadata from
90
- * `tools/list` (MCPJam's `ResultsPanel` reads
91
- * `toolMeta.ui.resourceUri` from the tool definition) can open the
92
- * MCP App iframe when a paywall/nudge response lands. Merchant
93
- * `meta.ui.resourceUri` overrides the default if supplied.
90
+ * `registerPayableTool` does NOT inject `ui.resourceUri` by default:
91
+ * per SEP-1865 descriptor-advertising means hosts MUST open the
92
+ * iframe on every call, so auto-stamping produced empty widgets on
93
+ * silent success. Merchants who want the widget opened for every
94
+ * call can opt in explicitly via
95
+ * `meta: { ui: { resourceUri: 'ui://...' } }`.
94
96
  */
95
97
  meta?: Record<string, unknown>;
96
98
  /**
@@ -105,9 +107,7 @@ interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | Any
105
107
  * Brand icons surfaced on `tools/list`. Hosts that read tool
106
108
  * metadata for the chrome strip (ChatGPT, Claude Desktop) swap the
107
109
  * default placeholder for this asset. Pass a square logomark for
108
- * best results. Merchants typically share one `icons[]` across
109
- * every tool — consider a single branding source at the server
110
- * level.
110
+ * best results.
111
111
  */
112
112
  icons?: SolvaPayToolIcon[];
113
113
  }
@@ -122,9 +122,10 @@ declare function registerPayableTool<InputSchema extends ZodRawShapeCompat | Any
122
122
  * fresh `McpServer` from the official `@modelcontextprotocol/sdk`,
123
123
  * plus the UI resource the `open_*` tools reference.
124
124
  *
125
- * Internals are a thin mapper over `buildSolvaPayDescriptors` from
126
- * `@solvapay/mcp-core` this package is the only one importing
127
- * `@modelcontextprotocol/*`.
125
+ * Internals delegate to `internal/buildMcpServer` (shared with the
126
+ * `./fetch` subpath entry) so the two factories register the same 11
127
+ * tools in the same order off the same `buildSolvaPayDescriptors`
128
+ * bundle without duplicating the registration loop.
128
129
  */
129
130
 
130
131
  /**
@@ -143,7 +144,7 @@ interface AdditionalToolsContext {
143
144
  * Zod `schema` flows through to the handler's `args` parameter so
144
145
  * merchants get inferred arg types without a second declaration.
145
146
  */
146
- registerPayable: <InputSchema extends ZodRawShapeCompat | AnySchema | undefined = undefined, TData = unknown>(name: string, options: Omit<RegisterPayableToolOptions<InputSchema, TData>, 'solvaPay' | 'resourceUri' | 'product'> & {
147
+ registerPayable: <InputSchema extends ZodRawShapeCompat | AnySchema | undefined = undefined, TData = unknown>(name: string, options: Omit<RegisterPayableToolOptions<InputSchema, TData>, 'solvaPay' | 'product'> & {
147
148
  product?: string;
148
149
  }) => void;
149
150
  }
@@ -171,6 +172,21 @@ interface CreateSolvaPayMcpServerOptions extends BuildSolvaPayDescriptorsOptions
171
172
  serverName?: string;
172
173
  /** Overrides the default `McpServer` version. */
173
174
  serverVersion?: string;
175
+ /**
176
+ * After registration, wrap the `tools/list` handler to drop any
177
+ * tool whose `_meta.audience` matches one of these values. The
178
+ * tools stay `enabled: true` so `tools/call` still reaches their
179
+ * handlers — this option only affects the `tools/list` response
180
+ * shape. Pass `['ui']` when deploying to a text-host MCP client
181
+ * (Claude Desktop, MCPJam, ChatGPT connectors) that won't embed
182
+ * the SolvaPay iframe surface, so the LLM's tool catalogue only
183
+ * surfaces the intent tools (`upgrade` / `manage_account` /
184
+ * `activate_plan` / `topup`) and merchant-registered data tools.
185
+ * The hidden transport tools (`create_payment_intent`, etc.) stay
186
+ * callable so the iframe can still invoke them for server-side
187
+ * work.
188
+ */
189
+ hideToolsByAudience?: string[];
174
190
  }
175
191
  /**
176
192
  * Build the MCP server and register the full SolvaPay tool surface.
package/dist/index.d.ts CHANGED
@@ -9,12 +9,19 @@ import { SolvaPay } from '@solvapay/server';
9
9
  * a paywall-protected MCP tool on the official `@modelcontextprotocol/sdk`
10
10
  * `McpServer`.
11
11
  *
12
- * Always advertises `_meta.ui.resourceUri` at the descriptor level so
13
- * descriptor-reading hosts (MCPJam's `ResultsPanel`, MCP App inspector)
14
- * learn the widget exists and open the MCP App iframe when a paywall or
15
- * nudge response lands. `buildPayableHandler` stamps the same metadata
16
- * on the result envelope as a secondary signal for hosts that key off
17
- * tool-call results (Claude Desktop, mcp-ui, ChatGPT Apps).
12
+ * Payable data tools do NOT advertise `_meta.ui.resourceUri` at the
13
+ * descriptor level by default. Per SEP-1865 / MCP Apps (2026-01-26),
14
+ * descriptor-advertising means the host MUST open the iframe on every
15
+ * call so auto-stamping would flash an empty widget next to every
16
+ * successful `search_knowledge` / `predict_direction` result. Paywall
17
+ * / nudge / activation responses are text-only narrations instead,
18
+ * with the recovery intent tool (`upgrade` / `topup` / `activate_plan`)
19
+ * named in `content[0].text` and `checkoutUrl` inlined for
20
+ * terminal-first hosts.
21
+ *
22
+ * Merchants who deliberately want the widget opened on every call
23
+ * (e.g. the tool's UX genuinely is the iframe — rare) can opt in with
24
+ * `meta: { ui: { resourceUri } }`.
18
25
  *
19
26
  * Mirrors the positional-`name` shape of `registerAppTool` to keep the
20
27
  * convention consistent across the ecosystem.
@@ -30,11 +37,6 @@ type InferHandlerArgs<InputSchema> = [InputSchema] extends [undefined] ? Record<
30
37
  interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | AnySchema | undefined = undefined, TData = unknown> {
31
38
  /** The initialised SolvaPay instance used to build `payable({ product }).mcp(handler)`. */
32
39
  solvaPay: SolvaPay;
33
- /**
34
- * UI resource URI the MCP host should open to render the paywall view.
35
- * Typically `'ui://<app>/<resource>.html'`.
36
- */
37
- resourceUri: string;
38
40
  /** Zod-compatible input schema (raw shape or discriminated schema). */
39
41
  schema?: InputSchema;
40
42
  /** SolvaPay product ref to protect this tool against. */
@@ -55,8 +57,8 @@ interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | Any
55
57
  * - `ctx.product` — bootstrap product projection.
56
58
  * - `ctx.respond(data, options?)` — return an envelope. `options`
57
59
  * carries `text` (override `content[0].text`), `nudge` (inline
58
- * upsell strip), and the reserved `units` (V1.1 variable billing —
59
- * V1 silently ignores).
60
+ * text-suffix upsell copy), and the reserved `units` (V1.1
61
+ * variable billing — V1 silently ignores).
60
62
  * - `ctx.gate(reason?)` — stops handler execution and emits a
61
63
  * paywall response through the adapter's `formatGate` channel.
62
64
  * Rare — the SDK normally fires the paywall automatically via
@@ -70,10 +72,10 @@ interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | Any
70
72
  */
71
73
  handler: PayableHandler<InferHandlerArgs<InputSchema>, TData>;
72
74
  /**
73
- * Builds the full `BootstrapPayload` embedded on paywall results so
74
- * the React shell renders the paywall view directly from the gate
75
- * response. Wire from
76
- * `buildSolvaPayDescriptors(...).buildBootstrapPayload`.
75
+ * Builds the full `BootstrapPayload`. Accepted for forward
76
+ * compatibility with intent-tool reuse, but the text-only payable
77
+ * branch does NOT invoke it — gate responses ride through as
78
+ * `structuredContent = gate` + `content[0].text = gate.message`.
77
79
  */
78
80
  buildBootstrap?: BuildBootstrapPayloadFn;
79
81
  /**
@@ -85,12 +87,12 @@ interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | Any
85
87
  * Additional `_meta` merged onto the tool **descriptor** (the tool
86
88
  * advertisement returned by `tools/list`).
87
89
  *
88
- * `registerPayableTool` always injects `ui.resourceUri` at the
89
- * descriptor level so hosts that read widget metadata from
90
- * `tools/list` (MCPJam's `ResultsPanel` reads
91
- * `toolMeta.ui.resourceUri` from the tool definition) can open the
92
- * MCP App iframe when a paywall/nudge response lands. Merchant
93
- * `meta.ui.resourceUri` overrides the default if supplied.
90
+ * `registerPayableTool` does NOT inject `ui.resourceUri` by default:
91
+ * per SEP-1865 descriptor-advertising means hosts MUST open the
92
+ * iframe on every call, so auto-stamping produced empty widgets on
93
+ * silent success. Merchants who want the widget opened for every
94
+ * call can opt in explicitly via
95
+ * `meta: { ui: { resourceUri: 'ui://...' } }`.
94
96
  */
95
97
  meta?: Record<string, unknown>;
96
98
  /**
@@ -105,9 +107,7 @@ interface RegisterPayableToolOptions<InputSchema extends ZodRawShapeCompat | Any
105
107
  * Brand icons surfaced on `tools/list`. Hosts that read tool
106
108
  * metadata for the chrome strip (ChatGPT, Claude Desktop) swap the
107
109
  * default placeholder for this asset. Pass a square logomark for
108
- * best results. Merchants typically share one `icons[]` across
109
- * every tool — consider a single branding source at the server
110
- * level.
110
+ * best results.
111
111
  */
112
112
  icons?: SolvaPayToolIcon[];
113
113
  }
@@ -122,9 +122,10 @@ declare function registerPayableTool<InputSchema extends ZodRawShapeCompat | Any
122
122
  * fresh `McpServer` from the official `@modelcontextprotocol/sdk`,
123
123
  * plus the UI resource the `open_*` tools reference.
124
124
  *
125
- * Internals are a thin mapper over `buildSolvaPayDescriptors` from
126
- * `@solvapay/mcp-core` this package is the only one importing
127
- * `@modelcontextprotocol/*`.
125
+ * Internals delegate to `internal/buildMcpServer` (shared with the
126
+ * `./fetch` subpath entry) so the two factories register the same 11
127
+ * tools in the same order off the same `buildSolvaPayDescriptors`
128
+ * bundle without duplicating the registration loop.
128
129
  */
129
130
 
130
131
  /**
@@ -143,7 +144,7 @@ interface AdditionalToolsContext {
143
144
  * Zod `schema` flows through to the handler's `args` parameter so
144
145
  * merchants get inferred arg types without a second declaration.
145
146
  */
146
- registerPayable: <InputSchema extends ZodRawShapeCompat | AnySchema | undefined = undefined, TData = unknown>(name: string, options: Omit<RegisterPayableToolOptions<InputSchema, TData>, 'solvaPay' | 'resourceUri' | 'product'> & {
147
+ registerPayable: <InputSchema extends ZodRawShapeCompat | AnySchema | undefined = undefined, TData = unknown>(name: string, options: Omit<RegisterPayableToolOptions<InputSchema, TData>, 'solvaPay' | 'product'> & {
147
148
  product?: string;
148
149
  }) => void;
149
150
  }
@@ -171,6 +172,21 @@ interface CreateSolvaPayMcpServerOptions extends BuildSolvaPayDescriptorsOptions
171
172
  serverName?: string;
172
173
  /** Overrides the default `McpServer` version. */
173
174
  serverVersion?: string;
175
+ /**
176
+ * After registration, wrap the `tools/list` handler to drop any
177
+ * tool whose `_meta.audience` matches one of these values. The
178
+ * tools stay `enabled: true` so `tools/call` still reaches their
179
+ * handlers — this option only affects the `tools/list` response
180
+ * shape. Pass `['ui']` when deploying to a text-host MCP client
181
+ * (Claude Desktop, MCPJam, ChatGPT connectors) that won't embed
182
+ * the SolvaPay iframe surface, so the LLM's tool catalogue only
183
+ * surfaces the intent tools (`upgrade` / `manage_account` /
184
+ * `activate_plan` / `topup`) and merchant-registered data tools.
185
+ * The hidden transport tools (`create_payment_intent`, etc.) stay
186
+ * callable so the iframe can still invoke them for server-side
187
+ * work.
188
+ */
189
+ hideToolsByAudience?: string[];
174
190
  }
175
191
  /**
176
192
  * Build the MCP server and register the full SolvaPay tool surface.