|
1 | 1 | declare const __VERSION__: string; |
2 | 2 |
|
| 3 | +import { AsyncLocalStorage } from "node:async_hooks"; |
3 | 4 | import { buildCommand, type CommandContext } from "@stricli/core"; |
4 | 5 | import { TEMPO_NETWORK } from "../handler.js"; |
5 | 6 | import { appendHistory, displayNetwork, formatAmount, type TxRecord } from "../history.js"; |
@@ -455,15 +456,17 @@ Wallet is auto-generated on first run. No env vars needed.`, |
455 | 456 | const account = privateKeyToAccount(wallet.evmKey as `0x${string}`); |
456 | 457 | const maxDeposit = config?.mppSessionBudget ?? "1"; |
457 | 458 |
|
458 | | - // Wrap tempo methods to capture payment amounts from challenges |
459 | | - let lastChallengeAmount: number | undefined; |
| 459 | + // Per-call async context to capture payment amounts without races. |
| 460 | + // Each concurrent callTool gets its own store via AsyncLocalStorage. |
| 461 | + const challengeAmountStore = new AsyncLocalStorage<{ amount?: number }>(); |
460 | 462 | const tempoMethods = tempo({ account, maxDeposit }); |
461 | 463 | const wrappedMethods = tempoMethods.map((m) => ({ |
462 | 464 | ...m, |
463 | 465 | createCredential: async (params: { challenge: { request: Record<string, unknown> } }) => { |
464 | 466 | const req = params.challenge.request as { amount?: string; decimals?: number }; |
465 | | - if (req.amount) { |
466 | | - lastChallengeAmount = Number(req.amount) / 10 ** (req.decimals ?? 6); |
| 467 | + const store = challengeAmountStore.getStore(); |
| 468 | + if (req.amount && store) { |
| 469 | + store.amount = Number(req.amount) / 10 ** (req.decimals ?? 6); |
467 | 470 | } |
468 | 471 | return (m.createCredential as (p: unknown) => Promise<string>)(params); |
469 | 472 | }, |
@@ -515,31 +518,32 @@ Wallet is auto-generated on first run. No env vars needed.`, |
515 | 518 |
|
516 | 519 | localServer.setRequestHandler(CallToolRequestSchema, async (request) => { |
517 | 520 | const { name, arguments: args } = request.params; |
518 | | - const result = await mppClient.callTool({ name, arguments: args ?? {} }); |
519 | | - |
520 | | - // Record MPP payment if receipt present |
521 | | - if (result.receipt) { |
522 | | - const record: TxRecord = { |
523 | | - t: Date.now(), |
524 | | - ok: true, |
525 | | - kind: "mpp_payment", |
526 | | - net: TEMPO_NETWORK, |
527 | | - from: wallet.evmAddress ?? "unknown", |
528 | | - tx: result.receipt.reference, |
529 | | - amount: lastChallengeAmount, |
530 | | - token: "USDC", |
531 | | - label: `mcp:${name}`, |
532 | | - }; |
533 | | - appendHistory(getHistoryPath(), record); |
534 | | - const amountStr = |
535 | | - lastChallengeAmount !== undefined ? formatAmount(lastChallengeAmount, "USDC") : ""; |
536 | | - warn( |
537 | | - ` MPP payment for tool "${name}" (Tempo)${amountStr ? ` \u00b7 ${amountStr}` : ""}`, |
538 | | - ); |
539 | | - lastChallengeAmount = undefined; |
540 | | - } |
| 521 | + const store = { amount: undefined as number | undefined }; |
| 522 | + return challengeAmountStore.run(store, async () => { |
| 523 | + const result = await mppClient.callTool({ name, arguments: args ?? {} }); |
| 524 | + |
| 525 | + // Record MPP payment if receipt present |
| 526 | + if (result.receipt) { |
| 527 | + const record: TxRecord = { |
| 528 | + t: Date.now(), |
| 529 | + ok: true, |
| 530 | + kind: "mpp_payment", |
| 531 | + net: TEMPO_NETWORK, |
| 532 | + from: wallet.evmAddress ?? "unknown", |
| 533 | + tx: result.receipt.reference, |
| 534 | + amount: store.amount, |
| 535 | + token: "USDC", |
| 536 | + label: `mcp:${name}`, |
| 537 | + }; |
| 538 | + appendHistory(getHistoryPath(), record); |
| 539 | + const amountStr = store.amount !== undefined ? formatAmount(store.amount, "USDC") : ""; |
| 540 | + warn( |
| 541 | + ` MPP payment for tool "${name}" (Tempo)${amountStr ? ` \u00b7 ${amountStr}` : ""}`, |
| 542 | + ); |
| 543 | + } |
541 | 544 |
|
542 | | - return normalizeCallToolResult(result as CallToolResultLike); |
| 545 | + return normalizeCallToolResult(result as CallToolResultLike); |
| 546 | + }); |
543 | 547 | }); |
544 | 548 |
|
545 | 549 | if (remoteResources.length > 0) { |
|
0 commit comments