@dcentralab/d402-client 0.3.4 → 0.3.7

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.mjs CHANGED
@@ -297,12 +297,12 @@ __export(signer_exports, {
297
297
  async function signD402Payment(params) {
298
298
  const {
299
299
  operatorAccount,
300
+ walletClient,
300
301
  paymentRequirement,
301
302
  iatpWalletAddress,
302
303
  requestPath,
303
304
  d402Version = 1
304
305
  } = params;
305
- const consumerWallet = iatpWalletAddress || operatorAccount.address;
306
306
  let finalRequestPath = requestPath || paymentRequirement.resource || "/mcp";
307
307
  if (!finalRequestPath || finalRequestPath.trim() === "") {
308
308
  finalRequestPath = "/mcp";
@@ -319,27 +319,39 @@ async function signD402Payment(params) {
319
319
  name: walletName,
320
320
  version: walletVersion,
321
321
  chainId,
322
- verifyingContract: consumerWallet
322
+ verifyingContract: iatpWalletAddress
323
323
  };
324
324
  const message = {
325
- wallet: consumerWallet,
325
+ wallet: iatpWalletAddress,
326
326
  provider: paymentRequirement.payTo,
327
327
  token: paymentRequirement.asset,
328
328
  amount: BigInt(paymentRequirement.maxAmountRequired),
329
329
  deadline: BigInt(validBefore),
330
330
  requestPath: finalRequestPath
331
331
  };
332
- if (!operatorAccount.signTypedData) {
333
- throw new Error("Account does not support signTypedData");
332
+ let signature;
333
+ if (walletClient) {
334
+ signature = await walletClient.signTypedData({
335
+ account: operatorAccount,
336
+ domain,
337
+ types: {
338
+ PullFundsForSettlement: EIP712_TYPES.PullFundsForSettlement
339
+ },
340
+ primaryType: "PullFundsForSettlement",
341
+ message
342
+ });
343
+ } else if (operatorAccount.signTypedData) {
344
+ signature = await operatorAccount.signTypedData({
345
+ domain,
346
+ types: {
347
+ PullFundsForSettlement: EIP712_TYPES.PullFundsForSettlement
348
+ },
349
+ primaryType: "PullFundsForSettlement",
350
+ message
351
+ });
352
+ } else {
353
+ throw new Error("Account does not support signTypedData. Pass walletClient for wagmi support.");
334
354
  }
335
- const signature = await operatorAccount.signTypedData({
336
- domain,
337
- types: {
338
- PullFundsForSettlement: EIP712_TYPES.PullFundsForSettlement
339
- },
340
- primaryType: "PullFundsForSettlement",
341
- message
342
- });
343
355
  const signedPayment = {
344
356
  d402Version,
345
357
  scheme: paymentRequirement.scheme,
@@ -347,7 +359,7 @@ async function signD402Payment(params) {
347
359
  payload: {
348
360
  signature,
349
361
  authorization: {
350
- from: consumerWallet,
362
+ from: iatpWalletAddress,
351
363
  to: paymentRequirement.payTo,
352
364
  value: paymentRequirement.maxAmountRequired,
353
365
  validAfter,
@@ -406,6 +418,131 @@ var init_encoder = __esm({
406
418
  }
407
419
  });
408
420
 
421
+ // src/mcp/session.ts
422
+ var session_exports = {};
423
+ __export(session_exports, {
424
+ DEFAULT_JSONRPC_VERSION: () => DEFAULT_JSONRPC_VERSION,
425
+ DEFAULT_REQUEST_ID: () => DEFAULT_REQUEST_ID,
426
+ initMcpSession: () => initMcpSession
427
+ });
428
+ async function initMcpSession(endpoint) {
429
+ const response = await fetch(endpoint, {
430
+ method: "POST",
431
+ headers: {
432
+ "Content-Type": "application/json",
433
+ "Accept": "application/json, text/event-stream"
434
+ },
435
+ body: JSON.stringify({
436
+ jsonrpc: DEFAULT_JSONRPC_VERSION,
437
+ id: DEFAULT_REQUEST_ID,
438
+ method: "initialize",
439
+ params: {
440
+ protocolVersion: "2024-11-05",
441
+ capabilities: {},
442
+ clientInfo: { name: "d402-client", version: "1.0" }
443
+ }
444
+ })
445
+ });
446
+ if (!response.ok) {
447
+ throw new Error(`MCP init failed: ${response.status} ${response.statusText}`);
448
+ }
449
+ return response.headers.get("mcp-session-id");
450
+ }
451
+ var DEFAULT_REQUEST_ID, DEFAULT_JSONRPC_VERSION;
452
+ var init_session = __esm({
453
+ "src/mcp/session.ts"() {
454
+ DEFAULT_REQUEST_ID = "init-1";
455
+ DEFAULT_JSONRPC_VERSION = "2.0";
456
+ }
457
+ });
458
+
459
+ // src/mcp/payload.ts
460
+ var payload_exports = {};
461
+ __export(payload_exports, {
462
+ buildMcpHeaders: () => buildMcpHeaders,
463
+ buildToolCallPayload: () => buildToolCallPayload
464
+ });
465
+ function buildToolCallPayload(toolName, args, requestId = DEFAULT_REQUEST_ID) {
466
+ return {
467
+ jsonrpc: DEFAULT_JSONRPC_VERSION,
468
+ id: requestId,
469
+ method: "tools/call",
470
+ params: {
471
+ name: toolName,
472
+ arguments: args
473
+ }
474
+ };
475
+ }
476
+ function buildMcpHeaders(sessionId) {
477
+ const headers = {
478
+ "Content-Type": "application/json",
479
+ "Accept": "application/json, text/event-stream"
480
+ };
481
+ if (sessionId) {
482
+ headers["mcp-session-id"] = sessionId;
483
+ }
484
+ return headers;
485
+ }
486
+ var init_payload = __esm({
487
+ "src/mcp/payload.ts"() {
488
+ init_session();
489
+ }
490
+ });
491
+
492
+ // src/mcp/response.ts
493
+ var response_exports = {};
494
+ __export(response_exports, {
495
+ extractToolResult: () => extractToolResult,
496
+ parseMcpResponse: () => parseMcpResponse
497
+ });
498
+ async function parseMcpResponse(response) {
499
+ const contentType = response.headers.get("content-type") || "";
500
+ if (contentType.includes("text/event-stream")) {
501
+ return parseSSEResponse(await response.text());
502
+ } else {
503
+ return await response.json();
504
+ }
505
+ }
506
+ function parseSSEResponse(text) {
507
+ const lines = text.split("\n");
508
+ for (const line of lines) {
509
+ if (line.startsWith("data: ")) {
510
+ const jsonStr = line.substring(6);
511
+ try {
512
+ return JSON.parse(jsonStr);
513
+ } catch {
514
+ continue;
515
+ }
516
+ }
517
+ }
518
+ return {
519
+ id: "unknown",
520
+ result: { raw: text },
521
+ error: {
522
+ code: -32700,
523
+ message: "Could not parse SSE response",
524
+ data: text
525
+ }
526
+ };
527
+ }
528
+ function extractToolResult(response) {
529
+ if (response.error) {
530
+ throw new Error(`MCP error ${response.error.code}: ${response.error.message}`);
531
+ }
532
+ if (response.result && typeof response.result === "object") {
533
+ const result = response.result;
534
+ if (result.structuredContent) {
535
+ return result.structuredContent;
536
+ }
537
+ return result;
538
+ }
539
+ return response.result;
540
+ }
541
+ var init_response = __esm({
542
+ "src/mcp/response.ts"() {
543
+ }
544
+ });
545
+
409
546
  // src/payment/selector.ts
410
547
  init_errors();
411
548
  function selectPaymentRequirement(requirements, options = {}) {
@@ -5039,7 +5176,7 @@ function getContractConfig(contractName, network = "sepolia") {
5039
5176
 
5040
5177
  // src/wallet/creation.ts
5041
5178
  async function createIATPWallet(params) {
5042
- const { ownerAccount, network = "sepolia", rpcUrl } = params;
5179
+ const { ownerAccount, walletClient: externalWalletClient, network = "sepolia", rpcUrl } = params;
5043
5180
  const factoryConfig = getContractConfig("IATPWalletFactory" /* IATP_WALLET_FACTORY */, network);
5044
5181
  if (!factoryConfig) {
5045
5182
  throw new Error(`IATPWalletFactory not found for network: ${network}`);
@@ -5051,7 +5188,7 @@ async function createIATPWallet(params) {
5051
5188
  chain,
5052
5189
  transport
5053
5190
  });
5054
- const walletClient = createWalletClient({
5191
+ const walletClient = externalWalletClient ?? createWalletClient({
5055
5192
  account: ownerAccount,
5056
5193
  chain,
5057
5194
  transport
@@ -5060,14 +5197,14 @@ async function createIATPWallet(params) {
5060
5197
  if (balance === 0n) {
5061
5198
  throw new Error("Owner has no ETH for gas. Please fund the account.");
5062
5199
  }
5063
- const { request } = await publicClient.simulateContract({
5200
+ const hash = await walletClient.writeContract({
5064
5201
  account: ownerAccount,
5065
5202
  address: factoryConfig.address,
5066
5203
  abi: factoryConfig.abi,
5067
5204
  functionName: "createWallet",
5068
- args: [operatorAddress, 0, "", ""]
5205
+ args: [operatorAddress, 0, "", ""],
5206
+ chain
5069
5207
  });
5070
- const hash = await walletClient.writeContract(request);
5071
5208
  const receipt = await publicClient.waitForTransactionReceipt({
5072
5209
  hash,
5073
5210
  timeout: 3e5
@@ -5245,6 +5382,7 @@ var D402Client = class {
5245
5382
  */
5246
5383
  constructor(config) {
5247
5384
  this.operatorAccount = config.operatorAccount;
5385
+ this.walletClient = config.walletClient;
5248
5386
  this.iatpWalletAddress = config.iatpWalletAddress;
5249
5387
  this.maxValue = config.maxValue;
5250
5388
  this.networkFilter = config.networkFilter;
@@ -5388,7 +5526,15 @@ var D402Client = class {
5388
5526
  const { parseAllPaymentRequirements: parseAllPaymentRequirements2 } = await Promise.resolve().then(() => (init_parser(), parser_exports));
5389
5527
  const { signD402Payment: signD402Payment2 } = await Promise.resolve().then(() => (init_signer(), signer_exports));
5390
5528
  const { encodePayment: encodePayment2 } = await Promise.resolve().then(() => (init_encoder(), encoder_exports));
5391
- let response = await fetch(url, init);
5529
+ const enhancedInit = {
5530
+ ...init,
5531
+ headers: {
5532
+ ...init?.headers,
5533
+ // Preserve existing Accept header or set default for MCP compatibility
5534
+ "Accept": init?.headers?.["Accept"] || "application/json, text/event-stream"
5535
+ }
5536
+ };
5537
+ let response = await fetch(url, enhancedInit);
5392
5538
  if (response.status !== 402) {
5393
5539
  return response;
5394
5540
  }
@@ -5397,14 +5543,15 @@ var D402Client = class {
5397
5543
  const selectedRequirement = this.selectPaymentRequirement(requirements);
5398
5544
  const signedPayment = await signD402Payment2({
5399
5545
  operatorAccount: this.operatorAccount,
5546
+ walletClient: this.walletClient,
5400
5547
  paymentRequirement: selectedRequirement,
5401
5548
  iatpWalletAddress: this.iatpWalletAddress
5402
5549
  });
5403
5550
  const paymentHeader = encodePayment2(signedPayment);
5404
5551
  response = await fetch(url, {
5405
- ...init,
5552
+ ...enhancedInit,
5406
5553
  headers: {
5407
- ...init?.headers,
5554
+ ...enhancedInit.headers,
5408
5555
  "X-Payment": paymentHeader,
5409
5556
  "Access-Control-Expose-Headers": "X-Payment-Response"
5410
5557
  }
@@ -5414,6 +5561,63 @@ var D402Client = class {
5414
5561
  throw error;
5415
5562
  }
5416
5563
  }
5564
+ // ========================================================================
5565
+ // MCP Methods - Simplified API for MCP tool calls
5566
+ // ========================================================================
5567
+ /**
5568
+ * Call an MCP tool with automatic session initialization and payment handling.
5569
+ *
5570
+ * This is the simplest way to call an MCP tool. It handles:
5571
+ * - MCP session initialization
5572
+ * - JSON-RPC payload construction
5573
+ * - HTTP 402 payment flow
5574
+ * - SSE/JSON response parsing
5575
+ *
5576
+ * @param endpoint - MCP server endpoint URL
5577
+ * @param toolName - Name of the tool to call
5578
+ * @param input - Tool arguments
5579
+ * @param options - Optional configuration
5580
+ * @returns The tool's result data
5581
+ *
5582
+ * @example
5583
+ * ```ts
5584
+ * const client = new D402Client({
5585
+ * operatorAccount: walletClient.account,
5586
+ * walletClient,
5587
+ * iatpWalletAddress,
5588
+ * })
5589
+ *
5590
+ * // Simple one-liner!
5591
+ * const result = await client.mcpCall(
5592
+ * 'https://my-mcp.example.com/mcp',
5593
+ * 'google_search',
5594
+ * { q: 'test search' }
5595
+ * )
5596
+ *
5597
+ * console.log(result) // { searchResults: [...] }
5598
+ * ```
5599
+ */
5600
+ async mcpCall(endpoint, toolName, input, options) {
5601
+ const { initMcpSession: initMcpSession2 } = await Promise.resolve().then(() => (init_session(), session_exports));
5602
+ const { buildToolCallPayload: buildToolCallPayload2, buildMcpHeaders: buildMcpHeaders2 } = await Promise.resolve().then(() => (init_payload(), payload_exports));
5603
+ const { parseMcpResponse: parseMcpResponse2, extractToolResult: extractToolResult2 } = await Promise.resolve().then(() => (init_response(), response_exports));
5604
+ let sessionId = null;
5605
+ if (!options?.skipInit) {
5606
+ try {
5607
+ sessionId = await initMcpSession2(endpoint);
5608
+ } catch {
5609
+ }
5610
+ }
5611
+ const headers = buildMcpHeaders2(sessionId);
5612
+ const payload = buildToolCallPayload2(toolName, input, options?.requestId);
5613
+ const response = await this.fetch(endpoint, {
5614
+ method: "POST",
5615
+ headers,
5616
+ body: JSON.stringify(payload)
5617
+ });
5618
+ const parsed = await parseMcpResponse2(response);
5619
+ return extractToolResult2(parsed);
5620
+ }
5417
5621
  };
5418
5622
 
5419
5623
  // src/index.ts
@@ -5421,6 +5625,11 @@ init_signer();
5421
5625
  init_parser();
5422
5626
  init_encoder();
5423
5627
 
5628
+ // src/mcp/index.ts
5629
+ init_session();
5630
+ init_payload();
5631
+ init_response();
5632
+
5424
5633
  // src/settlement/queries.ts
5425
5634
  async function getLockedBalanceForProvider(params) {
5426
5635
  const { publicClient, providerAddress, tokenAddress, network = "sepolia" } = params;
@@ -5493,6 +5702,6 @@ async function withdrawAllAvailableEpochs(params) {
5493
5702
  init_utils();
5494
5703
  init_errors();
5495
5704
 
5496
- export { ContractName, D402Client, Invalid402ResponseError, MissingRequestConfigError, PaymentAlreadyAttemptedError, PaymentAmountExceededError, PaymentError, PaymentVerificationError, UnsupportedNetworkError, UnsupportedSchemeError, createIATPWallet, createPaymentSelector, decodePayment, decodePaymentResponse, encodePayment, executeWithdrawal, findMatchingPaymentRequirement, formatMoney, generateNonce, getAvailableBalance, getChainId, getContractAbi, getContractAddress, getContractConfig, getCurrentTimestamp, getLockedBalanceForProvider, getUnlockedBalanceForProvider, getUsdcAddress, getWalletsByOwner, getWithdrawalRequest, isValidAddress, normalizeAddress, parseAllPaymentRequirements, parseMoney, parsePaymentRequirement, requestWithdrawal, selectPaymentRequirement, signD402Payment, sortPaymentRequirements, usdToUsdc, withdrawAllAvailableEpochs };
5705
+ export { ContractName, D402Client, Invalid402ResponseError, MissingRequestConfigError, PaymentAlreadyAttemptedError, PaymentAmountExceededError, PaymentError, PaymentVerificationError, UnsupportedNetworkError, UnsupportedSchemeError, buildMcpHeaders, buildToolCallPayload, createIATPWallet, createPaymentSelector, decodePayment, decodePaymentResponse, encodePayment, executeWithdrawal, extractToolResult, findMatchingPaymentRequirement, formatMoney, generateNonce, getAvailableBalance, getChainId, getContractAbi, getContractAddress, getContractConfig, getCurrentTimestamp, getLockedBalanceForProvider, getUnlockedBalanceForProvider, getUsdcAddress, getWalletsByOwner, getWithdrawalRequest, initMcpSession, isValidAddress, normalizeAddress, parseAllPaymentRequirements, parseMcpResponse, parseMoney, parsePaymentRequirement, requestWithdrawal, selectPaymentRequirement, signD402Payment, sortPaymentRequirements, usdToUsdc, withdrawAllAvailableEpochs };
5497
5706
  //# sourceMappingURL=index.mjs.map
5498
5707
  //# sourceMappingURL=index.mjs.map