@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.
@@ -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,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ export declare function hashAddress(address: string): string;
2
+ export declare function encryptWithPassword(text: string, password: string): Promise<string>;
3
+ export declare function decryptWithPassword(payload: string, password: string): Promise<string>;
@@ -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,6 @@
1
+ export declare function readEnvTrimmed(name: string): string | undefined;
2
+ export declare function getMainWalletEnv(): {
3
+ address: string | undefined;
4
+ password: string | undefined;
5
+ privateKey: string | undefined;
6
+ };
@@ -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,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dynamicImport = dynamicImport;
4
+ async function dynamicImport(specifier) {
5
+ const importer = new Function('s', 'return import(s);');
6
+ return await importer(specifier);
7
+ }
@@ -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
+ }