@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/README.md +35 -9
- package/dist/chunk-3VDAADZU.js +211 -0
- package/dist/express/index.cjs +504 -0
- package/dist/express/index.d.cts +65 -0
- package/dist/express/index.d.ts +65 -0
- package/dist/express/index.js +481 -0
- package/dist/fetch/index.cjs +787 -0
- package/dist/fetch/index.d.cts +238 -0
- package/dist/fetch/index.d.ts +238 -0
- package/dist/fetch/index.js +565 -0
- package/dist/index.cjs +116 -75
- package/dist/index.d.cts +46 -30
- package/dist/index.d.ts +46 -30
- package/dist/index.js +14 -171
- package/package.json +16 -7
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/
|
|
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,
|
|
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
|
|
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
|
|
98
|
+
const descriptors = (0, import_mcp_core.buildSolvaPayDescriptors)(descriptorOptions);
|
|
157
99
|
const effectiveServerName = serverName ?? descriptorOptions.branding?.brandName ?? "solvapay-mcp-server";
|
|
158
|
-
const
|
|
159
|
-
|
|
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
|
-
|
|
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:
|
|
125
|
+
mimeType: import_server.RESOURCE_MIME_TYPE,
|
|
178
126
|
_meta: {
|
|
179
127
|
ui: {
|
|
180
128
|
csp: resource.csp,
|
|
181
|
-
|
|
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:
|
|
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:
|
|
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
|
-
*
|
|
13
|
-
* descriptor
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
|
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
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* `
|
|
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`
|
|
89
|
-
* descriptor
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* `meta
|
|
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.
|
|
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
|
|
126
|
-
*
|
|
127
|
-
*
|
|
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' | '
|
|
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
|
-
*
|
|
13
|
-
* descriptor
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
|
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
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* `
|
|
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`
|
|
89
|
-
* descriptor
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* `meta
|
|
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.
|
|
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
|
|
126
|
-
*
|
|
127
|
-
*
|
|
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' | '
|
|
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.
|