@nullpay/mcp 1.0.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 +49 -0
- package/dist/aleo.d.ts +67 -0
- package/dist/aleo.js +515 -0
- package/dist/backend-client.d.ts +45 -0
- package/dist/backend-client.js +93 -0
- package/dist/crypto.d.ts +3 -0
- package/dist/crypto.js +66 -0
- package/dist/esm.d.ts +1 -0
- package/dist/esm.js +7 -0
- package/dist/protocol.d.ts +19 -0
- package/dist/protocol.js +120 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +111 -0
- package/dist/service.d.ts +179 -0
- package/dist/service.js +620 -0
- package/dist/session-store.d.ts +9 -0
- package/dist/session-store.js +32 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.js +2 -0
- package/dist/utils/crypto.d.ts +3 -0
- package/dist/utils/crypto.js +66 -0
- package/dist/utils/env.d.ts +6 -0
- package/dist/utils/env.js +15 -0
- package/dist/utils/esm.d.ts +1 -0
- package/dist/utils/esm.js +7 -0
- package/dist/utils/formatters.d.ts +14 -0
- package/dist/utils/formatters.js +132 -0
- package/package.json +39 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export type WalletPreference = 'main' | 'burner';
|
|
2
|
+
export type InvoiceType = 'standard' | 'multipay' | 'donation';
|
|
3
|
+
export type Currency = 'CREDITS' | 'USDCX' | 'USAD' | 'ANY';
|
|
4
|
+
export interface UserProfile {
|
|
5
|
+
address_hash: string;
|
|
6
|
+
main_address?: string | null;
|
|
7
|
+
burner_address?: string | null;
|
|
8
|
+
encrypted_burner_key?: string | null;
|
|
9
|
+
profile_main_invoice_hash?: string | null;
|
|
10
|
+
profile_burner_invoice_hash?: string | null;
|
|
11
|
+
updated_at?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface InvoiceRecord {
|
|
14
|
+
invoice_hash: string;
|
|
15
|
+
merchant_address?: string | null;
|
|
16
|
+
designated_address?: string | null;
|
|
17
|
+
merchant_address_hash?: string | null;
|
|
18
|
+
is_burner?: boolean;
|
|
19
|
+
payer_address?: string | null;
|
|
20
|
+
amount?: number | null;
|
|
21
|
+
amount_micro?: number | null;
|
|
22
|
+
memo?: string | null;
|
|
23
|
+
status: 'PENDING' | 'SETTLED';
|
|
24
|
+
block_height?: number | null;
|
|
25
|
+
block_settled?: number | null;
|
|
26
|
+
invoice_transaction_id?: string | null;
|
|
27
|
+
payment_tx_ids?: string[] | null;
|
|
28
|
+
created_at?: string;
|
|
29
|
+
updated_at?: string;
|
|
30
|
+
salt?: string | null;
|
|
31
|
+
invoice_type?: number | null;
|
|
32
|
+
token_type?: number | null;
|
|
33
|
+
invoice_items?: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
quantity: number;
|
|
36
|
+
unitPrice: number;
|
|
37
|
+
total: number;
|
|
38
|
+
}> | null;
|
|
39
|
+
for_sdk?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface SessionState {
|
|
42
|
+
address: string;
|
|
43
|
+
addressHash: string;
|
|
44
|
+
password: string;
|
|
45
|
+
activeWallet: WalletPreference;
|
|
46
|
+
encryptedMainAddress: string;
|
|
47
|
+
encryptedBurnerAddress?: string | null;
|
|
48
|
+
encryptedBurnerKey?: string | null;
|
|
49
|
+
mainPrivateKey?: string | null;
|
|
50
|
+
hasMainPrivateKeyInEnv?: boolean;
|
|
51
|
+
createdAt: string;
|
|
52
|
+
updatedAt: string;
|
|
53
|
+
}
|
|
54
|
+
export interface LoginArgs {
|
|
55
|
+
address?: string;
|
|
56
|
+
password?: string;
|
|
57
|
+
main_private_key?: string;
|
|
58
|
+
create_burner_wallet?: boolean;
|
|
59
|
+
wallet_preference?: WalletPreference;
|
|
60
|
+
}
|
|
61
|
+
export interface CreateInvoiceArgs {
|
|
62
|
+
amount: number;
|
|
63
|
+
currency?: Currency;
|
|
64
|
+
memo?: string;
|
|
65
|
+
invoice_type?: InvoiceType;
|
|
66
|
+
wallet?: WalletPreference;
|
|
67
|
+
line_items?: Array<{
|
|
68
|
+
name: string;
|
|
69
|
+
quantity: number;
|
|
70
|
+
unitPrice: number;
|
|
71
|
+
total: number;
|
|
72
|
+
}>;
|
|
73
|
+
}
|
|
74
|
+
export interface PayInvoiceArgs {
|
|
75
|
+
payment_link?: string;
|
|
76
|
+
invoice_hash?: string;
|
|
77
|
+
wallet?: WalletPreference;
|
|
78
|
+
amount?: number;
|
|
79
|
+
currency?: Exclude<Currency, 'ANY'>;
|
|
80
|
+
session_id?: string;
|
|
81
|
+
}
|
|
82
|
+
export interface GetTransactionInfoArgs {
|
|
83
|
+
invoice_hash?: string;
|
|
84
|
+
wallet?: WalletPreference;
|
|
85
|
+
limit?: number;
|
|
86
|
+
}
|
|
87
|
+
export interface InvoiceStatusData {
|
|
88
|
+
status: number;
|
|
89
|
+
tokenType: number;
|
|
90
|
+
invoiceType: number;
|
|
91
|
+
}
|
|
92
|
+
export interface ParsedOwnedInvoiceRecord {
|
|
93
|
+
owner: string;
|
|
94
|
+
invoiceHash: string;
|
|
95
|
+
amountMicro: number;
|
|
96
|
+
tokenType: number;
|
|
97
|
+
invoiceType: number;
|
|
98
|
+
salt: string;
|
|
99
|
+
memo: string;
|
|
100
|
+
walletType: number;
|
|
101
|
+
plaintext: string;
|
|
102
|
+
}
|
|
103
|
+
export interface ToolResult {
|
|
104
|
+
content: Array<{
|
|
105
|
+
type: 'text';
|
|
106
|
+
text: string;
|
|
107
|
+
}>;
|
|
108
|
+
structuredContent?: Record<string, unknown>;
|
|
109
|
+
isError?: boolean;
|
|
110
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.hashAddress = hashAddress;
|
|
7
|
+
exports.encryptWithPassword = encryptWithPassword;
|
|
8
|
+
exports.decryptWithPassword = decryptWithPassword;
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
const ITERATIONS = 100000;
|
|
11
|
+
const KEY_LENGTH = 32;
|
|
12
|
+
const DIGEST = 'sha256';
|
|
13
|
+
function toBase64(buffer) {
|
|
14
|
+
return Buffer.from(buffer).toString('base64');
|
|
15
|
+
}
|
|
16
|
+
function fromBase64(value) {
|
|
17
|
+
return Buffer.from(value, 'base64');
|
|
18
|
+
}
|
|
19
|
+
function hashAddress(address) {
|
|
20
|
+
return crypto_1.default.createHash('sha256').update(address).digest('hex');
|
|
21
|
+
}
|
|
22
|
+
async function encryptWithPassword(text, password) {
|
|
23
|
+
const salt = crypto_1.default.randomBytes(16);
|
|
24
|
+
const iv = crypto_1.default.randomBytes(12);
|
|
25
|
+
const key = await new Promise((resolve, reject) => {
|
|
26
|
+
crypto_1.default.pbkdf2(password, salt, ITERATIONS, KEY_LENGTH, DIGEST, (error, derivedKey) => {
|
|
27
|
+
if (error)
|
|
28
|
+
reject(error);
|
|
29
|
+
else
|
|
30
|
+
resolve(derivedKey);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
const cipher = crypto_1.default.createCipheriv('aes-256-gcm', key, iv);
|
|
34
|
+
const ciphertext = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
|
|
35
|
+
const tag = cipher.getAuthTag();
|
|
36
|
+
return `${toBase64(salt)}:${toBase64(iv)}:${toBase64(Buffer.concat([ciphertext, tag]))}`;
|
|
37
|
+
}
|
|
38
|
+
async function decryptWithPassword(payload, password) {
|
|
39
|
+
const parts = payload.split(':');
|
|
40
|
+
if (parts.length !== 3) {
|
|
41
|
+
throw new Error('Invalid encrypted payload format');
|
|
42
|
+
}
|
|
43
|
+
const [saltPart, ivPart, cipherPart] = parts;
|
|
44
|
+
const salt = fromBase64(saltPart);
|
|
45
|
+
const iv = fromBase64(ivPart);
|
|
46
|
+
const cipherWithTag = fromBase64(cipherPart);
|
|
47
|
+
const ciphertext = cipherWithTag.subarray(0, cipherWithTag.length - 16);
|
|
48
|
+
const tag = cipherWithTag.subarray(cipherWithTag.length - 16);
|
|
49
|
+
const key = await new Promise((resolve, reject) => {
|
|
50
|
+
crypto_1.default.pbkdf2(password, salt, ITERATIONS, KEY_LENGTH, DIGEST, (error, derivedKey) => {
|
|
51
|
+
if (error)
|
|
52
|
+
reject(error);
|
|
53
|
+
else
|
|
54
|
+
resolve(derivedKey);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
try {
|
|
58
|
+
const decipher = crypto_1.default.createDecipheriv('aes-256-gcm', key, iv);
|
|
59
|
+
decipher.setAuthTag(tag);
|
|
60
|
+
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
61
|
+
return plaintext.toString('utf8');
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
throw new Error('Incorrect password or corrupted data');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readEnvTrimmed = readEnvTrimmed;
|
|
4
|
+
exports.getMainWalletEnv = getMainWalletEnv;
|
|
5
|
+
function readEnvTrimmed(name) {
|
|
6
|
+
const value = process.env[name]?.trim();
|
|
7
|
+
return value ? value : undefined;
|
|
8
|
+
}
|
|
9
|
+
function getMainWalletEnv() {
|
|
10
|
+
return {
|
|
11
|
+
address: readEnvTrimmed('NULLPAY_MAIN_ADDRESS'),
|
|
12
|
+
password: readEnvTrimmed('NULLPAY_MAIN_PASSWORD'),
|
|
13
|
+
privateKey: readEnvTrimmed('NULLPAY_MAIN_PRIVATE_KEY') || readEnvTrimmed('NULLPAY_MAIN_PVT_KEY')
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function dynamicImport<T = any>(specifier: string): Promise<T>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Currency, InvoiceRecord, InvoiceType } from '../types';
|
|
2
|
+
export declare function normalizeCurrency(value?: string): Currency;
|
|
3
|
+
export declare function normalizePaymentCurrency(value?: string): Exclude<Currency, 'ANY'> | undefined;
|
|
4
|
+
export declare function normalizeInvoiceType(value?: string): InvoiceType;
|
|
5
|
+
export declare function tokenTypeLabel(tokenType?: number | null): string;
|
|
6
|
+
export declare function invoiceTypeLabel(invoiceType?: number | null): string;
|
|
7
|
+
export declare function currencyToTokenType(currency?: Currency | null): number;
|
|
8
|
+
export declare function linkTokenToCurrency(token?: string | null): Currency | undefined;
|
|
9
|
+
export declare function linkTypeToInvoiceType(type?: string | null): InvoiceType;
|
|
10
|
+
export declare function parseAmount(value?: string | number | null): number | undefined;
|
|
11
|
+
export declare function shouldMarkInvoiceSettled(invoiceType?: number | null): boolean;
|
|
12
|
+
export declare function formatInvoiceSummary(invoice: InvoiceRecord): string;
|
|
13
|
+
export declare function getAmountSource(invoice: InvoiceRecord): 'record' | 'database' | 'missing';
|
|
14
|
+
export declare function buildAmountLookupHint(invoice: InvoiceRecord, hasInvoiceLookupKey: boolean): string;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeCurrency = normalizeCurrency;
|
|
4
|
+
exports.normalizePaymentCurrency = normalizePaymentCurrency;
|
|
5
|
+
exports.normalizeInvoiceType = normalizeInvoiceType;
|
|
6
|
+
exports.tokenTypeLabel = tokenTypeLabel;
|
|
7
|
+
exports.invoiceTypeLabel = invoiceTypeLabel;
|
|
8
|
+
exports.currencyToTokenType = currencyToTokenType;
|
|
9
|
+
exports.linkTokenToCurrency = linkTokenToCurrency;
|
|
10
|
+
exports.linkTypeToInvoiceType = linkTypeToInvoiceType;
|
|
11
|
+
exports.parseAmount = parseAmount;
|
|
12
|
+
exports.shouldMarkInvoiceSettled = shouldMarkInvoiceSettled;
|
|
13
|
+
exports.formatInvoiceSummary = formatInvoiceSummary;
|
|
14
|
+
exports.getAmountSource = getAmountSource;
|
|
15
|
+
exports.buildAmountLookupHint = buildAmountLookupHint;
|
|
16
|
+
function normalizeCurrency(value) {
|
|
17
|
+
const normalized = (value || 'CREDITS').toUpperCase();
|
|
18
|
+
if (normalized === 'USDCX' || normalized === 'USAD' || normalized === 'ANY') {
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
return 'CREDITS';
|
|
22
|
+
}
|
|
23
|
+
function normalizePaymentCurrency(value) {
|
|
24
|
+
if (!value) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const normalized = value.toUpperCase();
|
|
28
|
+
if (normalized === 'USDCX' || normalized === 'USAD') {
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|
|
31
|
+
return 'CREDITS';
|
|
32
|
+
}
|
|
33
|
+
function normalizeInvoiceType(value) {
|
|
34
|
+
if (value === 'multipay' || value === 'donation')
|
|
35
|
+
return value;
|
|
36
|
+
return 'standard';
|
|
37
|
+
}
|
|
38
|
+
function tokenTypeLabel(tokenType) {
|
|
39
|
+
if (tokenType === 1)
|
|
40
|
+
return 'USDCX';
|
|
41
|
+
if (tokenType === 2)
|
|
42
|
+
return 'USAD';
|
|
43
|
+
if (tokenType === 3)
|
|
44
|
+
return 'ANY';
|
|
45
|
+
return 'CREDITS';
|
|
46
|
+
}
|
|
47
|
+
function invoiceTypeLabel(invoiceType) {
|
|
48
|
+
if (invoiceType === 1)
|
|
49
|
+
return 'multipay';
|
|
50
|
+
if (invoiceType === 2)
|
|
51
|
+
return 'donation';
|
|
52
|
+
return 'standard';
|
|
53
|
+
}
|
|
54
|
+
function currencyToTokenType(currency) {
|
|
55
|
+
if (currency === 'USDCX')
|
|
56
|
+
return 1;
|
|
57
|
+
if (currency === 'USAD')
|
|
58
|
+
return 2;
|
|
59
|
+
if (currency === 'ANY')
|
|
60
|
+
return 3;
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
function linkTokenToCurrency(token) {
|
|
64
|
+
if (!token) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const normalized = token.trim().toLowerCase();
|
|
68
|
+
if (normalized === 'usdcx')
|
|
69
|
+
return 'USDCX';
|
|
70
|
+
if (normalized === 'usad')
|
|
71
|
+
return 'USAD';
|
|
72
|
+
if (normalized === 'any')
|
|
73
|
+
return 'ANY';
|
|
74
|
+
return 'CREDITS';
|
|
75
|
+
}
|
|
76
|
+
function linkTypeToInvoiceType(type) {
|
|
77
|
+
if (type === 'multipay' || type === 'donation') {
|
|
78
|
+
return type;
|
|
79
|
+
}
|
|
80
|
+
return 'standard';
|
|
81
|
+
}
|
|
82
|
+
function parseAmount(value) {
|
|
83
|
+
if (typeof value === 'number') {
|
|
84
|
+
return Number.isFinite(value) ? value : undefined;
|
|
85
|
+
}
|
|
86
|
+
if (!value) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
const parsed = Number(value);
|
|
90
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
91
|
+
}
|
|
92
|
+
function shouldMarkInvoiceSettled(invoiceType) {
|
|
93
|
+
return invoiceType !== 1 && invoiceType !== 2;
|
|
94
|
+
}
|
|
95
|
+
function formatInvoiceSummary(invoice) {
|
|
96
|
+
const paymentIds = Array.isArray(invoice.payment_tx_ids) && invoice.payment_tx_ids.length > 0
|
|
97
|
+
? invoice.payment_tx_ids.join(', ')
|
|
98
|
+
: 'none';
|
|
99
|
+
const amount = invoice.amount ?? 0;
|
|
100
|
+
return [
|
|
101
|
+
`invoice=${invoice.invoice_hash}`,
|
|
102
|
+
`status=${invoice.status}`,
|
|
103
|
+
`amount=${amount}`,
|
|
104
|
+
`token=${tokenTypeLabel(invoice.token_type)}`,
|
|
105
|
+
`type=${invoiceTypeLabel(invoice.invoice_type)}`,
|
|
106
|
+
`created=${invoice.created_at || 'unknown'}`,
|
|
107
|
+
`invoice_tx=${invoice.invoice_transaction_id || 'none'}`,
|
|
108
|
+
`payment_txs=${paymentIds}`
|
|
109
|
+
].join(' | ');
|
|
110
|
+
}
|
|
111
|
+
function getAmountSource(invoice) {
|
|
112
|
+
if (typeof invoice.amount_micro === 'number') {
|
|
113
|
+
return 'record';
|
|
114
|
+
}
|
|
115
|
+
if (typeof invoice.amount === 'number' && invoice.amount > 0) {
|
|
116
|
+
return 'database';
|
|
117
|
+
}
|
|
118
|
+
return 'missing';
|
|
119
|
+
}
|
|
120
|
+
function buildAmountLookupHint(invoice, hasInvoiceLookupKey) {
|
|
121
|
+
const amountSource = getAmountSource(invoice);
|
|
122
|
+
if (amountSource === 'record') {
|
|
123
|
+
return ' | amount_source=record';
|
|
124
|
+
}
|
|
125
|
+
if (amountSource === 'database') {
|
|
126
|
+
return ' | amount_source=database';
|
|
127
|
+
}
|
|
128
|
+
if (hasInvoiceLookupKey) {
|
|
129
|
+
return ' | amount_source=missing | record_lookup=not_found_or_unreadable_for_selected_wallet';
|
|
130
|
+
}
|
|
131
|
+
return ' | amount_source=db_only (private key missing to fetch record-backed amount)';
|
|
132
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nullpay/mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "NullPay MCP server for conversational invoice and payment flows",
|
|
5
|
+
"main": "dist/server.js",
|
|
6
|
+
"types": "dist/server.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc -p tsconfig.json",
|
|
12
|
+
"start": "node dist/server.js",
|
|
13
|
+
"dev": "ts-node src/server.ts"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public",
|
|
17
|
+
"registry": "https://registry.npmjs.org/"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@provablehq/sdk": "^0.9.18",
|
|
21
|
+
"@provablehq/wasm": "^0.9.18"
|
|
22
|
+
},
|
|
23
|
+
"author": "geekofdhruv",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/geekofdhruv/NullPay.git",
|
|
28
|
+
"directory": "packages/nullpay-mcp"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/geekofdhruv/NullPay/issues"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/geekofdhruv/NullPay/tree/main/packages/nullpay-mcp#readme",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^25.4.0",
|
|
36
|
+
"ts-node": "^10.9.2",
|
|
37
|
+
"typescript": "^5.9.3"
|
|
38
|
+
}
|
|
39
|
+
}
|