@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.
@@ -0,0 +1,787 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/fetch/index.ts
21
+ var fetch_exports = {};
22
+ __export(fetch_exports, {
23
+ McpBearerAuthError: () => import_mcp_core6.McpBearerAuthError,
24
+ applyNativeCors: () => applyNativeCors,
25
+ authChallenge: () => authChallenge,
26
+ buildAuthInfoFromBearer: () => import_mcp_core6.buildAuthInfoFromBearer,
27
+ corsPreflight: () => corsPreflight,
28
+ createAuthorizationServerHandler: () => createAuthorizationServerHandler,
29
+ createOAuthAuthorizeHandler: () => createOAuthAuthorizeHandler,
30
+ createOAuthFetchRouter: () => createOAuthFetchRouter,
31
+ createOAuthRegisterHandler: () => createOAuthRegisterHandler,
32
+ createOAuthRevokeHandler: () => createOAuthRevokeHandler,
33
+ createOAuthTokenHandler: () => createOAuthTokenHandler,
34
+ createOpenidNotFoundHandler: () => createOpenidNotFoundHandler,
35
+ createProtectedResourceHandler: () => createProtectedResourceHandler,
36
+ createSolvaPayMcpFetch: () => createSolvaPayMcpFetch,
37
+ createSolvaPayMcpFetchHandler: () => createSolvaPayMcpFetchHandler,
38
+ getOAuthAuthorizationServerResponse: () => import_mcp_core6.getOAuthAuthorizationServerResponse,
39
+ getOAuthProtectedResourceResponse: () => import_mcp_core6.getOAuthProtectedResourceResponse,
40
+ isNativeClientOrigin: () => isNativeClientOrigin,
41
+ resolveBearer: () => resolveBearer
42
+ });
43
+ module.exports = __toCommonJS(fetch_exports);
44
+
45
+ // src/fetch/oauth-bridge.ts
46
+ var import_mcp_core2 = require("@solvapay/mcp-core");
47
+
48
+ // src/fetch/cors.ts
49
+ var import_mcp_core = require("@solvapay/mcp-core");
50
+ var NATIVE_CLIENT_ORIGIN_REGEX = /^(cursor|vscode|vscode-webview|claude):\/\/.+$/;
51
+ function isNativeClientOrigin(origin) {
52
+ if (!origin) return false;
53
+ return NATIVE_CLIENT_ORIGIN_REGEX.test(origin);
54
+ }
55
+ function applyNativeCors(reqHeaders, resHeaders) {
56
+ const origin = reqHeaders.get("origin");
57
+ if (!origin) return;
58
+ if (isNativeClientOrigin(origin)) {
59
+ resHeaders.set("Access-Control-Allow-Origin", origin);
60
+ resHeaders.append("Vary", "Origin");
61
+ }
62
+ }
63
+ function corsPreflight(req) {
64
+ const reqHeaders = req.headers;
65
+ const requestedMethod = reqHeaders.get("access-control-request-method") ?? "POST";
66
+ const requestedHeaders = reqHeaders.get("access-control-request-headers") ?? "authorization, content-type";
67
+ const headers = new Headers();
68
+ applyNativeCors(reqHeaders, headers);
69
+ headers.set("Access-Control-Allow-Methods", `${requestedMethod}, OPTIONS`);
70
+ headers.set("Access-Control-Allow-Headers", requestedHeaders);
71
+ headers.set("Access-Control-Max-Age", "600");
72
+ return new Response(null, { status: 204, headers });
73
+ }
74
+ function authChallenge(req, options) {
75
+ const {
76
+ publicBaseUrl,
77
+ protectedResourcePath = "/.well-known/oauth-protected-resource",
78
+ jsonRpcId = null
79
+ } = options;
80
+ const headers = new Headers();
81
+ applyNativeCors(req.headers, headers);
82
+ headers.set("Access-Control-Expose-Headers", "WWW-Authenticate");
83
+ headers.set(
84
+ "WWW-Authenticate",
85
+ `Bearer resource_metadata="${(0, import_mcp_core.withoutTrailingSlash)(publicBaseUrl)}${protectedResourcePath}"`
86
+ );
87
+ headers.set("Content-Type", "application/json");
88
+ const body = {
89
+ jsonrpc: "2.0",
90
+ id: jsonRpcId,
91
+ error: { code: -32001, message: "Unauthorized" }
92
+ };
93
+ return new Response(JSON.stringify(body), { status: 401, headers });
94
+ }
95
+ function resolveBearer(req) {
96
+ const header = req.headers.get("authorization");
97
+ if (!header) return null;
98
+ const match = /^\s*Bearer\s+(.+?)\s*$/i.exec(header);
99
+ return match ? match[1] : null;
100
+ }
101
+
102
+ // src/fetch/oauth-bridge.ts
103
+ function hasOAuthErrorShape(body) {
104
+ return body !== null && typeof body === "object" && typeof body.error === "string";
105
+ }
106
+ function extractZodErrors(body) {
107
+ const errs = body.errors;
108
+ if (!Array.isArray(errs)) return [];
109
+ return errs.filter((e) => !!e && typeof e === "object");
110
+ }
111
+ function deriveOAuthErrorCode(status, nestBody) {
112
+ if (status === 401 || status === 403) return "invalid_client";
113
+ if (status >= 500) return "server_error";
114
+ const zodErrors = extractZodErrors(nestBody);
115
+ const touches = (field) => zodErrors.some((e) => {
116
+ const path = e.path;
117
+ return Array.isArray(path) && path.includes(field);
118
+ });
119
+ if (touches("grant_type")) {
120
+ const grantTypeErr = zodErrors.find((e) => {
121
+ const path = e.path;
122
+ return Array.isArray(path) && path.includes("grant_type");
123
+ });
124
+ const received = grantTypeErr && grantTypeErr.received;
125
+ if (received !== "undefined" && received !== void 0 && received !== "") {
126
+ return "unsupported_grant_type";
127
+ }
128
+ return "invalid_request";
129
+ }
130
+ if (touches("code") || touches("refresh_token")) return "invalid_grant";
131
+ if (touches("scope")) return "invalid_scope";
132
+ if (touches("client_id") || touches("client_secret")) return "invalid_client";
133
+ return "invalid_request";
134
+ }
135
+ function buildErrorDescription(nestBody) {
136
+ const zodErrors = extractZodErrors(nestBody);
137
+ if (zodErrors.length > 0) {
138
+ const parts = zodErrors.map((e) => {
139
+ const path = e.path;
140
+ const message2 = e.message;
141
+ const pathStr = Array.isArray(path) ? path.filter((p) => typeof p === "string").join(".") : "";
142
+ const msgStr = typeof message2 === "string" ? message2 : "";
143
+ if (pathStr && msgStr) return `${pathStr}: ${msgStr}`;
144
+ return pathStr || msgStr;
145
+ }).filter(Boolean);
146
+ if (parts.length > 0) return parts.join("; ");
147
+ }
148
+ const message = nestBody.message;
149
+ if (typeof message === "string") return message;
150
+ if (Array.isArray(message)) {
151
+ const strings = message.filter((m) => typeof m === "string");
152
+ if (strings.length > 0) return strings.join("; ");
153
+ }
154
+ return void 0;
155
+ }
156
+ function toOAuthErrorBody(body, text, status) {
157
+ if (hasOAuthErrorShape(body)) return body;
158
+ if (body && typeof body === "object") {
159
+ const nestBody = body;
160
+ const error = deriveOAuthErrorCode(status, nestBody);
161
+ const error_description = buildErrorDescription(nestBody);
162
+ return error_description ? { error, error_description } : { error };
163
+ }
164
+ const fallbackError = status >= 500 ? "server_error" : "invalid_request";
165
+ const description = typeof text === "string" && text.length > 0 && text.length < 500 ? text : void 0;
166
+ return description ? { error: fallbackError, error_description: description } : { error: fallbackError };
167
+ }
168
+ async function parseUpstreamJson(response) {
169
+ const text = await response.text();
170
+ if (!text) return { body: {}, text: "" };
171
+ try {
172
+ return { body: JSON.parse(text), text };
173
+ } catch {
174
+ return { body: text, text };
175
+ }
176
+ }
177
+ function upstreamUnreachable(req) {
178
+ const headers = new Headers({ "content-type": "application/json" });
179
+ applyNativeCors(req.headers, headers);
180
+ return new Response(JSON.stringify({ error: "upstream_unreachable" }), { status: 502, headers });
181
+ }
182
+ function corsResponse(req, response) {
183
+ const headers = new Headers(response.headers);
184
+ applyNativeCors(req.headers, headers);
185
+ return new Response(response.body, { status: response.status, headers });
186
+ }
187
+ function jsonResponse(req, status, body) {
188
+ const headers = new Headers({ "content-type": "application/json" });
189
+ applyNativeCors(req.headers, headers);
190
+ return new Response(JSON.stringify(body), { status, headers });
191
+ }
192
+ function emptyResponse(req, status) {
193
+ const headers = new Headers();
194
+ applyNativeCors(req.headers, headers);
195
+ return new Response(null, { status, headers });
196
+ }
197
+ function pathOf(req) {
198
+ return new URL(req.url).pathname;
199
+ }
200
+ function queryOf(req) {
201
+ const search = new URL(req.url).search;
202
+ return search || "";
203
+ }
204
+ function createProtectedResourceHandler(options) {
205
+ const path = options.protectedResourcePath ?? "/.well-known/oauth-protected-resource";
206
+ return async (req) => {
207
+ if (req.method !== "GET" || pathOf(req) !== path) return null;
208
+ return jsonResponse(req, 200, (0, import_mcp_core2.getOAuthProtectedResourceResponse)(options.publicBaseUrl));
209
+ };
210
+ }
211
+ function createAuthorizationServerHandler(options) {
212
+ const path = options.authorizationServerPath ?? "/.well-known/oauth-authorization-server";
213
+ const resolvedPaths = (0, import_mcp_core2.resolveOAuthPaths)(options.paths);
214
+ return async (req) => {
215
+ if (req.method !== "GET" || pathOf(req) !== path) return null;
216
+ if (!options.productRef) {
217
+ return jsonResponse(req, 500, { error: "SOLVAPAY_PRODUCT_REF missing" });
218
+ }
219
+ return jsonResponse(
220
+ req,
221
+ 200,
222
+ (0, import_mcp_core2.getOAuthAuthorizationServerResponse)({
223
+ publicBaseUrl: options.publicBaseUrl,
224
+ paths: resolvedPaths
225
+ })
226
+ );
227
+ };
228
+ }
229
+ function createOpenidNotFoundHandler() {
230
+ return async (req) => {
231
+ if (req.method !== "GET" || pathOf(req) !== "/.well-known/openid-configuration") return null;
232
+ return emptyResponse(req, 404);
233
+ };
234
+ }
235
+ function createOAuthRegisterHandler(options) {
236
+ const path = options.path ?? "/oauth/register";
237
+ const api = (0, import_mcp_core2.withoutTrailingSlash)(options.apiBaseUrl);
238
+ const upstream = `${api}/v1/customer/auth/register?product_ref=${encodeURIComponent(options.productRef)}`;
239
+ return async (req) => {
240
+ if (pathOf(req) !== path) return null;
241
+ if (req.method === "OPTIONS") return corsPreflight(req);
242
+ if (req.method !== "POST") return null;
243
+ const body = await req.text();
244
+ try {
245
+ const upstreamResponse = await fetch(upstream, {
246
+ method: "POST",
247
+ headers: { "content-type": req.headers.get("content-type") ?? "application/json" },
248
+ body
249
+ });
250
+ return corsResponse(req, upstreamResponse);
251
+ } catch {
252
+ return upstreamUnreachable(req);
253
+ }
254
+ };
255
+ }
256
+ function createOAuthAuthorizeHandler(options) {
257
+ const path = options.path ?? "/oauth/authorize";
258
+ const api = (0, import_mcp_core2.withoutTrailingSlash)(options.apiBaseUrl);
259
+ return async (req) => {
260
+ if (pathOf(req) !== path) return null;
261
+ if (req.method === "OPTIONS") return corsPreflight(req);
262
+ if (req.method !== "GET") return null;
263
+ const query = queryOf(req);
264
+ const location = `${api}/v1/customer/auth/authorize${query}`;
265
+ const headers = new Headers({ Location: location });
266
+ applyNativeCors(req.headers, headers);
267
+ return new Response(null, { status: 302, headers });
268
+ };
269
+ }
270
+ async function proxyFormEndpoint(req, upstreamUrl, normalizeErrors) {
271
+ const rawBody = await req.text();
272
+ const contentType = req.headers.get("content-type") ?? "application/x-www-form-urlencoded";
273
+ const headers = { "content-type": contentType };
274
+ const authorization = req.headers.get("authorization");
275
+ if (authorization) headers.authorization = authorization;
276
+ try {
277
+ const upstreamResponse = await fetch(upstreamUrl, {
278
+ method: "POST",
279
+ headers,
280
+ body: rawBody
281
+ });
282
+ if (!normalizeErrors || upstreamResponse.ok || upstreamResponse.status === 204) {
283
+ return corsResponse(req, upstreamResponse);
284
+ }
285
+ const { body, text } = await parseUpstreamJson(upstreamResponse);
286
+ const normalized = toOAuthErrorBody(body, text, upstreamResponse.status);
287
+ return jsonResponse(req, upstreamResponse.status, normalized);
288
+ } catch {
289
+ return upstreamUnreachable(req);
290
+ }
291
+ }
292
+ function createOAuthTokenHandler(options) {
293
+ const path = options.path ?? "/oauth/token";
294
+ const upstream = `${(0, import_mcp_core2.withoutTrailingSlash)(options.apiBaseUrl)}/v1/customer/auth/token`;
295
+ return async (req) => {
296
+ if (pathOf(req) !== path) return null;
297
+ if (req.method === "OPTIONS") return corsPreflight(req);
298
+ if (req.method !== "POST") return null;
299
+ return proxyFormEndpoint(
300
+ req,
301
+ upstream,
302
+ /* normalizeErrors */
303
+ true
304
+ );
305
+ };
306
+ }
307
+ function createOAuthRevokeHandler(options) {
308
+ const path = options.path ?? "/oauth/revoke";
309
+ const upstream = `${(0, import_mcp_core2.withoutTrailingSlash)(options.apiBaseUrl)}/v1/customer/auth/revoke`;
310
+ return async (req) => {
311
+ if (pathOf(req) !== path) return null;
312
+ if (req.method === "OPTIONS") return corsPreflight(req);
313
+ if (req.method !== "POST") return null;
314
+ return proxyFormEndpoint(
315
+ req,
316
+ upstream,
317
+ /* normalizeErrors */
318
+ true
319
+ );
320
+ };
321
+ }
322
+ function createOAuthFetchRouter(options) {
323
+ const paths = (0, import_mcp_core2.resolveOAuthPaths)(options.oauthPaths);
324
+ const handlers = [
325
+ createOpenidNotFoundHandler(),
326
+ createProtectedResourceHandler({
327
+ publicBaseUrl: options.publicBaseUrl,
328
+ protectedResourcePath: options.protectedResourcePath
329
+ }),
330
+ createAuthorizationServerHandler({
331
+ publicBaseUrl: options.publicBaseUrl,
332
+ authorizationServerPath: options.authorizationServerPath,
333
+ paths,
334
+ productRef: options.productRef
335
+ }),
336
+ createOAuthRegisterHandler({
337
+ apiBaseUrl: options.apiBaseUrl,
338
+ productRef: options.productRef,
339
+ path: paths.register
340
+ }),
341
+ createOAuthAuthorizeHandler({ apiBaseUrl: options.apiBaseUrl, path: paths.authorize }),
342
+ createOAuthTokenHandler({ apiBaseUrl: options.apiBaseUrl, path: paths.token }),
343
+ createOAuthRevokeHandler({ apiBaseUrl: options.apiBaseUrl, path: paths.revoke })
344
+ ];
345
+ return async (req) => {
346
+ for (const handler of handlers) {
347
+ const response = await handler(req);
348
+ if (response) return response;
349
+ }
350
+ return null;
351
+ };
352
+ }
353
+
354
+ // src/fetch/handler.ts
355
+ var import_mcp_core3 = require("@solvapay/mcp-core");
356
+ var import_webStandardStreamableHttp = require("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
357
+ function defaultSessionIdGenerator() {
358
+ const c = globalThis.crypto;
359
+ if (c?.randomUUID) return c.randomUUID();
360
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (ch) => {
361
+ const r = Math.floor(Math.random() * 16);
362
+ const v = ch === "x" ? r : r & 3 | 8;
363
+ return v.toString(16);
364
+ });
365
+ }
366
+ function getJsonRpcId(body) {
367
+ if (body && typeof body === "object" && "id" in body) {
368
+ const id = body.id;
369
+ return id ?? null;
370
+ }
371
+ return null;
372
+ }
373
+ async function readJsonRpcId(req) {
374
+ try {
375
+ const clone = req.clone();
376
+ const body = await clone.json();
377
+ return getJsonRpcId(body);
378
+ } catch {
379
+ return null;
380
+ }
381
+ }
382
+ function createSolvaPayMcpFetchHandler(options) {
383
+ const {
384
+ server,
385
+ publicBaseUrl,
386
+ apiBaseUrl,
387
+ productRef,
388
+ mcpPath = "/mcp",
389
+ requireAuth = true,
390
+ authInfo,
391
+ protectedResourcePath,
392
+ authorizationServerPath,
393
+ oauthPaths,
394
+ mode = "sse-stateful",
395
+ buildTransport,
396
+ sessionIdGenerator
397
+ } = options;
398
+ const oauthRouter = createOAuthFetchRouter({
399
+ publicBaseUrl,
400
+ apiBaseUrl,
401
+ productRef,
402
+ protectedResourcePath,
403
+ authorizationServerPath,
404
+ oauthPaths
405
+ });
406
+ const makeTransport = () => {
407
+ if (buildTransport) return buildTransport();
408
+ if (mode === "json-stateless") {
409
+ return new import_webStandardStreamableHttp.WebStandardStreamableHTTPServerTransport({
410
+ sessionIdGenerator: void 0,
411
+ enableJsonResponse: true
412
+ });
413
+ }
414
+ if (mode === "sse-stateless") {
415
+ return new import_webStandardStreamableHttp.WebStandardStreamableHTTPServerTransport({
416
+ sessionIdGenerator: void 0
417
+ });
418
+ }
419
+ return new import_webStandardStreamableHttp.WebStandardStreamableHTTPServerTransport({
420
+ sessionIdGenerator: sessionIdGenerator ?? defaultSessionIdGenerator
421
+ });
422
+ };
423
+ let serverMutex = Promise.resolve();
424
+ return async (req) => {
425
+ const url = new URL(req.url);
426
+ const pathname = url.pathname;
427
+ if (req.method === "OPTIONS" && pathname === mcpPath) {
428
+ return corsPreflight(req);
429
+ }
430
+ const oauthResponse = await oauthRouter(req);
431
+ if (oauthResponse) return oauthResponse;
432
+ if (pathname !== mcpPath) {
433
+ return new Response("not_found", { status: 404 });
434
+ }
435
+ if (req.method && req.method !== "POST" && req.method !== "OPTIONS") {
436
+ const headers = new Headers({ Allow: "POST, OPTIONS" });
437
+ applyNativeCors(req.headers, headers);
438
+ return new Response(null, { status: 405, headers });
439
+ }
440
+ const authHeader = req.headers.get("authorization");
441
+ let resolvedAuthInfo = null;
442
+ if (authHeader || requireAuth) {
443
+ try {
444
+ resolvedAuthInfo = (0, import_mcp_core3.buildAuthInfoFromBearer)(authHeader, authInfo);
445
+ if (!resolvedAuthInfo) {
446
+ throw new import_mcp_core3.McpBearerAuthError("Missing bearer token");
447
+ }
448
+ } catch {
449
+ const jsonRpcId = await readJsonRpcId(req);
450
+ return authChallenge(req, {
451
+ publicBaseUrl,
452
+ protectedResourcePath,
453
+ jsonRpcId
454
+ });
455
+ }
456
+ }
457
+ const previous = serverMutex;
458
+ let releaseMutex = () => {
459
+ };
460
+ serverMutex = new Promise((resolve) => {
461
+ releaseMutex = resolve;
462
+ });
463
+ await previous;
464
+ const transport = makeTransport();
465
+ try {
466
+ await server.connect(transport);
467
+ const response = await transport.handleRequest(
468
+ req,
469
+ resolvedAuthInfo ? {
470
+ // `AuthInfo` from the SDK is structurally identical to our
471
+ // envelope — cast away the brand so the types line up.
472
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
473
+ authInfo: resolvedAuthInfo
474
+ } : void 0
475
+ );
476
+ const merged = new Headers(response.headers);
477
+ applyNativeCors(req.headers, merged);
478
+ return new Response(response.body, { status: response.status, headers: merged });
479
+ } catch (error) {
480
+ const headers = new Headers({ "content-type": "application/json" });
481
+ applyNativeCors(req.headers, headers);
482
+ const jsonRpcId = await readJsonRpcId(req);
483
+ return new Response(
484
+ JSON.stringify({
485
+ jsonrpc: "2.0",
486
+ id: jsonRpcId,
487
+ error: {
488
+ code: -32603,
489
+ message: error instanceof Error ? error.message : "internal_error"
490
+ }
491
+ }),
492
+ { status: 500, headers }
493
+ );
494
+ } finally {
495
+ await transport.close().catch(() => {
496
+ });
497
+ releaseMutex();
498
+ }
499
+ };
500
+ }
501
+
502
+ // src/internal/buildMcpServer.ts
503
+ var import_server = require("@modelcontextprotocol/ext-apps/server");
504
+ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
505
+ var import_mcp_core4 = require("@solvapay/mcp-core");
506
+ function registerDescriptor(server, tool) {
507
+ const baseMeta = tool.meta ?? {};
508
+ const baseUi = baseMeta.ui ?? {};
509
+ const metaWithIcons = tool.icons && tool.icons.length > 0 ? { ...baseMeta, ui: { ...baseUi, icons: tool.icons } } : baseMeta;
510
+ (0, import_server.registerAppTool)(
511
+ server,
512
+ tool.name,
513
+ {
514
+ ...tool.title !== void 0 ? { title: tool.title } : {},
515
+ description: tool.description,
516
+ inputSchema: tool.inputSchema,
517
+ _meta: metaWithIcons,
518
+ ...tool.annotations !== void 0 ? { annotations: tool.annotations } : {},
519
+ ...tool.icons !== void 0 ? { icons: tool.icons } : {}
520
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
521
+ },
522
+ // `SolvaPayCallToolResult` is a structural subset of the official
523
+ // SDK's `CallToolResult`; cast to erase the extra-narrow `resource`
524
+ // block typing the SDK expects on `{ type: 'resource' }` content.
525
+ async (args, extra) => await tool.handler(
526
+ args,
527
+ extra
528
+ )
529
+ );
530
+ }
531
+ function registerPromptDescriptor(server, prompt) {
532
+ const config = { description: prompt.description };
533
+ if (prompt.title !== void 0) config.title = prompt.title;
534
+ if (prompt.argsSchema !== void 0) config.argsSchema = prompt.argsSchema;
535
+ server.registerPrompt(
536
+ prompt.name,
537
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
538
+ config,
539
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
540
+ async (args) => await prompt.handler(args ?? {})
541
+ );
542
+ }
543
+ function registerDocsResource(server, docs) {
544
+ server.registerResource(
545
+ docs.name,
546
+ docs.uri,
547
+ {
548
+ ...docs.title !== void 0 ? { title: docs.title } : {},
549
+ description: docs.description,
550
+ mimeType: docs.mimeType
551
+ },
552
+ async () => ({
553
+ contents: [
554
+ {
555
+ uri: docs.uri,
556
+ mimeType: docs.mimeType,
557
+ text: await docs.readBody()
558
+ }
559
+ ]
560
+ })
561
+ );
562
+ }
563
+ function buildSolvaPayMcpServer(options) {
564
+ const {
565
+ registerPrompts = true,
566
+ registerDocsResources = true,
567
+ serverName,
568
+ serverVersion = "1.0.0",
569
+ hideToolsByAudience: _hideToolsByAudience,
570
+ ...descriptorOptions
571
+ } = options;
572
+ const descriptors = (0, import_mcp_core4.buildSolvaPayDescriptors)(descriptorOptions);
573
+ const effectiveServerName = serverName ?? descriptorOptions.branding?.brandName ?? "solvapay-mcp-server";
574
+ const serverIcons = (0, import_mcp_core4.deriveIcons)(descriptorOptions.branding);
575
+ const server = new import_mcp.McpServer({
576
+ name: effectiveServerName,
577
+ version: serverVersion,
578
+ ...serverIcons ? { icons: serverIcons } : {}
579
+ });
580
+ for (const tool of descriptors.tools) {
581
+ registerDescriptor(server, tool);
582
+ }
583
+ if (registerPrompts) {
584
+ for (const prompt of descriptors.prompts) {
585
+ registerPromptDescriptor(server, prompt);
586
+ }
587
+ }
588
+ if (registerDocsResources) {
589
+ for (const docs of descriptors.docsResources) {
590
+ registerDocsResource(server, docs);
591
+ }
592
+ }
593
+ const resource = descriptors.resource;
594
+ (0, import_server.registerAppResource)(
595
+ server,
596
+ resource.uri,
597
+ resource.uri,
598
+ {
599
+ mimeType: import_server.RESOURCE_MIME_TYPE,
600
+ _meta: {
601
+ ui: {
602
+ csp: resource.csp,
603
+ // `false` asks the host to skip painting its own outer card /
604
+ // border around the iframe. The widget paints its own frame
605
+ // via `.solvapay-mcp-card`, and `<AppHeader>` renders the
606
+ // merchant mark at the top; a host-painted card on top of
607
+ // that produced a nested-container look (visible on MCP Jam
608
+ // with the earlier `true` default). Hosts that honour the
609
+ // preference (per the MCP Apps spec) now render us flush
610
+ // inside their conversation surface.
611
+ prefersBorder: false
612
+ }
613
+ }
614
+ },
615
+ async () => ({
616
+ contents: [
617
+ {
618
+ uri: resource.uri,
619
+ mimeType: import_server.RESOURCE_MIME_TYPE,
620
+ text: await resource.readHtml(),
621
+ _meta: {
622
+ ui: {
623
+ csp: resource.csp,
624
+ prefersBorder: false
625
+ }
626
+ }
627
+ }
628
+ ]
629
+ })
630
+ );
631
+ return { server, descriptors };
632
+ }
633
+
634
+ // src/registerPayableTool.ts
635
+ var import_server2 = require("@modelcontextprotocol/ext-apps/server");
636
+ var import_mcp_core5 = require("@solvapay/mcp-core");
637
+ function registerPayableTool(server, name, options) {
638
+ const {
639
+ solvaPay,
640
+ schema,
641
+ product,
642
+ title,
643
+ description,
644
+ handler,
645
+ buildBootstrap,
646
+ getCustomerRef,
647
+ meta,
648
+ annotations,
649
+ icons
650
+ } = options;
651
+ const protectedHandler = (0, import_mcp_core5.buildPayableHandler)(
652
+ solvaPay,
653
+ { product, buildBootstrap, getCustomerRef },
654
+ handler
655
+ );
656
+ const baseMeta = meta ?? {};
657
+ const baseUi = baseMeta.ui ?? {};
658
+ const hasIcons = icons !== void 0 && icons.length > 0;
659
+ const mergedUi = {
660
+ ...baseUi,
661
+ ...hasIcons ? { icons } : {}
662
+ };
663
+ const hasUi = Object.keys(mergedUi).length > 0;
664
+ const toolMeta = hasUi ? { ...baseMeta, ui: mergedUi } : { ...baseMeta };
665
+ const effectiveAnnotations = {
666
+ readOnlyHint: true,
667
+ openWorldHint: true,
668
+ ...annotations
669
+ };
670
+ const hasUiResource = hasUi && typeof mergedUi.resourceUri === "string";
671
+ const toolConfig = {
672
+ ...title !== void 0 ? { title } : {},
673
+ ...description !== void 0 ? { description } : {},
674
+ ...schema !== void 0 ? { inputSchema: schema } : {},
675
+ ...Object.keys(toolMeta).length > 0 ? { _meta: toolMeta } : {},
676
+ annotations: effectiveAnnotations,
677
+ ...icons !== void 0 && icons.length > 0 ? { icons } : {}
678
+ };
679
+ const toolCallback = async (args, extra) => await protectedHandler(args, extra);
680
+ if (hasUiResource) {
681
+ return (0, import_server2.registerAppTool)(
682
+ server,
683
+ name,
684
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
685
+ toolConfig,
686
+ toolCallback
687
+ );
688
+ }
689
+ return server.registerTool(
690
+ name,
691
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
692
+ toolConfig,
693
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
694
+ toolCallback
695
+ );
696
+ }
697
+
698
+ // src/fetch/createSolvaPayMcpFetch.ts
699
+ function createSolvaPayMcpFetch(options) {
700
+ const {
701
+ // Descriptor options.
702
+ solvaPay,
703
+ productRef,
704
+ resourceUri,
705
+ htmlPath,
706
+ readHtml,
707
+ publicBaseUrl,
708
+ views,
709
+ csp,
710
+ getCustomerRef,
711
+ onToolCall,
712
+ onToolResult,
713
+ branding,
714
+ // Server / registration options.
715
+ additionalTools,
716
+ hideToolsByAudience,
717
+ registerPrompts = true,
718
+ registerDocsResources = true,
719
+ serverName,
720
+ serverVersion = "1.0.0",
721
+ // Handler options — everything in
722
+ // `CreateSolvaPayMcpFetchHandlerOptions` except `server`.
723
+ ...handlerRest
724
+ } = options;
725
+ const { server, descriptors } = buildSolvaPayMcpServer({
726
+ solvaPay,
727
+ productRef,
728
+ resourceUri,
729
+ ...htmlPath !== void 0 ? { htmlPath } : {},
730
+ ...readHtml !== void 0 ? { readHtml } : {},
731
+ publicBaseUrl,
732
+ ...views !== void 0 ? { views } : {},
733
+ ...csp !== void 0 ? { csp } : {},
734
+ ...getCustomerRef !== void 0 ? { getCustomerRef } : {},
735
+ ...onToolCall !== void 0 ? { onToolCall } : {},
736
+ ...onToolResult !== void 0 ? { onToolResult } : {},
737
+ ...branding !== void 0 ? { branding } : {},
738
+ registerPrompts,
739
+ registerDocsResources,
740
+ ...serverName !== void 0 ? { serverName } : {},
741
+ serverVersion
742
+ });
743
+ if (additionalTools) {
744
+ const registerPayable = (name, opts) => {
745
+ registerPayableTool(server, name, {
746
+ solvaPay,
747
+ ...opts,
748
+ product: opts.product ?? productRef,
749
+ buildBootstrap: opts.buildBootstrap ?? descriptors.buildBootstrapPayload
750
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
751
+ });
752
+ };
753
+ additionalTools({ server, solvaPay, resourceUri, productRef, registerPayable });
754
+ }
755
+ (0, import_mcp_core4.applyHideToolsByAudience)(server, hideToolsByAudience);
756
+ return createSolvaPayMcpFetchHandler({
757
+ server,
758
+ publicBaseUrl,
759
+ productRef,
760
+ ...handlerRest
761
+ });
762
+ }
763
+
764
+ // src/fetch/index.ts
765
+ var import_mcp_core6 = require("@solvapay/mcp-core");
766
+ // Annotate the CommonJS export names for ESM import in node:
767
+ 0 && (module.exports = {
768
+ McpBearerAuthError,
769
+ applyNativeCors,
770
+ authChallenge,
771
+ buildAuthInfoFromBearer,
772
+ corsPreflight,
773
+ createAuthorizationServerHandler,
774
+ createOAuthAuthorizeHandler,
775
+ createOAuthFetchRouter,
776
+ createOAuthRegisterHandler,
777
+ createOAuthRevokeHandler,
778
+ createOAuthTokenHandler,
779
+ createOpenidNotFoundHandler,
780
+ createProtectedResourceHandler,
781
+ createSolvaPayMcpFetch,
782
+ createSolvaPayMcpFetchHandler,
783
+ getOAuthAuthorizationServerResponse,
784
+ getOAuthProtectedResourceResponse,
785
+ isNativeClientOrigin,
786
+ resolveBearer
787
+ });