@payware/mcp-server 1.3.2 → 1.4.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/.env.example +4 -0
- package/README.md +18 -0
- package/package.json +7 -9
- package/src/auth/rsa-keys.js +12 -6
- package/src/auth/sandbox-setup.js +2 -0
- package/src/config/toolsets.js +104 -0
- package/src/core/auth/jwt-factory.js +4 -1
- package/src/core/auth/jwt-token.js +4 -0
- package/src/index.js +10 -6
- package/src/isv/data/index.js +15 -14
- package/src/isv/deep-links/delete-product-link.js +3 -2
- package/src/isv/deep-links/delete-transaction-link.js +3 -2
- package/src/isv/deep-links/get-product-link.js +8 -6
- package/src/isv/deep-links/get-transaction-link.js +8 -6
- package/src/isv/index.js +6 -0
- package/src/isv/invitations/index.js +5 -0
- package/src/isv/oauth2/get-token-info.js +10 -5
- package/src/isv/oauth2/obtain-token.js +9 -4
- package/src/isv/oauth2/token-helper.js +28 -26
- package/src/isv/poi/cancel-price.js +9 -2
- package/src/isv/poi/get-poi.js +4 -3
- package/src/isv/poi/get-qrcode.js +40 -9
- package/src/isv/poi/get-status.js +196 -168
- package/src/isv/poi/list-pois.js +6 -6
- package/src/isv/poi/set-price.js +40 -53
- package/src/isv/products/audios.js +8 -2
- package/src/isv/products/create-product.js +2 -0
- package/src/isv/products/delete-product.js +2 -0
- package/src/isv/products/get-product-image.js +2 -0
- package/src/isv/products/get-product.js +2 -0
- package/src/isv/products/list-products.js +2 -0
- package/src/isv/products/schedules.js +6 -0
- package/src/isv/products/update-product.js +2 -0
- package/src/isv/reference/index.js +2 -0
- package/src/isv/transactions/cancel-transaction.js +2 -0
- package/src/isv/transactions/create-transaction.js +2 -0
- package/src/isv/transactions/get-status.js +3 -1
- package/src/isv/transactions/process-transaction.js +2 -0
- package/src/isv/transactions/simulate-callback.js +21 -10
- package/src/isv/transactions/transaction-history.js +2 -0
- package/src/merchant/data/export-report.js +2 -0
- package/src/merchant/data/generate-report.js +2 -0
- package/src/merchant/data/get-export-list.js +2 -0
- package/src/merchant/data/get-report-requests.js +2 -0
- package/src/merchant/data/get-report-status.js +2 -0
- package/src/merchant/data/index.js +15 -10
- package/src/merchant/data/list-reports.js +2 -0
- package/src/merchant/deep-links/delete-product-link.js +3 -2
- package/src/merchant/deep-links/delete-transaction-link.js +3 -2
- package/src/merchant/deep-links/get-product-link.js +8 -6
- package/src/merchant/deep-links/get-transaction-link.js +8 -6
- package/src/merchant/index.js +7 -1
- package/src/merchant/logs/index.js +4 -0
- package/src/merchant/products/audios.js +15 -14
- package/src/merchant/products/create-product.js +3 -2
- package/src/merchant/products/delete-product.js +3 -2
- package/src/merchant/products/get-product-image.js +3 -2
- package/src/merchant/products/get-product.js +3 -2
- package/src/merchant/products/list-products.js +3 -2
- package/src/merchant/products/schedules.js +11 -10
- package/src/merchant/products/update-product.js +3 -2
- package/src/merchant/transactions/cancel-transaction.js +3 -2
- package/src/merchant/transactions/create-transaction.js +3 -1
- package/src/merchant/transactions/get-status.js +4 -3
- package/src/merchant/transactions/process-transaction.js +5 -4
- package/src/merchant/transactions/simulate-callback.js +325 -313
- package/src/merchant/transactions/transaction-history.js +7 -6
- package/src/payment-institution/data/index.js +15 -14
- package/src/payment-institution/deep-links/delete-transaction-link.js +3 -2
- package/src/payment-institution/deep-links/get-transaction-link.js +8 -6
- package/src/payment-institution/transactions/create-pi-transaction.js +4 -3
- package/src/payment-institution/transactions/finalize-transaction.js +6 -3
- package/src/payment-institution/transactions/get-transaction-history.js +8 -5
- package/src/payment-institution/transactions/get-transaction-status.js +16 -13
- package/src/payment-institution/transactions/process-pi-transaction.js +7 -6
- package/src/payment-institution/transactions/simulate-pi-callback.js +388 -375
- package/src/payment-institution/transactions/soundbite-transaction.js +6 -5
- package/src/proxy-server.js +25 -0
- package/src/shared/placements/api.js +51 -0
- package/src/shared/placements/tools.js +519 -0
- package/src/shared/poi/poi-create-api.js +4 -1
- package/src/shared/products/products-api.js +36 -25
- package/src/shared/shops/shops-api.js +2 -0
- package/src/shared/tool-annotations.js +53 -0
- package/src/tools/advanced-code-generator.js +17 -265
- package/src/utils/code-examples/common/auth-examples.js +1 -1
- package/src/utils/code-examples/isv/products.js +1 -1
- package/src/utils/code-examples/isv/transactions.js +1 -1
- package/src/utils/code-examples/merchant/transactions.js +1 -1
- package/src/utils/format-request.js +2 -0
- package/src/utils/json-formatter.js +2 -0
- package/src/utils/server-info.js +2 -0
- package/src/utils/code-examples.js +0 -646
|
@@ -3,6 +3,7 @@ import { createAuthHeaders } from '../auth-headers.js';
|
|
|
3
3
|
import { apiErrorResult } from '../api-errors.js';
|
|
4
4
|
import { createMinimizedJSON } from '../../core/utils/json-serializer.js';
|
|
5
5
|
import { getSandboxUrl, getProductionUrl } from '../../config/env.js';
|
|
6
|
+
import { CREATES } from '../tool-annotations.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Creating POIs (Points of Interaction) - the physical payment points a payer scans.
|
|
@@ -206,6 +207,7 @@ export function buildCreatePOITool({ partnerType, resolveAuth }) {
|
|
|
206
207
|
|
|
207
208
|
return {
|
|
208
209
|
name: 'payware_poi_create',
|
|
210
|
+
annotations: CREATES,
|
|
209
211
|
description: `Create a single POI (Point of Interaction) - a physical payment point a payer scans.
|
|
210
212
|
|
|
211
213
|
**Endpoint:** POST /poi -> 201 Created
|
|
@@ -241,7 +243,7 @@ ${isIsv ? `
|
|
|
241
243
|
},
|
|
242
244
|
callbackUrl: {
|
|
243
245
|
type: 'string',
|
|
244
|
-
description: 'HTTPS URL for POI
|
|
246
|
+
description: 'HTTPS URL for this POI\'s callbacks: poi.scanned (with the new transaction id), poi.expired (price not scanned) and the sale\'s TRANSACTION_FINALIZED (final status, with poiId). Signed by the ISV that set the price, otherwise the merchant. A POI without one sends no callbacks - there is no per-price callback URL. Must present a publicly-trusted TLS certificate and resolve to a public address.',
|
|
245
247
|
format: 'uri'
|
|
246
248
|
},
|
|
247
249
|
useSandbox: {
|
|
@@ -296,6 +298,7 @@ export function buildCreatePOIBatchTool({ partnerType, resolveAuth }) {
|
|
|
296
298
|
|
|
297
299
|
return {
|
|
298
300
|
name: 'payware_poi_create_batch',
|
|
301
|
+
annotations: CREATES,
|
|
299
302
|
description: `Create up to ${MAX_POI_BATCH_SIZE} POIs in a single **atomic** call - the tool for rolling out a terminal estate.
|
|
300
303
|
|
|
301
304
|
**Endpoint:** POST /poi/batch -> 201 Created, returning \`{ created, pois: [...] }\`
|
|
@@ -802,35 +802,46 @@ export async function updateAudio({
|
|
|
802
802
|
throw new Error('audioId is required');
|
|
803
803
|
}
|
|
804
804
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
805
|
+
// PATCH is metadata only. The server refuses a different productId there with
|
|
806
|
+
// ERR_AUDIO_REASSIGN_FORBIDDEN and moves an audio through POST .../{id}/transfer instead
|
|
807
|
+
// (AudioService.update), so a rename and a move are two calls. The rename goes first: if the move
|
|
808
|
+
// is then refused, the title the caller asked for is still applied.
|
|
809
|
+
const move = newProductId !== undefined && newProductId !== productId;
|
|
810
|
+
if (title === undefined && !move) {
|
|
811
|
+
throw new Error('Nothing to update: provide a title, or a newProductId different from productId');
|
|
812
|
+
}
|
|
809
813
|
|
|
810
|
-
const minimizedBody = createMinimizedJSON(requestBody);
|
|
811
|
-
const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
|
|
812
814
|
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
815
|
+
const audioUrl = `${baseUrl}/products/${productId}/audios/${audioId}`;
|
|
816
|
+
|
|
817
|
+
const send = async (method, url, requestBody, operation) => {
|
|
818
|
+
const minimizedBody = createMinimizedJSON(requestBody);
|
|
819
|
+
const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
|
|
820
|
+
try {
|
|
821
|
+
const response = await axios[method](url, minimizedBody, { headers });
|
|
822
|
+
return {
|
|
823
|
+
success: true,
|
|
824
|
+
data: response.data,
|
|
825
|
+
requestInfo: {
|
|
826
|
+
url,
|
|
827
|
+
method: method.toUpperCase(),
|
|
828
|
+
requestBody: minimizedBody,
|
|
829
|
+
statusCode: response.status
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
} catch (error) {
|
|
833
|
+
throw describeApiError(error, operation);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
813
836
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
);
|
|
820
|
-
|
|
821
|
-
return {
|
|
822
|
-
success: true,
|
|
823
|
-
data: response.data,
|
|
824
|
-
requestInfo: {
|
|
825
|
-
url: `${baseUrl}/products/${productId}/audios/${audioId}`,
|
|
826
|
-
method: 'PATCH',
|
|
827
|
-
requestBody: minimizedBody,
|
|
828
|
-
statusCode: response.status
|
|
829
|
-
}
|
|
830
|
-
};
|
|
831
|
-
} catch (error) {
|
|
832
|
-
throw describeApiError(error, 'update audio');
|
|
837
|
+
let result;
|
|
838
|
+
if (title !== undefined) {
|
|
839
|
+
result = await send('patch', audioUrl, { title }, 'update audio');
|
|
840
|
+
}
|
|
841
|
+
if (move) {
|
|
842
|
+
result = await send('post', `${audioUrl}/transfer`, { targetProductId: newProductId }, 'transfer audio');
|
|
833
843
|
}
|
|
844
|
+
return result;
|
|
834
845
|
}
|
|
835
846
|
|
|
836
847
|
/**
|
|
@@ -2,6 +2,7 @@ import axios from 'axios';
|
|
|
2
2
|
import { createAuthHeaders } from '../auth-headers.js';
|
|
3
3
|
import { apiErrorResult } from '../api-errors.js';
|
|
4
4
|
import { getSandboxUrl, getProductionUrl } from '../../config/env.js';
|
|
5
|
+
import { READS } from '../tool-annotations.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Shops - the merchant outlets a transaction, product or POI belongs to.
|
|
@@ -48,6 +49,7 @@ export function buildListShopsTool({ partnerType, resolveAuth }) {
|
|
|
48
49
|
|
|
49
50
|
return {
|
|
50
51
|
name: 'payware_shops_list',
|
|
52
|
+
annotations: READS,
|
|
51
53
|
description: `List the merchant outlets (shops) the caller can act on.
|
|
52
54
|
|
|
53
55
|
**Endpoint:** GET /shops
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool annotations, as the six combinations this server's tools actually fall into.
|
|
3
|
+
*
|
|
4
|
+
* Annotations are hints a client uses to decide how much to ask the user before running a tool: a
|
|
5
|
+
* read can run unattended, a destructive call should be confirmed, a non-idempotent one should not
|
|
6
|
+
* be retried blindly after a timeout. Every tool declares one of these as `annotations`, and
|
|
7
|
+
* tests/tool-contract.test.js fails on a tool that does not. tests/tool-routes.test.js checks the
|
|
8
|
+
* choice against the route the tool calls, so a GET cannot be declared destructive or a DELETE
|
|
9
|
+
* read-only.
|
|
10
|
+
*
|
|
11
|
+
* All four hints are always set. The protocol defaults are the cautious ones (not read-only,
|
|
12
|
+
* destructive, open world), so a tool that left them out would be presented as more dangerous than
|
|
13
|
+
* it is, and a directory that lists servers requires them to be explicit.
|
|
14
|
+
*
|
|
15
|
+
* "Open world" means the tool reaches the payware API, and through it real payers, merchants and
|
|
16
|
+
* money. The local tools - keys, tokens, code samples, formatting, callback simulation - do not.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** Computes something locally and calls nothing. */
|
|
20
|
+
export const LOCAL = Object.freeze({
|
|
21
|
+
readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/** Reads from the payware API and changes nothing. */
|
|
25
|
+
export const READS = Object.freeze({
|
|
26
|
+
readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Adds something that a repeat call returns rather than adds again: a shareable link, which the
|
|
31
|
+
* server mints on first request and records on the transaction, or a downloaded file saved locally.
|
|
32
|
+
*/
|
|
33
|
+
export const ADDS = Object.freeze({
|
|
34
|
+
readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/** Creates something new each time it is called: a transaction, a product, a report run. */
|
|
38
|
+
export const CREATES = Object.freeze({
|
|
39
|
+
readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/** Overwrites, cancels or deletes. Repeating it changes nothing further. */
|
|
43
|
+
export const CHANGES = Object.freeze({
|
|
44
|
+
readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: true
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Moves a payment forward irreversibly: processing it as the payer, or finalizing it as the
|
|
49
|
+
* institution. A retry after a timeout must not be automatic - the first call may have landed.
|
|
50
|
+
*/
|
|
51
|
+
export const COMMITS = Object.freeze({
|
|
52
|
+
readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true
|
|
53
|
+
});
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import { CommonTemplates } from '../utils/code-examples/common/helpers.js';
|
|
20
20
|
import { AuthGenerators } from '../utils/code-examples/common/auth-examples.js';
|
|
21
21
|
import { createDeterministicJSON } from '../core/utils/json-serializer.js';
|
|
22
|
+
import { LOCAL } from '../shared/tool-annotations.js';
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Advanced payware Code Generator
|
|
@@ -324,22 +325,21 @@ class AdvancedCodeGenerator {
|
|
|
324
325
|
*/
|
|
325
326
|
generateAuthenticationExample(language, partnerType, options) {
|
|
326
327
|
const AuthGen = AuthGenerators[language];
|
|
327
|
-
if (AuthGen) {
|
|
328
|
-
|
|
329
|
-
const envTemplate = generator.getEnvironmentTemplate(partnerType, options);
|
|
330
|
-
const depsTemplate = generator.getDependenciesTemplate(options);
|
|
331
|
-
const authTemplate = generator.getAuthTemplate(partnerType, options);
|
|
332
|
-
|
|
333
|
-
return this.wrapCompleteExample(
|
|
334
|
-
`${envTemplate}\n\n${depsTemplate}\n\n${authTemplate}`,
|
|
335
|
-
'Authentication Setup',
|
|
336
|
-
language,
|
|
337
|
-
partnerType,
|
|
338
|
-
options
|
|
339
|
-
);
|
|
340
|
-
} else {
|
|
341
|
-
return this.generateBasicAuthExample(language, partnerType, options);
|
|
328
|
+
if (!AuthGen) {
|
|
329
|
+
throw new Error(`No authentication generator for language: ${language}`);
|
|
342
330
|
}
|
|
331
|
+
const generator = new AuthGen();
|
|
332
|
+
const envTemplate = generator.getEnvironmentTemplate(partnerType, options);
|
|
333
|
+
const depsTemplate = generator.getDependenciesTemplate(options);
|
|
334
|
+
const authTemplate = generator.getAuthTemplate(partnerType, options);
|
|
335
|
+
|
|
336
|
+
return this.wrapCompleteExample(
|
|
337
|
+
`${envTemplate}\n\n${depsTemplate}\n\n${authTemplate}`,
|
|
338
|
+
'Authentication Setup',
|
|
339
|
+
language,
|
|
340
|
+
partnerType,
|
|
341
|
+
options
|
|
342
|
+
);
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
/**
|
|
@@ -1455,256 +1455,6 @@ echo "✅ Request completed"`;
|
|
|
1455
1455
|
return this.wrapCodeExample(code, opDef.description, 'bash', partnerType, options);
|
|
1456
1456
|
}
|
|
1457
1457
|
|
|
1458
|
-
|
|
1459
|
-
generateBasicAuthExample(language, partnerType, options) {
|
|
1460
|
-
const { includeComments = true } = options;
|
|
1461
|
-
|
|
1462
|
-
const authExamples = {
|
|
1463
|
-
python: `${includeComments ? '# Basic Authentication Setup - Python' : ''}
|
|
1464
|
-
import jwt
|
|
1465
|
-
import json
|
|
1466
|
-
import hashlib
|
|
1467
|
-
import base64
|
|
1468
|
-
from datetime import datetime, timezone
|
|
1469
|
-
|
|
1470
|
-
def create_jwt_token(request_body=None):
|
|
1471
|
-
${includeComments ? '"""Create JWT token for payware API authentication"""' : ''}
|
|
1472
|
-
partner_id = "YOUR_PARTNER_ID"
|
|
1473
|
-
private_key = """-----BEGIN RSA PRIVATE KEY-----
|
|
1474
|
-
YOUR_PRIVATE_KEY_HERE
|
|
1475
|
-
-----END RSA PRIVATE KEY-----"""
|
|
1476
|
-
|
|
1477
|
-
# Create content SHA-256 for request body
|
|
1478
|
-
content_sha256 = ""
|
|
1479
|
-
if request_body:
|
|
1480
|
-
content_sha256 = base64.b64encode(hashlib.sha256(request_body.encode()).digest()).decode()
|
|
1481
|
-
|
|
1482
|
-
# JWT payload
|
|
1483
|
-
payload = {
|
|
1484
|
-
"iss": partner_id,
|
|
1485
|
-
"aud": "payware.eu",
|
|
1486
|
-
"iat": int(datetime.now(timezone.utc).timestamp()),
|
|
1487
|
-
"exp": int(datetime.now(timezone.utc).timestamp()) + 300,
|
|
1488
|
-
"contentSha256": content_sha256
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
# Create JWT token
|
|
1492
|
-
token = jwt.encode(payload, private_key, algorithm="RS256")
|
|
1493
|
-
return token
|
|
1494
|
-
|
|
1495
|
-
${includeComments ? '# Example usage' : ''}
|
|
1496
|
-
token = create_jwt_token()
|
|
1497
|
-
print(f"JWT Token: {token}")`,
|
|
1498
|
-
|
|
1499
|
-
nodejs: `${includeComments ? '// Basic Authentication Setup - Node.js' : ''}
|
|
1500
|
-
const jwt = require('jsonwebtoken');
|
|
1501
|
-
const crypto = require('crypto');
|
|
1502
|
-
|
|
1503
|
-
function createJWTToken(requestBody = null) {
|
|
1504
|
-
/**
|
|
1505
|
-
* Create JWT token for payware API authentication
|
|
1506
|
-
*/
|
|
1507
|
-
const partnerId = "YOUR_PARTNER_ID";
|
|
1508
|
-
const privateKey = \`-----BEGIN RSA PRIVATE KEY-----
|
|
1509
|
-
YOUR_PRIVATE_KEY_HERE
|
|
1510
|
-
-----END RSA PRIVATE KEY-----\`;
|
|
1511
|
-
|
|
1512
|
-
${includeComments ? '// Create content SHA-256' : ''} for request body
|
|
1513
|
-
let contentSha256 = "";
|
|
1514
|
-
if (requestBody) {
|
|
1515
|
-
contentSha256 = crypto.createHash('sha256').update(requestBody).digest('base64');
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
// JWT payload
|
|
1519
|
-
const payload = {
|
|
1520
|
-
iss: partnerId,
|
|
1521
|
-
aud: "payware.eu",
|
|
1522
|
-
iat: Math.floor(Date.now() / 1000),
|
|
1523
|
-
exp: Math.floor(Date.now() / 1000) + 300,
|
|
1524
|
-
contentSha256: contentSha256
|
|
1525
|
-
};
|
|
1526
|
-
|
|
1527
|
-
// Create JWT token
|
|
1528
|
-
const token = jwt.sign(payload, privateKey, { algorithm: 'RS256' });
|
|
1529
|
-
return token;
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
${includeComments ? '// Example usage' : ''}
|
|
1533
|
-
const token = createJWTToken();
|
|
1534
|
-
console.log(\`JWT Token: \${token}\`);`,
|
|
1535
|
-
|
|
1536
|
-
java: `${includeComments ? '// Basic Authentication Setup - Java' : ''}
|
|
1537
|
-
import io.jsonwebtoken.Jwts;
|
|
1538
|
-
import io.jsonwebtoken.SignatureAlgorithm;
|
|
1539
|
-
import java.security.PrivateKey;
|
|
1540
|
-
import java.security.spec.PKCS8EncodedKeySpec;
|
|
1541
|
-
import java.security.KeyFactory;
|
|
1542
|
-
import java.util.Date;
|
|
1543
|
-
import java.util.Map;
|
|
1544
|
-
import java.util.HashMap;
|
|
1545
|
-
import java.security.MessageDigest;
|
|
1546
|
-
import java.util.Base64;
|
|
1547
|
-
|
|
1548
|
-
public class PaywareAuth {
|
|
1549
|
-
|
|
1550
|
-
private static String createJWTToken(String requestBody) {
|
|
1551
|
-
try {
|
|
1552
|
-
String partnerId = "YOUR_PARTNER_ID";
|
|
1553
|
-
String privateKeyPEM = "-----BEGIN RSA PRIVATE KEY-----\\nYOUR_PRIVATE_KEY_HERE\\n-----END RSA PRIVATE KEY-----";
|
|
1554
|
-
|
|
1555
|
-
${includeComments ? '// Create content SHA-256' : ''}
|
|
1556
|
-
String contentSha256 = "";
|
|
1557
|
-
if (requestBody != null) {
|
|
1558
|
-
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
1559
|
-
byte[] digest = md.digest(requestBody.getBytes());
|
|
1560
|
-
contentSha256 = Base64.getEncoder().encodeToString(digest);
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
// JWT payload
|
|
1564
|
-
Map<String, Object> claims = new HashMap<>();
|
|
1565
|
-
claims.put("iss", partnerId);
|
|
1566
|
-
claims.put("aud", "payware.eu");
|
|
1567
|
-
claims.put("iat", new Date().getTime() / 1000);
|
|
1568
|
-
claims.put("exp", (new Date().getTime() / 1000) + 300);
|
|
1569
|
-
claims.put("contentSha256", contentSha256);
|
|
1570
|
-
|
|
1571
|
-
// Note: You'll need to implement private key loading
|
|
1572
|
-
// PrivateKey privateKey = loadPrivateKey(privateKeyPEM);
|
|
1573
|
-
|
|
1574
|
-
return "your-jwt-token"; // Placeholder - implement JWT creation
|
|
1575
|
-
|
|
1576
|
-
} catch (Exception e) {
|
|
1577
|
-
throw new RuntimeException("Failed to create JWT token", e);
|
|
1578
|
-
}
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
public static void main(String[] args) {
|
|
1582
|
-
String token = createJWTToken(null);
|
|
1583
|
-
System.out.println("JWT Token: " + token);
|
|
1584
|
-
}
|
|
1585
|
-
}`,
|
|
1586
|
-
|
|
1587
|
-
csharp: `${includeComments ? '// Basic Authentication Setup - C#' : ''}
|
|
1588
|
-
using System;
|
|
1589
|
-
using System.Text;
|
|
1590
|
-
using System.Security.Cryptography;
|
|
1591
|
-
using Microsoft.IdentityModel.Tokens;
|
|
1592
|
-
using System.IdentityModel.Tokens.Jwt;
|
|
1593
|
-
using System.Security.Claims;
|
|
1594
|
-
|
|
1595
|
-
public class PaywareAuth
|
|
1596
|
-
{
|
|
1597
|
-
private static string CreateJWTToken(string requestBody = null)
|
|
1598
|
-
{
|
|
1599
|
-
var partnerId = "YOUR_PARTNER_ID";
|
|
1600
|
-
var privateKeyPEM = @"-----BEGIN RSA PRIVATE KEY-----
|
|
1601
|
-
YOUR_PRIVATE_KEY_HERE
|
|
1602
|
-
-----END RSA PRIVATE KEY-----";
|
|
1603
|
-
|
|
1604
|
-
${includeComments ? '// Create content SHA-256' : ''}
|
|
1605
|
-
var contentSha256 = "";
|
|
1606
|
-
if (!string.IsNullOrEmpty(requestBody))
|
|
1607
|
-
{
|
|
1608
|
-
using (var sha256 = SHA256.Create())
|
|
1609
|
-
{
|
|
1610
|
-
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(requestBody));
|
|
1611
|
-
contentSha256 = Convert.ToBase64String(hash);
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
// JWT payload
|
|
1616
|
-
var claims = new[]
|
|
1617
|
-
{
|
|
1618
|
-
new Claim("iss", partnerId),
|
|
1619
|
-
new Claim("aud", "payware.eu"),
|
|
1620
|
-
new Claim("iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer),
|
|
1621
|
-
new Claim("exp", DateTimeOffset.UtcNow.AddMinutes(5).ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer),
|
|
1622
|
-
new Claim("contentSha256", contentSha256)
|
|
1623
|
-
};
|
|
1624
|
-
|
|
1625
|
-
// Note: You'll need to implement RSA key loading
|
|
1626
|
-
// var rsa = RSA.Create();
|
|
1627
|
-
// rsa.ImportFromPem(privateKeyPEM);
|
|
1628
|
-
// var key = new RsaSecurityKey(rsa);
|
|
1629
|
-
|
|
1630
|
-
return "your-jwt-token"; // Placeholder - implement JWT creation
|
|
1631
|
-
}
|
|
1632
|
-
|
|
1633
|
-
public static void Main(string[] args)
|
|
1634
|
-
{
|
|
1635
|
-
var token = CreateJWTToken();
|
|
1636
|
-
Console.WriteLine($"JWT Token: {token}");
|
|
1637
|
-
}
|
|
1638
|
-
}`,
|
|
1639
|
-
|
|
1640
|
-
php: `${includeComments ? '<?php // Basic Authentication Setup - PHP' : '<?php'}
|
|
1641
|
-
require_once 'vendor/autoload.php';
|
|
1642
|
-
use Firebase\\JWT\\JWT;
|
|
1643
|
-
use Firebase\\JWT\\Key;
|
|
1644
|
-
|
|
1645
|
-
function createJWTToken($requestBody = null) {
|
|
1646
|
-
$partnerId = "YOUR_PARTNER_ID";
|
|
1647
|
-
$privateKey = "-----BEGIN RSA PRIVATE KEY-----
|
|
1648
|
-
YOUR_PRIVATE_KEY_HERE
|
|
1649
|
-
-----END RSA PRIVATE KEY-----";
|
|
1650
|
-
|
|
1651
|
-
${includeComments ? '// Create content SHA-256' : ''}
|
|
1652
|
-
$contentSha256 = "";
|
|
1653
|
-
if ($requestBody !== null) {
|
|
1654
|
-
$contentSha256 = base64_encode(hash('sha256', $requestBody, true));
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
// JWT payload
|
|
1658
|
-
$payload = [
|
|
1659
|
-
'iss' => $partnerId,
|
|
1660
|
-
'aud' => 'payware.eu',
|
|
1661
|
-
'iat' => time(),
|
|
1662
|
-
'exp' => time() + 300,
|
|
1663
|
-
'contentSha256' => $contentSha256
|
|
1664
|
-
];
|
|
1665
|
-
|
|
1666
|
-
// Create JWT token
|
|
1667
|
-
$token = JWT::encode($payload, $privateKey, 'RS256');
|
|
1668
|
-
return $token;
|
|
1669
|
-
}
|
|
1670
|
-
|
|
1671
|
-
${includeComments ? '// Example usage' : ''}
|
|
1672
|
-
$token = createJWTToken();
|
|
1673
|
-
echo "JWT Token: " . $token . "\\n";
|
|
1674
|
-
?>`,
|
|
1675
|
-
|
|
1676
|
-
curl: `${includeComments ? '#!/bin/bash\n# Basic Authentication Setup - cURL' : '#!/bin/bash'}
|
|
1677
|
-
|
|
1678
|
-
# Configuration
|
|
1679
|
-
PARTNER_ID="YOUR_PARTNER_ID"
|
|
1680
|
-
PRIVATE_KEY_FILE="path/to/private-key.pem"
|
|
1681
|
-
|
|
1682
|
-
# Function to create JWT token (simplified)
|
|
1683
|
-
create_jwt_token() {
|
|
1684
|
-
local request_body="\$1"
|
|
1685
|
-
local content_sha256=""
|
|
1686
|
-
|
|
1687
|
-
if [ -n "\$request_body" ]; then
|
|
1688
|
-
content_sha256=\$(echo -n "\$request_body" | openssl dgst -sha256 -binary | base64)
|
|
1689
|
-
fi
|
|
1690
|
-
|
|
1691
|
-
echo "your-jwt-token" # Placeholder - implement JWT creation with openssl
|
|
1692
|
-
}
|
|
1693
|
-
|
|
1694
|
-
${includeComments ? '# Example usage' : ''}
|
|
1695
|
-
JWT_TOKEN=\$(create_jwt_token)
|
|
1696
|
-
echo "JWT Token: \$JWT_TOKEN"`
|
|
1697
|
-
};
|
|
1698
|
-
|
|
1699
|
-
return this.wrapCodeExample(
|
|
1700
|
-
authExamples[language] || authExamples.python,
|
|
1701
|
-
'Authentication Setup',
|
|
1702
|
-
language,
|
|
1703
|
-
partnerType,
|
|
1704
|
-
options
|
|
1705
|
-
);
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
1458
|
// Helper methods for Java code generation
|
|
1709
1459
|
toPascalCase(str) {
|
|
1710
1460
|
return str.split(/[-_]/).map(word =>
|
|
@@ -1986,6 +1736,7 @@ export const advancedCodeGenerator = new AdvancedCodeGenerator();
|
|
|
1986
1736
|
*/
|
|
1987
1737
|
export const generateCodeExampleTool = {
|
|
1988
1738
|
name: 'payware_generate_code_example',
|
|
1739
|
+
annotations: LOCAL,
|
|
1989
1740
|
description: 'Generate production-ready payware API integration code examples with authentication, error handling, and environment configuration for any operation across 16 supported operations and 6 programming languages.',
|
|
1990
1741
|
|
|
1991
1742
|
inputSchema: {
|
|
@@ -2126,6 +1877,7 @@ Use different parameters to explore all available options!
|
|
|
2126
1877
|
*/
|
|
2127
1878
|
export const generateDocumentationTool = {
|
|
2128
1879
|
name: 'payware_generate_documentation',
|
|
1880
|
+
annotations: LOCAL,
|
|
2129
1881
|
description: 'Generate comprehensive documentation for payware API integration with quick start instructions, authentication flows, operation examples, error handling patterns, and language-specific integration guides.',
|
|
2130
1882
|
|
|
2131
1883
|
inputSchema: {
|
|
@@ -68,7 +68,7 @@ from cryptography.hazmat.primitives import serialization`;
|
|
|
68
68
|
${options.includeComments ? '# Create JWT payload\n ' : ''}payload = {
|
|
69
69
|
'iss': partner_id,
|
|
70
70
|
'aud': 'https://payware.eu',
|
|
71
|
-
'iat': int(datetime.
|
|
71
|
+
'iat': int(datetime.now().timestamp())
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
${options.includeComments ? '# Create and return token\n ' : ''}token = jwt.encode(payload, private_key, algorithm='RS256', headers=header)
|
|
@@ -295,7 +295,7 @@ def create_isv_jwt_token(merchant_partner_id, oauth2_token, request_body=None, u
|
|
|
295
295
|
'iss': isv_partner_id, # ISV Partner ID
|
|
296
296
|
'aud': merchant_partner_id, # Target Merchant ID
|
|
297
297
|
'sub': oauth2_token, # OAuth2 access token
|
|
298
|
-
'iat': int(datetime.
|
|
298
|
+
'iat': int(datetime.now().timestamp())
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
# Create and return token
|
|
@@ -217,7 +217,7 @@ def create_isv_jwt_token(merchant_partner_id, oauth2_token, request_body=None, u
|
|
|
217
217
|
'iss': config['isv_partner_id'], # ISV Partner ID
|
|
218
218
|
'aud': merchant_partner_id, # Target Merchant ID
|
|
219
219
|
'sub': oauth2_token, # OAuth2 access token
|
|
220
|
-
'iat': int(datetime.
|
|
220
|
+
'iat': int(datetime.now().timestamp())
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
# Create token
|
|
@@ -171,7 +171,7 @@ def create_jwt_token(request_body=None, use_sandbox=True):
|
|
|
171
171
|
payload = {
|
|
172
172
|
'iss': config['partner_id'],
|
|
173
173
|
'aud': 'https://payware.eu',
|
|
174
|
-
'iat': int(datetime.
|
|
174
|
+
'iat': int(datetime.now().timestamp())
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
# Create token
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { createMinimizedJSON } from '../core/utils/json-serializer.js';
|
|
6
|
+
import { LOCAL } from '../shared/tool-annotations.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Format transaction request data
|
|
@@ -165,6 +166,7 @@ export function formatCurlCommand(method, endpoint, headers, body = null) {
|
|
|
165
166
|
*/
|
|
166
167
|
export const formatRequestTool = {
|
|
167
168
|
name: "payware_utils_format_request",
|
|
169
|
+
annotations: LOCAL,
|
|
168
170
|
description: "Format and validate payware API requests with proper structure and headers",
|
|
169
171
|
inputSchema: {
|
|
170
172
|
type: "object",
|
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
import { createDeterministicJSON, validateJSONConsistency } from '../core/utils/json-serializer.js';
|
|
7
7
|
import { generateContentSha256 } from '../core/auth/jwt-token.js';
|
|
8
|
+
import { LOCAL } from '../shared/tool-annotations.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Format JSON with deterministic serialization tool
|
|
11
12
|
*/
|
|
12
13
|
export const formatJSONDeterministicTool = {
|
|
13
14
|
name: "payware_utils_format_json_deterministic",
|
|
15
|
+
annotations: LOCAL,
|
|
14
16
|
description: "Format JSON payload with deterministic key sorting for consistent SHA-256 calculation and payware API compliance",
|
|
15
17
|
inputSchema: {
|
|
16
18
|
type: "object",
|
package/src/utils/server-info.js
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
import { readFileSync } from 'fs';
|
|
6
6
|
import { getPartnerTypeSafe, getSandboxUrl, getProductionUrl } from '../config/env.js';
|
|
7
7
|
import { getPartnerDisplayInfo, getPartnerConfig } from '../config/partner-types.js';
|
|
8
|
+
import { LOCAL } from '../shared/tool-annotations.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Get server information tool implementation
|
|
11
12
|
*/
|
|
12
13
|
export const getServerInfoTool = {
|
|
13
14
|
name: "payware_utils_server_info",
|
|
15
|
+
annotations: LOCAL,
|
|
14
16
|
description: "Get MCP server version, status, and environment information",
|
|
15
17
|
inputSchema: {
|
|
16
18
|
type: "object",
|