diff --git a/packages/atxp-client/package.json b/packages/atxp-client/package.json index 69895ba..1025892 100644 --- a/packages/atxp-client/package.json +++ b/packages/atxp-client/package.json @@ -1,6 +1,6 @@ { "name": "@atxp/client", - "version": "0.11.10", + "version": "0.11.12", "description": "ATXP Client - MCP client with OAuth authentication and payment processing", "license": "MIT", "repository": { @@ -33,8 +33,8 @@ "pack:dry": "npm pack --dry-run" }, "dependencies": { - "@atxp/common": "0.11.10", - "@atxp/mpp": "0.11.10", + "@atxp/common": "0.11.11", + "@atxp/mpp": "0.11.11", "@modelcontextprotocol/sdk": "^1.15.0", "@x402/core": "^2.9.0", "@x402/evm": "^2.9.0", diff --git a/packages/atxp-client/src/atxpAccountHandler.test.ts b/packages/atxp-client/src/atxpAccountHandler.test.ts index d47c6d9..b1ac67d 100644 --- a/packages/atxp-client/src/atxpAccountHandler.test.ts +++ b/packages/atxp-client/src/atxpAccountHandler.test.ts @@ -55,14 +55,17 @@ describe('ATXPAccountHandler', () => { }); describe('handlePaymentChallenge', () => { - it('delegates to account.authorize() and retries with payment header', async () => { + it('delegates to account.authorize() and retries with payment and lifecycle headers', async () => { const authorize = vi.fn().mockResolvedValue({ protocol: 'atxp', credential: '{"token":"abc"}' }); const account = createMockAccount({ authorize }); const retryResponse = new Response('paid', { status: 200 }); const fetchFn = vi.fn().mockResolvedValue(retryResponse); const config = createMockConfig({ account, fetchFn }); - const response = make402Response({ chargeAmount: '0.01' }); + const response = make402Response({ + chargeAmount: '0.01', + paymentRequestId: 'pr_lifecycle_123', + }); const result = await handler.handlePaymentChallenge( response, { url: 'https://example.com/api' }, @@ -77,6 +80,10 @@ describe('ATXPAccountHandler', () => { }), ); expect(fetchFn).toHaveBeenCalledTimes(1); + const retryInit = fetchFn.mock.calls[0][1] as RequestInit; + const retryHeaders = retryInit.headers as Headers; + expect(retryHeaders.get('X-ATXP-PAYMENT')).toBe('{"token":"abc"}'); + expect(retryHeaders.get('X-ATXP-Payment-Request-Id')).toBe('pr_lifecycle_123'); expect(result).toBe(retryResponse); }); diff --git a/packages/atxp-client/src/atxpAccountHandler.ts b/packages/atxp-client/src/atxpAccountHandler.ts index 021adb3..8311ffc 100644 --- a/packages/atxp-client/src/atxpAccountHandler.ts +++ b/packages/atxp-client/src/atxpAccountHandler.ts @@ -91,6 +91,10 @@ export class ATXPAccountHandler implements ProtocolHandler { // Map the returned protocol to the correct HTTP header const retryHeaders = buildPaymentHeaders(result, originalRequest.init?.headers); + const paymentRequestId = challengeData.paymentRequestId; + if (typeof paymentRequestId === 'string' && paymentRequestId) { + retryHeaders.set('X-ATXP-Payment-Request-Id', paymentRequestId); + } const retryInit: RequestInit = { ...originalRequest.init, headers: retryHeaders }; return fetchFn(originalRequest.url, retryInit);