@payware/mcp-server 1.2.0 → 1.3.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 +5 -0
- package/package.json +69 -66
- package/src/auth/sandbox-setup.js +186 -186
- package/src/isv/index.js +29 -1
- package/src/isv/invitations/index.js +471 -0
- package/src/isv/oauth2/obtain-token.js +19 -8
- package/src/isv/oauth2/token-helper.js +5 -2
- package/src/isv/poi/cancel-price.js +2 -10
- package/src/isv/poi/create.js +19 -0
- package/src/isv/poi/get-poi.js +2 -10
- package/src/isv/poi/get-qrcode.js +2 -10
- package/src/isv/poi/get-status.js +2 -10
- package/src/isv/poi/index.js +5 -0
- package/src/isv/poi/list-pois.js +2 -10
- package/src/isv/poi/set-price.js +217 -225
- package/src/isv/products/create-product.js +313 -313
- package/src/isv/products/update-product.js +264 -264
- package/src/isv/reference/index.js +249 -0
- package/src/isv/shops/index.js +22 -0
- package/src/isv/transactions/cancel-transaction.js +41 -10
- package/src/isv/transactions/create-transaction.js +20 -4
- package/src/isv/transactions/get-status.js +18 -11
- package/src/isv/transactions/process-transaction.js +160 -42
- package/src/isv/transactions/simulate-callback.js +128 -109
- package/src/isv/transactions/transaction-history.js +86 -90
- package/src/merchant/data/generate-report.js +19 -1
- package/src/merchant/index.js +21 -1
- package/src/merchant/logs/index.js +366 -0
- package/src/merchant/products/create-product.js +287 -287
- package/src/merchant/products/update-product.js +281 -281
- package/src/merchant/shops/index.js +18 -0
- package/src/merchant/transactions/cancel-transaction.js +10 -13
- package/src/merchant/transactions/create-transaction.js +88 -8
- package/src/merchant/transactions/get-status.js +40 -11
- package/src/merchant/transactions/process-transaction.js +2 -10
- package/src/merchant/transactions/simulate-callback.js +68 -9
- package/src/merchant/transactions/transaction-history.js +275 -257
- package/src/payment-institution/transactions/create-pi-transaction.js +2 -10
- package/src/payment-institution/transactions/finalize-transaction.js +333 -340
- package/src/payment-institution/transactions/get-transaction-history.js +2 -10
- package/src/payment-institution/transactions/get-transaction-status.js +38 -11
- package/src/payment-institution/transactions/process-pi-transaction.js +2 -10
- package/src/payment-institution/transactions/simulate-pi-callback.js +49 -9
- package/src/payment-institution/transactions/soundbite-transaction.js +2 -10
- package/src/shared/api-errors.js +188 -0
- package/src/shared/auth-headers.js +62 -0
- package/src/shared/data/data-api.js +11 -10
- package/src/shared/deep-links/api.js +5 -4
- package/src/shared/logs/logs-api.js +242 -0
- package/src/shared/poi/poi-create-api.js +419 -0
- package/src/shared/products/products-api.js +17 -16
- package/src/shared/shops/shops-api.js +155 -0
- package/src/tools/advanced-code-generator.js +2255 -2246
- package/src/utils/code-examples/common/auth-examples.js +1484 -1481
- package/src/utils/code-examples/common/helpers.js +7 -4
- package/src/utils/code-examples/isv/oauth2.js +458 -600
- package/src/utils/code-examples/isv/transactions.js +815 -812
- package/MCP-SETUP.md +0 -190
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
|
|
3
3
|
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
4
|
+
import { describeApiError } from '../../shared/api-errors.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* Get transaction
|
|
7
|
+
* Get one completed transaction as an ISV acting on behalf of a merchant.
|
|
8
|
+
*
|
|
9
|
+
* **This used to be a list-and-filter tool, and there is nothing on the server to list.**
|
|
10
|
+
* It built `GET /transactions-history?limit=50&offset=0&status=...&from=...&to=...` and read
|
|
11
|
+
* `result.transactions` / `result.totalCount` off the response. `TransactionHistoryController` maps
|
|
12
|
+
* exactly one route - `GET /api/transactions-history/{transactionId}` - so the bare path matched no
|
|
13
|
+
* handler and the call answered 404 every time, whatever the filters said. The filters, the
|
|
14
|
+
* pagination and the result shape were all describing an endpoint that has never existed.
|
|
15
|
+
*
|
|
16
|
+
* It now does what the merchant tool does and what the API offers: fetch one transaction by id.
|
|
7
17
|
*/
|
|
8
18
|
export async function getTransactionHistory({
|
|
9
19
|
merchantPartnerId,
|
|
10
20
|
oauth2Token,
|
|
11
|
-
partnerId,
|
|
12
21
|
transactionId,
|
|
13
|
-
limit = 50,
|
|
14
|
-
offset = 0,
|
|
15
|
-
status,
|
|
16
|
-
from,
|
|
17
|
-
to,
|
|
18
22
|
useSandbox = true
|
|
19
23
|
}) {
|
|
24
|
+
if (!transactionId) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
'transactionId is required. The payware API has no endpoint that lists or filters transaction ' +
|
|
27
|
+
'history - GET /transactions-history/{transactionId} fetches one transaction by id, and that ' +
|
|
28
|
+
'is the whole surface. Keep your own record of the ids you created, or read them from the ' +
|
|
29
|
+
'callbacks you received.'
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
if (!merchantPartnerId) {
|
|
21
34
|
throw new Error('Merchant Partner ID is required for ISV operations');
|
|
22
35
|
}
|
|
@@ -28,6 +41,7 @@ export async function getTransactionHistory({
|
|
|
28
41
|
const isvPartnerId = getPartnerIdSafe();
|
|
29
42
|
const privateKey = getPrivateKeySafe(useSandbox);
|
|
30
43
|
|
|
44
|
+
// GET, so no body and no content hash.
|
|
31
45
|
const jwtData = await createJWTForPartner({
|
|
32
46
|
partnerId: isvPartnerId,
|
|
33
47
|
privateKey,
|
|
@@ -36,19 +50,9 @@ export async function getTransactionHistory({
|
|
|
36
50
|
oauth2Token
|
|
37
51
|
});
|
|
38
52
|
|
|
39
|
-
const params = new URLSearchParams();
|
|
40
|
-
if (partnerId) params.append('partnerId', partnerId);
|
|
41
|
-
if (transactionId) params.append('transactionId', transactionId);
|
|
42
|
-
if (limit) params.append('limit', limit.toString());
|
|
43
|
-
if (offset) params.append('offset', offset.toString());
|
|
44
|
-
if (status) params.append('status', status);
|
|
45
|
-
if (from) params.append('from', from);
|
|
46
|
-
if (to) params.append('to', to);
|
|
47
|
-
|
|
48
53
|
try {
|
|
49
54
|
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
50
|
-
const
|
|
51
|
-
const response = await axios.get(url, {
|
|
55
|
+
const response = await axios.get(`${baseUrl}/transactions-history/${transactionId}`, {
|
|
52
56
|
headers: {
|
|
53
57
|
'Authorization': `Bearer ${jwtData.token}`,
|
|
54
58
|
'Content-Type': 'application/json',
|
|
@@ -58,62 +62,50 @@ export async function getTransactionHistory({
|
|
|
58
62
|
|
|
59
63
|
return response.data;
|
|
60
64
|
} catch (error) {
|
|
61
|
-
|
|
62
|
-
throw new Error(`payware API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
|
63
|
-
}
|
|
64
|
-
throw error;
|
|
65
|
+
throw describeApiError(error, 'call the payware API');
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
export const getTransactionHistoryTool = {
|
|
69
70
|
name: 'payware_operations_get_transaction_history',
|
|
70
|
-
description: `Get transaction
|
|
71
|
+
description: `Get one completed or expired transaction as an ISV on behalf of a merchant.
|
|
72
|
+
|
|
73
|
+
**Endpoint:** GET /transactions-history/{transactionId}
|
|
74
|
+
|
|
75
|
+
Returns a transaction in a final state: CONFIRMED, DECLINED, FAILED, EXPIRED or CANCELLED. For a
|
|
76
|
+
transaction still ACTIVE, use \`payware_operations_get_transaction_status\` instead - the two
|
|
77
|
+
endpoints cover disjoint sets of transactions and neither falls back to the other.
|
|
78
|
+
|
|
79
|
+
⚠️ **There is no way to list or search transaction history.** This endpoint takes an id and returns
|
|
80
|
+
that one transaction. There is no pagination, no date range and no status filter anywhere in the
|
|
81
|
+
payware API - so keep your own record of the transaction ids you created, or read them from the
|
|
82
|
+
callbacks you received. (This tool previously advertised \`limit\`, \`offset\`, \`status\`, \`from\` and
|
|
83
|
+
\`to\` parameters; they described an endpoint that does not exist and every call 404'd.)
|
|
84
|
+
|
|
85
|
+
📦 **This is the only source of the delivery address.** For a SHIPPABLE transaction,
|
|
86
|
+
\`deliveryAddress\` is returned here and nowhere else - it was removed from the finalized callback on
|
|
87
|
+
2026-08-07, because a callback goes to whatever certificate the merchant's endpoint presents and a
|
|
88
|
+
shopper's home address does not belong on that channel. The callback tells you the shipment is
|
|
89
|
+
ready; this call gives you the address.
|
|
71
90
|
|
|
72
|
-
|
|
73
|
-
|
|
91
|
+
⚠️ **The MERCHANT's plan governs, and this endpoint is now gated.** It was ungated until 2026-08-21
|
|
92
|
+
and now requires Standard or Premium, so acting for a **Basic** merchant answers **403**.`,
|
|
74
93
|
|
|
75
94
|
inputSchema: {
|
|
76
95
|
type: 'object',
|
|
77
|
-
required: ['merchantPartnerId', 'oauth2Token'],
|
|
96
|
+
required: ['transactionId', 'merchantPartnerId', 'oauth2Token'],
|
|
78
97
|
properties: {
|
|
79
|
-
merchantPartnerId: {
|
|
80
|
-
type: 'string',
|
|
81
|
-
description: 'Partner ID of the target merchant'
|
|
82
|
-
},
|
|
83
|
-
oauth2Token: {
|
|
84
|
-
type: 'string',
|
|
85
|
-
description: 'OAuth2 access token obtained from the merchant'
|
|
86
|
-
},
|
|
87
|
-
partnerId: {
|
|
88
|
-
type: 'string',
|
|
89
|
-
description: 'Filter by partner ID (optional)'
|
|
90
|
-
},
|
|
91
98
|
transactionId: {
|
|
92
99
|
type: 'string',
|
|
93
|
-
description: '
|
|
94
|
-
},
|
|
95
|
-
limit: {
|
|
96
|
-
type: 'number',
|
|
97
|
-
default: 50,
|
|
98
|
-
description: 'Maximum number of results to return'
|
|
99
|
-
},
|
|
100
|
-
offset: {
|
|
101
|
-
type: 'number',
|
|
102
|
-
default: 0,
|
|
103
|
-
description: 'Number of results to skip for pagination'
|
|
100
|
+
description: 'The transaction to fetch, e.g. "pw7e4rCToG". Required - there is no list or search endpoint.'
|
|
104
101
|
},
|
|
105
|
-
|
|
106
|
-
type: 'string',
|
|
107
|
-
enum: ['ACTIVE', 'CONFIRMED', 'DECLINED', 'FAILED', 'EXPIRED', 'CANCELLED'],
|
|
108
|
-
description: 'Filter by transaction status'
|
|
109
|
-
},
|
|
110
|
-
from: {
|
|
102
|
+
merchantPartnerId: {
|
|
111
103
|
type: 'string',
|
|
112
|
-
description: '
|
|
104
|
+
description: 'Partner ID of the target merchant (8 alphanumeric characters)'
|
|
113
105
|
},
|
|
114
|
-
|
|
106
|
+
oauth2Token: {
|
|
115
107
|
type: 'string',
|
|
116
|
-
description: '
|
|
108
|
+
description: 'OAuth2 access token obtained from the merchant'
|
|
117
109
|
},
|
|
118
110
|
useSandbox: {
|
|
119
111
|
type: 'boolean',
|
|
@@ -125,46 +117,46 @@ Requires ISV authentication with merchant partner ID and OAuth2 token.`,
|
|
|
125
117
|
|
|
126
118
|
async handler(params) {
|
|
127
119
|
try {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
'CONFIRMED': '✅',
|
|
137
|
-
'DECLINED': '❌',
|
|
138
|
-
'FAILED': '⚠️',
|
|
139
|
-
'EXPIRED': '⏰',
|
|
140
|
-
'CANCELLED': '🚫'
|
|
141
|
-
};
|
|
142
|
-
const emoji = statusEmojis[tx.status] || '❓';
|
|
143
|
-
const paymentInfo = tx.paymentMethod ? ` [${tx.paymentMethod}]` : '';
|
|
144
|
-
return ` ${emoji} **${tx.id}** - ${tx.trData?.amount || '0.00'} ${tx.trData?.currency || 'EUR'}${paymentInfo} - ${tx.status} - ${tx.createdAt || 'N/A'}`;
|
|
120
|
+
const tx = await getTransactionHistory(params);
|
|
121
|
+
|
|
122
|
+
const statusEmojis = {
|
|
123
|
+
CONFIRMED: '✅',
|
|
124
|
+
DECLINED: '❌',
|
|
125
|
+
FAILED: '⚠️',
|
|
126
|
+
EXPIRED: '⏰',
|
|
127
|
+
CANCELLED: '🚫'
|
|
145
128
|
};
|
|
129
|
+
const emoji = statusEmojis[tx.status] || '❓';
|
|
130
|
+
|
|
131
|
+
const delivery = tx.deliveryAddress ? `
|
|
132
|
+
|
|
133
|
+
📦 **Delivery Address** (SHIPPABLE)
|
|
134
|
+
- Name: ${tx.deliveryAddress.fullName || 'N/A'}
|
|
135
|
+
- Address: ${tx.deliveryAddress.streetAddressLine1 || 'N/A'}${tx.deliveryAddress.streetAddressLine2 ? `, ${tx.deliveryAddress.streetAddressLine2}` : ''}
|
|
136
|
+
- City: ${tx.deliveryAddress.city || 'N/A'}, ${tx.deliveryAddress.zipCode || 'N/A'}
|
|
137
|
+
- Region: ${tx.deliveryAddress.region || 'N/A'}
|
|
138
|
+
- Country: ${tx.deliveryAddress.country || 'N/A'}
|
|
139
|
+
- Phone: ${tx.deliveryAddress.phoneNumber || 'N/A'}
|
|
140
|
+
- Email: ${tx.deliveryAddress.email || 'N/A'}` : '';
|
|
146
141
|
|
|
147
142
|
return {
|
|
148
143
|
content: [{
|
|
149
144
|
type: 'text',
|
|
150
|
-
text:
|
|
145
|
+
text: `${emoji} **Transaction ${tx.transactionId || params.transactionId}** - ${tx.status}
|
|
151
146
|
|
|
152
|
-
**ISV
|
|
153
|
-
- ISV Partner: ${getPartnerIdSafe()}
|
|
154
|
-
- Target Merchant: ${params.merchantPartnerId}
|
|
155
|
-
- OAuth2 Token: ${params.oauth2Token.substring(0, 8)}...
|
|
147
|
+
**ISV -> Merchant:** ${getPartnerIdSafe()} -> ${params.merchantPartnerId}
|
|
156
148
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
149
|
+
- Amount: ${tx.amount ?? 'N/A'} ${tx.currency ?? ''}
|
|
150
|
+
- Fee: ${tx.fee ?? '(not reported - absence means unknown, not zero)'}
|
|
151
|
+
- Type: ${tx.transactionType ?? 'N/A'}
|
|
152
|
+
- Payment method: ${tx.paymentMethod ?? 'N/A'}
|
|
153
|
+
- Status message: ${tx.statusMessage ?? 'N/A'}
|
|
154
|
+
- Created: ${tx.created ?? 'N/A'}
|
|
155
|
+
- Finalized: ${tx.finalized ?? '(absent - EXPIRED transactions carry no finalization moment)'}${delivery}
|
|
164
156
|
|
|
165
157
|
**Raw Response:**
|
|
166
158
|
\`\`\`json
|
|
167
|
-
${JSON.stringify(
|
|
159
|
+
${JSON.stringify(tx, null, 2)}
|
|
168
160
|
\`\`\``
|
|
169
161
|
}]
|
|
170
162
|
};
|
|
@@ -179,9 +171,13 @@ ${JSON.stringify(result, null, 2)}
|
|
|
179
171
|
**ISV Authentication:**
|
|
180
172
|
- Merchant Partner ID: ${params.merchantPartnerId}
|
|
181
173
|
- OAuth2 Token: ${params.oauth2Token ? 'Provided' : 'Missing'}
|
|
182
|
-
- ISV Partner ID: ${getPartnerIdSafe()}
|
|
174
|
+
- ISV Partner ID: ${getPartnerIdSafe()}
|
|
175
|
+
|
|
176
|
+
**Common causes:**
|
|
177
|
+
- 404: the transaction is still ACTIVE (use \`payware_operations_get_transaction_status\`), or the id is wrong.
|
|
178
|
+
- 403: the acting merchant is on the Basic plan, which does not include transaction history.`
|
|
183
179
|
}]
|
|
184
180
|
};
|
|
185
181
|
}
|
|
186
182
|
}
|
|
187
|
-
};
|
|
183
|
+
};
|
|
@@ -6,7 +6,25 @@ import { getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export const generateReportTool = {
|
|
8
8
|
name: "payware_data_generate_report",
|
|
9
|
-
description:
|
|
9
|
+
description: `Generate an asynchronous data report for merchant data analysis and reporting. Production only - not supported in sandbox.
|
|
10
|
+
|
|
11
|
+
⚠️ **Running a report is entitlement-checked as of 2026-08-22.** Naming a report answers **403
|
|
12
|
+
\`ERR_REPORT_NOT_AVAILABLE\`** when that report is not included in the caller's plan or partner type.
|
|
13
|
+
Until that date only the *menu* was filtered - the door was not - so a caller that hard-coded a
|
|
14
|
+
report id it had never been offered could still run it, and may now start failing.
|
|
15
|
+
|
|
16
|
+
**Always resolve the id from \`payware_data_list_reports\` rather than hard-coding one.** That call
|
|
17
|
+
and this check share a single rule, so the menu and the door cannot drift apart: if a report is in
|
|
18
|
+
that list, this call will accept it.
|
|
19
|
+
|
|
20
|
+
Distinguish the two failures:
|
|
21
|
+
- **403 \`ERR_REPORT_NOT_AVAILABLE\`** - the report exists, this caller may not run it. Not retryable;
|
|
22
|
+
it is a plan boundary, not a transient error.
|
|
23
|
+
- **404 \`ERR_REPORT_UNIT_ID_NOT_FOUND\`** - no report is registered under that id at all. Usually a
|
|
24
|
+
typo or a stale id.
|
|
25
|
+
|
|
26
|
+
For an ISV acting on behalf of a merchant, the plan that applies is the **merchant's**, and reports
|
|
27
|
+
are outside the Basic plan entirely.`,
|
|
10
28
|
inputSchema: {
|
|
11
29
|
type: "object",
|
|
12
30
|
properties: {
|
package/src/merchant/index.js
CHANGED
|
@@ -20,6 +20,12 @@ import { merchantProductTools } from './products/index.js';
|
|
|
20
20
|
// Deep links tools
|
|
21
21
|
import { merchantDeepLinksTools } from './deep-links/index.js';
|
|
22
22
|
|
|
23
|
+
// Logs tools (Premium feature)
|
|
24
|
+
import { merchantLogsTools } from './logs/index.js';
|
|
25
|
+
|
|
26
|
+
// Shop tools - needed before any call that takes a shop / shopCode
|
|
27
|
+
import { merchantShopTools } from './shops/index.js';
|
|
28
|
+
|
|
23
29
|
// Shared utility tools
|
|
24
30
|
import { getServerInfoTool } from '../utils/server-info.js';
|
|
25
31
|
|
|
@@ -48,7 +54,13 @@ export const merchantTools = [
|
|
|
48
54
|
...merchantProductTools,
|
|
49
55
|
|
|
50
56
|
// Deep links management
|
|
51
|
-
...merchantDeepLinksTools
|
|
57
|
+
...merchantDeepLinksTools,
|
|
58
|
+
|
|
59
|
+
// Logs management (Premium feature)
|
|
60
|
+
...merchantLogsTools,
|
|
61
|
+
|
|
62
|
+
// Shop lookup
|
|
63
|
+
...merchantShopTools
|
|
52
64
|
];
|
|
53
65
|
|
|
54
66
|
/**
|
|
@@ -83,6 +95,14 @@ export function getMerchantTools() {
|
|
|
83
95
|
else if (tool.name.startsWith('payware_deep_links_')) {
|
|
84
96
|
newName = tool.name; // Keep deep_links grouping
|
|
85
97
|
}
|
|
98
|
+
// Logs tools keep their logs grouping
|
|
99
|
+
else if (tool.name.startsWith('payware_logs_')) {
|
|
100
|
+
newName = tool.name; // Keep logs grouping
|
|
101
|
+
}
|
|
102
|
+
// Shop tools keep their shops grouping
|
|
103
|
+
else if (tool.name.startsWith('payware_shops_')) {
|
|
104
|
+
newName = tool.name; // Keep shops grouping
|
|
105
|
+
}
|
|
86
106
|
|
|
87
107
|
return {
|
|
88
108
|
...tool,
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merchant Logs Tools - Premium Feature
|
|
3
|
+
* Tools for querying and downloading application logs.
|
|
4
|
+
* Requires Premium (PRM) plan subscription.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
queryLogs,
|
|
9
|
+
getLogStatus,
|
|
10
|
+
getLogDownloadUrl,
|
|
11
|
+
downloadLogs,
|
|
12
|
+
LOG_LEVELS
|
|
13
|
+
} from '../../shared/logs/logs-api.js';
|
|
14
|
+
import { getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Query logs tool for merchants
|
|
18
|
+
*/
|
|
19
|
+
export const queryLogsTool = {
|
|
20
|
+
name: "payware_logs_query",
|
|
21
|
+
description: "Query application logs with filters. Premium plan required. Returns paginated JSON log entries for debugging and monitoring your integration.",
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
from: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "Start timestamp in ISO 8601 format (e.g., '2024-01-15T00:00:00Z'). Defaults to 24 hours ago."
|
|
28
|
+
},
|
|
29
|
+
to: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "End timestamp in ISO 8601 format (e.g., '2024-01-15T23:59:59Z'). Defaults to now."
|
|
32
|
+
},
|
|
33
|
+
level: {
|
|
34
|
+
type: "string",
|
|
35
|
+
enum: ["ERROR", "WARN", "INFO", "DEBUG"],
|
|
36
|
+
description: "Filter by log level. Use ERROR for errors only, WARN for warnings and above, etc."
|
|
37
|
+
},
|
|
38
|
+
logger: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "Filter by logger name (partial match). E.g., 'TransactionController' to see transaction-related logs."
|
|
41
|
+
},
|
|
42
|
+
search: {
|
|
43
|
+
type: "string",
|
|
44
|
+
description: "Search text in log messages. Case-insensitive partial match."
|
|
45
|
+
},
|
|
46
|
+
limit: {
|
|
47
|
+
type: "number",
|
|
48
|
+
description: "Maximum records to return (default 1000, max 10000).",
|
|
49
|
+
default: 1000
|
|
50
|
+
},
|
|
51
|
+
cursor: {
|
|
52
|
+
type: "string",
|
|
53
|
+
description: "Pagination cursor from previous response for fetching next page."
|
|
54
|
+
},
|
|
55
|
+
partnerId: {
|
|
56
|
+
type: "string",
|
|
57
|
+
description: "Partner ID from payware dashboard. Uses PAYWARE_PARTNER_ID env var as default.",
|
|
58
|
+
default: getPartnerIdSafe()
|
|
59
|
+
},
|
|
60
|
+
privateKey: {
|
|
61
|
+
type: "string",
|
|
62
|
+
description: "RSA private key for authentication. Uses environment-specific private key as default."
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
required: []
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
async handler(args) {
|
|
69
|
+
const {
|
|
70
|
+
from,
|
|
71
|
+
to,
|
|
72
|
+
level,
|
|
73
|
+
logger,
|
|
74
|
+
search,
|
|
75
|
+
limit = 1000,
|
|
76
|
+
cursor,
|
|
77
|
+
partnerId = getPartnerIdSafe(),
|
|
78
|
+
privateKey = getPrivateKeySafe()
|
|
79
|
+
} = args;
|
|
80
|
+
|
|
81
|
+
if (!partnerId || !privateKey) {
|
|
82
|
+
throw new Error("Partner ID and private key are required. Set PAYWARE_PARTNER_ID and environment-specific private key variables or provide them as parameters.");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const result = await queryLogs({
|
|
87
|
+
from,
|
|
88
|
+
to,
|
|
89
|
+
level,
|
|
90
|
+
logger,
|
|
91
|
+
search,
|
|
92
|
+
limit,
|
|
93
|
+
cursor,
|
|
94
|
+
partnerType: 'merchant',
|
|
95
|
+
partnerId,
|
|
96
|
+
privateKey
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const data = result.data;
|
|
100
|
+
const entries = data.entries || [];
|
|
101
|
+
const hasMore = data.hasMore || false;
|
|
102
|
+
const nextCursor = data.nextCursor;
|
|
103
|
+
|
|
104
|
+
// Format log entries for display
|
|
105
|
+
let logsPreview = '';
|
|
106
|
+
if (entries.length > 0) {
|
|
107
|
+
const displayEntries = entries.slice(0, 10); // Show first 10
|
|
108
|
+
logsPreview = displayEntries.map(log => {
|
|
109
|
+
const timestamp = log['@timestamp'] || log.timestamp || 'N/A';
|
|
110
|
+
const logLevel = log.level || 'N/A';
|
|
111
|
+
const loggerName = log.logger_name || log.loggerName || 'N/A';
|
|
112
|
+
const message = log.message || 'N/A';
|
|
113
|
+
const shortMessage = message.length > 100 ? message.substring(0, 100) + '...' : message;
|
|
114
|
+
return `[${timestamp}] ${logLevel} ${loggerName}\n ${shortMessage}`;
|
|
115
|
+
}).join('\n\n');
|
|
116
|
+
|
|
117
|
+
if (entries.length > 10) {
|
|
118
|
+
logsPreview += `\n\n... and ${entries.length - 10} more entries`;
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
logsPreview = 'No log entries found matching the criteria.';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Build filter summary
|
|
125
|
+
const filters = [];
|
|
126
|
+
if (from) filters.push(`from: ${from}`);
|
|
127
|
+
if (to) filters.push(`to: ${to}`);
|
|
128
|
+
if (level) filters.push(`level: ${level}`);
|
|
129
|
+
if (logger) filters.push(`logger: ${logger}`);
|
|
130
|
+
if (search) filters.push(`search: "${search}"`);
|
|
131
|
+
const filterSummary = filters.length > 0 ? filters.join(', ') : 'none (last 24 hours)';
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
content: [{
|
|
135
|
+
type: "text",
|
|
136
|
+
text: `📋 **Log Query Results**
|
|
137
|
+
|
|
138
|
+
**Query Summary:**
|
|
139
|
+
- Total Entries: ${data.totalCount || entries.length}
|
|
140
|
+
- Returned: ${data.returnedCount || entries.length}
|
|
141
|
+
- Has More: ${hasMore ? 'Yes' : 'No'}
|
|
142
|
+
- Filters: ${filterSummary}
|
|
143
|
+
|
|
144
|
+
**Log Entries Preview:**
|
|
145
|
+
\`\`\`
|
|
146
|
+
${logsPreview}
|
|
147
|
+
\`\`\`
|
|
148
|
+
|
|
149
|
+
${hasMore ? `**Pagination:**
|
|
150
|
+
Use cursor \`${nextCursor}\` to fetch the next page of results.` : ''}
|
|
151
|
+
|
|
152
|
+
**Log Levels:**
|
|
153
|
+
- 🔴 **ERROR**: Application errors and exceptions
|
|
154
|
+
- 🟠 **WARN**: Warnings that may need attention
|
|
155
|
+
- 🟢 **INFO**: Informational messages
|
|
156
|
+
- 🔵 **DEBUG**: Detailed debugging information
|
|
157
|
+
|
|
158
|
+
**Tips:**
|
|
159
|
+
- Use \`level: "ERROR"\` to quickly find errors
|
|
160
|
+
- Use \`search\` to find specific transaction IDs or error messages
|
|
161
|
+
- Use \`logger\` filter to focus on specific components
|
|
162
|
+
|
|
163
|
+
⚠️ **Note:** This is a Premium (PRM) plan feature.`
|
|
164
|
+
}]
|
|
165
|
+
};
|
|
166
|
+
} catch (error) {
|
|
167
|
+
throw new Error(`Failed to query logs: ${error.message}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get log status tool for merchants
|
|
174
|
+
*/
|
|
175
|
+
export const getLogStatusTool = {
|
|
176
|
+
name: "payware_logs_status",
|
|
177
|
+
description: "Get log availability and storage information. Premium plan required. Shows if logs are available, total size, and file count.",
|
|
178
|
+
inputSchema: {
|
|
179
|
+
type: "object",
|
|
180
|
+
properties: {
|
|
181
|
+
partnerId: {
|
|
182
|
+
type: "string",
|
|
183
|
+
description: "Partner ID from payware dashboard. Uses PAYWARE_PARTNER_ID env var as default.",
|
|
184
|
+
default: getPartnerIdSafe()
|
|
185
|
+
},
|
|
186
|
+
privateKey: {
|
|
187
|
+
type: "string",
|
|
188
|
+
description: "RSA private key for authentication. Uses environment-specific private key as default."
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
required: []
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
async handler(args) {
|
|
195
|
+
const {
|
|
196
|
+
partnerId = getPartnerIdSafe(),
|
|
197
|
+
privateKey = getPrivateKeySafe()
|
|
198
|
+
} = args;
|
|
199
|
+
|
|
200
|
+
if (!partnerId || !privateKey) {
|
|
201
|
+
throw new Error("Partner ID and private key are required. Set PAYWARE_PARTNER_ID and environment-specific private key variables or provide them as parameters.");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
const result = await getLogStatus({
|
|
206
|
+
partnerType: 'merchant',
|
|
207
|
+
partnerId,
|
|
208
|
+
privateKey
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const data = result.data;
|
|
212
|
+
|
|
213
|
+
// Format file size
|
|
214
|
+
const formatSize = (bytes) => {
|
|
215
|
+
if (!bytes) return '0 B';
|
|
216
|
+
const units = ['B', 'KB', 'MB', 'GB'];
|
|
217
|
+
let unitIndex = 0;
|
|
218
|
+
let size = bytes;
|
|
219
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
220
|
+
size /= 1024;
|
|
221
|
+
unitIndex++;
|
|
222
|
+
}
|
|
223
|
+
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
content: [{
|
|
228
|
+
type: "text",
|
|
229
|
+
text: `📊 **Log Status**
|
|
230
|
+
|
|
231
|
+
**Availability:**
|
|
232
|
+
- Partner ID: ${data.partnerId || partnerId}
|
|
233
|
+
- Logs Available: ${data.logsAvailable ? '✅ Yes' : '❌ No'}
|
|
234
|
+
|
|
235
|
+
**Storage Information:**
|
|
236
|
+
- Total Size: ${formatSize(data.totalSizeBytes)}
|
|
237
|
+
- File Count: ${data.fileCount || 0} files
|
|
238
|
+
|
|
239
|
+
**What You Can Do:**
|
|
240
|
+
${data.logsAvailable ? `
|
|
241
|
+
1. **Query logs** using \`payware_logs_query\` tool
|
|
242
|
+
- Filter by level, logger, search text, date range
|
|
243
|
+
- Paginate through results with cursor
|
|
244
|
+
|
|
245
|
+
2. **Download logs** using \`payware_logs_download_url\` tool
|
|
246
|
+
- Get compressed archive of logs for offline analysis
|
|
247
|
+
` : `
|
|
248
|
+
⚠️ No logs are currently available. Logs are generated when API calls are made.
|
|
249
|
+
`}
|
|
250
|
+
|
|
251
|
+
⚠️ **Note:** This is a Premium (PRM) plan feature.`
|
|
252
|
+
}]
|
|
253
|
+
};
|
|
254
|
+
} catch (error) {
|
|
255
|
+
throw new Error(`Failed to get log status: ${error.message}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Get log download URL tool for merchants
|
|
262
|
+
*/
|
|
263
|
+
export const getLogDownloadUrlTool = {
|
|
264
|
+
name: "payware_logs_download_url",
|
|
265
|
+
description: "Get download URL for logs archive. Premium plan required. Returns URL for downloading logs as gzipped JSON file.",
|
|
266
|
+
inputSchema: {
|
|
267
|
+
type: "object",
|
|
268
|
+
properties: {
|
|
269
|
+
from: {
|
|
270
|
+
type: "string",
|
|
271
|
+
description: "Start timestamp in ISO 8601 format (e.g., '2024-01-15T00:00:00Z'). Defaults to 24 hours ago."
|
|
272
|
+
},
|
|
273
|
+
to: {
|
|
274
|
+
type: "string",
|
|
275
|
+
description: "End timestamp in ISO 8601 format (e.g., '2024-01-15T23:59:59Z'). Defaults to now."
|
|
276
|
+
},
|
|
277
|
+
partnerId: {
|
|
278
|
+
type: "string",
|
|
279
|
+
description: "Partner ID from payware dashboard. Uses PAYWARE_PARTNER_ID env var as default.",
|
|
280
|
+
default: getPartnerIdSafe()
|
|
281
|
+
},
|
|
282
|
+
privateKey: {
|
|
283
|
+
type: "string",
|
|
284
|
+
description: "RSA private key for authentication. Uses environment-specific private key as default."
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
required: []
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
async handler(args) {
|
|
291
|
+
const {
|
|
292
|
+
from,
|
|
293
|
+
to,
|
|
294
|
+
partnerId = getPartnerIdSafe(),
|
|
295
|
+
privateKey = getPrivateKeySafe()
|
|
296
|
+
} = args;
|
|
297
|
+
|
|
298
|
+
if (!partnerId || !privateKey) {
|
|
299
|
+
throw new Error("Partner ID and private key are required. Set PAYWARE_PARTNER_ID and environment-specific private key variables or provide them as parameters.");
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
try {
|
|
303
|
+
const result = await getLogDownloadUrl({
|
|
304
|
+
from,
|
|
305
|
+
to,
|
|
306
|
+
partnerType: 'merchant',
|
|
307
|
+
partnerId,
|
|
308
|
+
privateKey
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const data = result.data;
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
content: [{
|
|
315
|
+
type: "text",
|
|
316
|
+
text: `📥 **Log Download Information**
|
|
317
|
+
|
|
318
|
+
**Download URL:**
|
|
319
|
+
\`${data.downloadUrl}\`
|
|
320
|
+
|
|
321
|
+
**Parameters:**
|
|
322
|
+
- From: ${data.parameters.from}
|
|
323
|
+
- To: ${data.parameters.to}
|
|
324
|
+
|
|
325
|
+
**Important:**
|
|
326
|
+
${data.note}
|
|
327
|
+
|
|
328
|
+
**File Format:**
|
|
329
|
+
- Content-Type: application/gzip
|
|
330
|
+
- Format: Gzipped newline-delimited JSON (NDJSON)
|
|
331
|
+
- Each line is a complete JSON log entry
|
|
332
|
+
|
|
333
|
+
**Usage Example (cURL):**
|
|
334
|
+
\`\`\`bash
|
|
335
|
+
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \\
|
|
336
|
+
-H "Api-Version: 1" \\
|
|
337
|
+
"${data.downloadUrl}" \\
|
|
338
|
+
-o logs.json.gz
|
|
339
|
+
\`\`\`
|
|
340
|
+
|
|
341
|
+
**Processing the Download:**
|
|
342
|
+
\`\`\`bash
|
|
343
|
+
# Decompress and view
|
|
344
|
+
gunzip -c logs.json.gz | head -10
|
|
345
|
+
|
|
346
|
+
# Parse with jq
|
|
347
|
+
gunzip -c logs.json.gz | jq '.level'
|
|
348
|
+
\`\`\`
|
|
349
|
+
|
|
350
|
+
⚠️ **Note:** This is a Premium (PRM) plan feature.`
|
|
351
|
+
}]
|
|
352
|
+
};
|
|
353
|
+
} catch (error) {
|
|
354
|
+
throw new Error(`Failed to get download URL: ${error.message}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* All merchant logs tools
|
|
361
|
+
*/
|
|
362
|
+
export const merchantLogsTools = [
|
|
363
|
+
queryLogsTool,
|
|
364
|
+
getLogStatusTool,
|
|
365
|
+
getLogDownloadUrlTool
|
|
366
|
+
];
|