@nullpay/mcp 1.0.0 → 1.0.1

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 CHANGED
@@ -1,49 +1,60 @@
1
- # @nullpay/mcp
1
+ # NullPay MCP
2
2
 
3
- NullPay MCP (Model Context Protocol) server for conversational invoice and payment flows.
3
+ NullPay MCP installs a local MCP server for Claude and lets users connect with only their wallet credentials.
4
4
 
5
- This server allows AI agents to interact with the NullPay protocol, enabling them to create invoices, track payments, and manage merchant flows directly through chat.
5
+ ## Install
6
6
 
7
- ## Features
7
+ ```bash
8
+ npx -y @nullpay/mcp
9
+ ```
8
10
 
9
- - **Tool-based Interaction**: Exposes tools for creating NullPay invoices.
10
- - **Privacy First**: Built on top of the Aleo blockchain with Zero-Knowledge Proofs.
11
- - **Stdio Transport**: Compatible with MCP clients like Claude Desktop.
11
+ The setup wizard asks whether to install into Claude Code or Claude Desktop, then writes the required MCP config automatically on the user's machine.
12
12
 
13
- ## Installation
13
+ ## User-provided env
14
14
 
15
- ```bash
16
- npm install @nullpay/mcp
17
- ```
15
+ Users only need to provide:
18
16
 
19
- ## Usage
20
-
21
- ### As an MCP Server
22
-
23
- Add the following to your MCP client configuration (e.g., `claude_desktop_config.json`):
24
-
25
- ```json
26
- {
27
- "mcpServers": {
28
- "nullpay": {
29
- "command": "npx",
30
- "args": ["-y", "@nullpay/mcp"],
31
- "env": {
32
- "NULLPAY_BACKEND_URL": "https://your-api.com/api",
33
- "NULLPAY_MCP_SHARED_SECRET": "your-secret"
34
- }
35
- }
36
- }
37
- }
38
- ```
17
+ - `NULLPAY_MAIN_ADDRESS`
18
+ - `NULLPAY_MAIN_PRIVATE_KEY`
19
+ - `NULLPAY_MAIN_PASSWORD`
20
+
21
+ ## Tools
22
+
23
+ - `login`
24
+ - `create_invoice`
25
+ - `pay_invoice`
26
+ - `get_transaction_info`
27
+
28
+ ## Environment
29
+
30
+ Bundled by NullPay inside the package:
31
+
32
+ - production backend URL
33
+ - public NullPay base URL
34
+ - Provable API key
35
+ - Provable consumer ID
36
+
37
+ Optional main-wallet credentials for record-backed transaction lookup and automated main-wallet payments:
38
+
39
+ - `NULLPAY_MAIN_ADDRESS`
40
+ - `NULLPAY_MAIN_PASSWORD`
41
+ - `NULLPAY_MAIN_PRIVATE_KEY`
42
+
43
+ `NULLPAY_MAIN_PVT_KEY` is also accepted as a legacy alias for the private key.
44
+
45
+ When Claude launches the MCP server, it also loads env values from these files if present:
39
46
 
40
- ## Configuration
47
+ - `packages/nullpay-mcp/.env`
48
+ - repo-root `.env`
49
+ - `backend/.env`
41
50
 
42
- The server requires the following environment variables:
51
+ For relayed invoice creation and sponsored execution, the backend still needs:
43
52
 
44
- - `NULLPAY_BACKEND_URL`: The base URL of your NullPay backend instance.
45
- - `NULLPAY_MCP_SHARED_SECRET`: A shared secret to authenticate with the backend.
53
+ - `RELAYER_PRIVATE_KEY`
46
54
 
47
- ## License
55
+ ## Notes
48
56
 
49
- MIT
57
+ - Burner wallet private keys remain encrypted at rest in the existing `users` table.
58
+ - The MCP server decrypts burner keys only in memory during payment execution.
59
+ - If `NULLPAY_MAIN_PRIVATE_KEY` is available, the MCP server can fetch invoice amounts from main-wallet records and pay invoices from the main wallet without exposing that key to the model.
60
+ - If the main private key is not available, the MCP server still allows login and invoice creation, and it prompts the user to add the env var for record-backed amount lookup and automated main-wallet payments.
package/dist/aleo.js CHANGED
@@ -19,6 +19,7 @@ exports.enrichInvoiceWithRecordAmount = enrichInvoiceWithRecordAmount;
19
19
  exports.createSponsoredPaymentAuthorization = createSponsoredPaymentAuthorization;
20
20
  const crypto_1 = __importDefault(require("crypto"));
21
21
  const esm_1 = require("./esm");
22
+ const env_1 = require("./env");
22
23
  exports.PROGRAM_ID = 'zk_pay_proofs_privacy_v22.aleo';
23
24
  const FREEZELIST_PROGRAM_ID = 'test_usdcx_freezelist.aleo';
24
25
  const EXPLORER_BASE = 'https://api.explorer.provable.com/v1';
@@ -206,12 +207,8 @@ function resolvePaymentMode(invoice, fallbackAmount, fallbackCurrency) {
206
207
  amountSuffix: 'u64',
207
208
  };
208
209
  }
209
- function getProvableConsumerId() {
210
- return process.env.PROVABLE_CONSUMER_ID || process.env.PROVABLE_CONSUMER_KEY;
211
- }
212
210
  async function getScannerSession(privateKey) {
213
- const provableApiKey = process.env.PROVABLE_API_KEY;
214
- const consumerId = getProvableConsumerId();
211
+ const { apiKey: provableApiKey, consumerId } = (0, env_1.getProvableConfig)();
215
212
  if (!provableApiKey || !consumerId) {
216
213
  throw new Error('PROVABLE_API_KEY and PROVABLE_CONSUMER_ID/PROVABLE_CONSUMER_KEY are required for record fetching and payment automation.');
217
214
  }
@@ -1,8 +1,7 @@
1
1
  import { InvoiceRecord, UserProfile } from './types';
2
2
  export declare class NullPayBackendClient {
3
3
  private readonly baseUrl;
4
- private readonly mcpSecret?;
5
- constructor(baseUrl: string, mcpSecret?: string | undefined);
4
+ constructor(baseUrl: string);
6
5
  private buildUrl;
7
6
  private request;
8
7
  getUserProfile(addressHash: string): Promise<UserProfile | null>;
@@ -2,20 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NullPayBackendClient = void 0;
4
4
  function mapBackendError(path, text) {
5
- if (path === '/mcp/relay/create-invoice') {
6
- if (text.includes('NULLPAY_MCP_SHARED_SECRET is not configured')) {
7
- return 'Invoice creation is blocked because NULLPAY_MCP_SHARED_SECRET is missing on the backend. Set the same NULLPAY_MCP_SHARED_SECRET value in both the backend env and the MCP server env, then restart both processes.';
8
- }
9
- if (text.includes('Invalid MCP shared secret')) {
10
- return 'Invoice creation is blocked because the MCP shared secret does not match. Set the same NULLPAY_MCP_SHARED_SECRET value in both the backend env and the MCP server env, then restart both processes.';
11
- }
12
- }
13
5
  return text;
14
6
  }
15
7
  class NullPayBackendClient {
16
- constructor(baseUrl, mcpSecret) {
8
+ constructor(baseUrl) {
17
9
  this.baseUrl = baseUrl;
18
- this.mcpSecret = mcpSecret;
19
10
  }
20
11
  buildUrl(path) {
21
12
  return `${this.baseUrl.replace(/\/+$/, '')}${path}`;
@@ -75,10 +66,7 @@ class NullPayBackendClient {
75
66
  async relayCreateInvoice(body) {
76
67
  return await this.request('/mcp/relay/create-invoice', {
77
68
  method: 'POST',
78
- headers: {
79
- 'Content-Type': 'application/json',
80
- ...(this.mcpSecret ? { 'x-nullpay-mcp-secret': this.mcpSecret } : {})
81
- },
69
+ headers: { 'Content-Type': 'application/json' },
82
70
  body: JSON.stringify(body),
83
71
  });
84
72
  }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const server_1 = require("./server");
5
+ const setup_1 = require("./setup");
6
+ function printHelp() {
7
+ console.log('NullPay MCP');
8
+ console.log('');
9
+ console.log('Usage:');
10
+ console.log(' nullpay-mcp Start the setup wizard');
11
+ console.log(' nullpay-mcp setup Start the setup wizard');
12
+ console.log(' nullpay-mcp server Run the stdio MCP server');
13
+ }
14
+ async function main() {
15
+ const mode = (process.argv[2] || 'setup').toLowerCase();
16
+ if (mode === 'server') {
17
+ (0, server_1.startServer)();
18
+ return;
19
+ }
20
+ if (mode === 'setup') {
21
+ await (0, setup_1.runSetupWizard)();
22
+ return;
23
+ }
24
+ if (mode === '--help' || mode === '-h' || mode === 'help') {
25
+ printHelp();
26
+ return;
27
+ }
28
+ console.error(`Unknown command: ${mode}`);
29
+ printHelp();
30
+ process.exitCode = 1;
31
+ }
32
+ void main().catch((error) => {
33
+ console.error(error instanceof Error ? error.message : String(error));
34
+ process.exit(1);
35
+ });
package/dist/env.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export declare const DEFAULT_BACKEND_URL = "http://localhost:3000/api";
2
+ export declare const DEFAULT_PUBLIC_BASE_URL = "https://nullpay.app";
3
+ export declare function parseDotEnv(content: string): Record<string, string>;
4
+ export declare function loadEnvFiles(): void;
5
+ export declare function getRuntimeConfig(): {
6
+ backendBaseUrl: string;
7
+ publicBaseUrl: string;
8
+ };
9
+ export declare function getProvableConfig(): {
10
+ apiKey: string;
11
+ consumerId: string;
12
+ };
package/dist/env.js ADDED
@@ -0,0 +1,75 @@
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.DEFAULT_PUBLIC_BASE_URL = exports.DEFAULT_BACKEND_URL = void 0;
7
+ exports.parseDotEnv = parseDotEnv;
8
+ exports.loadEnvFiles = loadEnvFiles;
9
+ exports.getRuntimeConfig = getRuntimeConfig;
10
+ exports.getProvableConfig = getProvableConfig;
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const path_1 = __importDefault(require("path"));
13
+ exports.DEFAULT_BACKEND_URL = 'http://localhost:3000/api';
14
+ exports.DEFAULT_PUBLIC_BASE_URL = 'https://nullpay.app';
15
+ const DEFAULT_PROVABLE_API_KEY = 'tWR9YWkM5SVmx1u3m7My8S4p4e2s84Oe';
16
+ const DEFAULT_PROVABLE_CONSUMER_ID = '73ba1b21-d8f7-4d7f-bfd9-0408a4e183f3';
17
+ function parseDotEnv(content) {
18
+ const parsed = {};
19
+ for (const rawLine of content.split(/\r?\n/)) {
20
+ const line = rawLine.trim();
21
+ if (!line || line.startsWith('#')) {
22
+ continue;
23
+ }
24
+ const normalized = line.startsWith('export ') ? line.slice(7).trim() : line;
25
+ const separatorIndex = normalized.indexOf('=');
26
+ if (separatorIndex <= 0) {
27
+ continue;
28
+ }
29
+ const key = normalized.slice(0, separatorIndex).trim();
30
+ let value = normalized.slice(separatorIndex + 1).trim();
31
+ if (!key) {
32
+ continue;
33
+ }
34
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
35
+ value = value.slice(1, -1);
36
+ }
37
+ parsed[key] = value;
38
+ }
39
+ return parsed;
40
+ }
41
+ function loadEnvFiles() {
42
+ const packageRoot = path_1.default.resolve(__dirname, '..');
43
+ const repoRoot = path_1.default.resolve(packageRoot, '..', '..');
44
+ const candidates = [
45
+ path_1.default.resolve(process.cwd(), '.env'),
46
+ path_1.default.resolve(packageRoot, '.env'),
47
+ path_1.default.resolve(repoRoot, '.env'),
48
+ path_1.default.resolve(repoRoot, 'backend', '.env'),
49
+ ];
50
+ for (const filePath of candidates) {
51
+ if (!fs_1.default.existsSync(filePath)) {
52
+ continue;
53
+ }
54
+ const values = parseDotEnv(fs_1.default.readFileSync(filePath, 'utf8'));
55
+ for (const [key, value] of Object.entries(values)) {
56
+ if (!process.env[key]) {
57
+ process.env[key] = value;
58
+ }
59
+ }
60
+ }
61
+ }
62
+ function getRuntimeConfig() {
63
+ loadEnvFiles();
64
+ return {
65
+ backendBaseUrl: process.env.NULLPAY_BACKEND_URL || exports.DEFAULT_BACKEND_URL,
66
+ publicBaseUrl: process.env.NULLPAY_PUBLIC_BASE_URL || exports.DEFAULT_PUBLIC_BASE_URL,
67
+ };
68
+ }
69
+ function getProvableConfig() {
70
+ loadEnvFiles();
71
+ return {
72
+ apiKey: process.env.PROVABLE_API_KEY || DEFAULT_PROVABLE_API_KEY,
73
+ consumerId: process.env.PROVABLE_CONSUMER_ID || process.env.PROVABLE_CONSUMER_KEY || DEFAULT_PROVABLE_CONSUMER_ID,
74
+ };
75
+ }
package/dist/server.d.ts CHANGED
@@ -1 +1 @@
1
- export {};
1
+ export declare function startServer(): void;
package/dist/server.js CHANGED
@@ -1,59 +1,11 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const fs_1 = __importDefault(require("fs"));
7
- const path_1 = __importDefault(require("path"));
3
+ exports.startServer = startServer;
8
4
  const backend_client_1 = require("./backend-client");
5
+ const env_1 = require("./env");
9
6
  const protocol_1 = require("./protocol");
10
7
  const session_store_1 = require("./session-store");
11
8
  const service_1 = require("./service");
12
- function parseDotEnv(content) {
13
- const parsed = {};
14
- for (const rawLine of content.split(/\r?\n/)) {
15
- const line = rawLine.trim();
16
- if (!line || line.startsWith('#')) {
17
- continue;
18
- }
19
- const normalized = line.startsWith('export ') ? line.slice(7).trim() : line;
20
- const separatorIndex = normalized.indexOf('=');
21
- if (separatorIndex <= 0) {
22
- continue;
23
- }
24
- const key = normalized.slice(0, separatorIndex).trim();
25
- let value = normalized.slice(separatorIndex + 1).trim();
26
- if (!key) {
27
- continue;
28
- }
29
- if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
30
- value = value.slice(1, -1);
31
- }
32
- parsed[key] = value;
33
- }
34
- return parsed;
35
- }
36
- function loadEnvFiles() {
37
- const packageRoot = path_1.default.resolve(__dirname, '..');
38
- const repoRoot = path_1.default.resolve(packageRoot, '..', '..');
39
- const candidates = [
40
- path_1.default.resolve(process.cwd(), '.env'),
41
- path_1.default.resolve(packageRoot, '.env'),
42
- path_1.default.resolve(repoRoot, '.env'),
43
- path_1.default.resolve(repoRoot, 'backend', '.env'),
44
- ];
45
- for (const filePath of candidates) {
46
- if (!fs_1.default.existsSync(filePath)) {
47
- continue;
48
- }
49
- const values = parseDotEnv(fs_1.default.readFileSync(filePath, 'utf8'));
50
- for (const [key, value] of Object.entries(values)) {
51
- if (!process.env[key]) {
52
- process.env[key] = value;
53
- }
54
- }
55
- }
56
- }
57
9
  function shieldStdoutForMcp() {
58
10
  const protocolWrite = process.stdout.write.bind(process.stdout);
59
11
  globalThis.__nullpayMcpStdoutWrite = (chunk) => protocolWrite(chunk);
@@ -73,39 +25,38 @@ function shieldStdoutForMcp() {
73
25
  return true;
74
26
  });
75
27
  }
76
- loadEnvFiles();
77
- shieldStdoutForMcp();
78
- const backendBaseUrl = process.env.NULLPAY_BACKEND_URL || 'http://localhost:3000/api';
79
- const publicBaseUrl = process.env.NULLPAY_PUBLIC_BASE_URL || 'https://nullpay.app';
80
- const mcpSecret = process.env.NULLPAY_MCP_SHARED_SECRET;
81
- const backend = new backend_client_1.NullPayBackendClient(backendBaseUrl, mcpSecret);
82
- const sessions = new session_store_1.SessionStore();
83
- const service = new service_1.NullPayMcpService(backend, sessions, publicBaseUrl);
84
- const server = new protocol_1.StdioJsonRpcServer(async (request) => {
85
- if (request.method === 'initialize') {
86
- return {
87
- protocolVersion: String(request.params?.protocolVersion || '2025-11-25'),
88
- capabilities: {
89
- tools: {}
90
- },
91
- serverInfo: {
92
- name: 'nullpay-mcp',
93
- version: '0.1.0'
94
- }
95
- };
96
- }
97
- if (request.method === 'notifications/initialized') {
28
+ function startServer() {
29
+ shieldStdoutForMcp();
30
+ const { backendBaseUrl, publicBaseUrl } = (0, env_1.getRuntimeConfig)();
31
+ const backend = new backend_client_1.NullPayBackendClient(backendBaseUrl);
32
+ const sessions = new session_store_1.SessionStore();
33
+ const service = new service_1.NullPayMcpService(backend, sessions, publicBaseUrl);
34
+ const server = new protocol_1.StdioJsonRpcServer(async (request) => {
35
+ if (request.method === 'initialize') {
36
+ return {
37
+ protocolVersion: String(request.params?.protocolVersion || '2025-11-25'),
38
+ capabilities: {
39
+ tools: {}
40
+ },
41
+ serverInfo: {
42
+ name: 'nullpay-mcp',
43
+ version: '0.2.0'
44
+ }
45
+ };
46
+ }
47
+ if (request.method === 'notifications/initialized') {
48
+ return {};
49
+ }
50
+ if (request.method === 'tools/list') {
51
+ return { tools: service.listTools() };
52
+ }
53
+ if (request.method === 'tools/call') {
54
+ const name = String(request.params?.name || '');
55
+ const args = (request.params?.arguments || {});
56
+ return await service.callTool(name, args);
57
+ }
98
58
  return {};
99
- }
100
- if (request.method === 'tools/list') {
101
- return { tools: service.listTools() };
102
- }
103
- if (request.method === 'tools/call') {
104
- const name = String(request.params?.name || '');
105
- const args = (request.params?.arguments || {});
106
- return await service.callTool(name, args);
107
- }
108
- return {};
109
- });
110
- console.error('nullpay mcp starting');
111
- server.start();
59
+ });
60
+ console.error(`nullpay mcp starting against ${backendBaseUrl}`);
61
+ server.start();
62
+ }
@@ -0,0 +1 @@
1
+ export declare function runSetupWizard(): Promise<void>;
package/dist/setup.js ADDED
@@ -0,0 +1,140 @@
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.runSetupWizard = runSetupWizard;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const os_1 = __importDefault(require("os"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const promises_1 = __importDefault(require("readline/promises"));
11
+ const process_1 = require("process");
12
+ function getClaudeCodeConfigPath() {
13
+ return path_1.default.join(os_1.default.homedir(), '.claude.json');
14
+ }
15
+ function getClaudeDesktopConfigPath() {
16
+ if (process.platform === 'win32') {
17
+ const localAppData = process.env.LOCALAPPDATA || path_1.default.join(os_1.default.homedir(), 'AppData', 'Local');
18
+ const packagedClaudePath = path_1.default.join(localAppData, 'Packages', 'Claude_pzs8sxrjxfjjc', 'LocalCache', 'Roaming', 'Claude', 'claude_desktop_config.json');
19
+ if (fs_1.default.existsSync(packagedClaudePath) || fs_1.default.existsSync(path_1.default.dirname(packagedClaudePath))) {
20
+ return packagedClaudePath;
21
+ }
22
+ }
23
+ if (process.platform === 'win32') {
24
+ const appData = process.env.APPDATA || path_1.default.join(os_1.default.homedir(), 'AppData', 'Roaming');
25
+ return path_1.default.join(appData, 'Claude', 'claude_desktop_config.json');
26
+ }
27
+ if (process.platform === 'darwin') {
28
+ return path_1.default.join(os_1.default.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
29
+ }
30
+ return path_1.default.join(os_1.default.homedir(), '.config', 'Claude', 'claude_desktop_config.json');
31
+ }
32
+ function buildServerEntry(answers) {
33
+ const env = {
34
+ NULLPAY_MAIN_ADDRESS: answers.address,
35
+ NULLPAY_MAIN_PRIVATE_KEY: answers.privateKey,
36
+ NULLPAY_MAIN_PASSWORD: answers.password,
37
+ };
38
+ if (process.platform === 'win32') {
39
+ return {
40
+ command: 'cmd',
41
+ args: ['/c', 'npx', '-y', '@nullpay/mcp', 'server'],
42
+ env,
43
+ };
44
+ }
45
+ return {
46
+ command: 'npx',
47
+ args: ['-y', '@nullpay/mcp', 'server'],
48
+ env,
49
+ };
50
+ }
51
+ function readJsonConfig(configPath) {
52
+ if (!fs_1.default.existsSync(configPath)) {
53
+ return {};
54
+ }
55
+ const raw = fs_1.default.readFileSync(configPath, 'utf8').trim();
56
+ if (!raw) {
57
+ return {};
58
+ }
59
+ const parsed = JSON.parse(raw);
60
+ if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {
61
+ throw new Error(`Config at ${configPath} is not a JSON object.`);
62
+ }
63
+ return parsed;
64
+ }
65
+ function writeMcpConfig(configPath, serverName, entry) {
66
+ const current = readJsonConfig(configPath);
67
+ const currentMcpServers = current.mcpServers && typeof current.mcpServers === 'object' && !Array.isArray(current.mcpServers)
68
+ ? current.mcpServers
69
+ : {};
70
+ const next = {
71
+ ...current,
72
+ mcpServers: {
73
+ ...currentMcpServers,
74
+ [serverName]: entry,
75
+ },
76
+ };
77
+ fs_1.default.mkdirSync(path_1.default.dirname(configPath), { recursive: true });
78
+ fs_1.default.writeFileSync(configPath, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
79
+ }
80
+ async function askChoice(rl) {
81
+ process_1.stdout.write('Where do you want to install NullPay MCP?\n');
82
+ process_1.stdout.write('1. Claude Code\n');
83
+ process_1.stdout.write('2. Claude Desktop\n');
84
+ process_1.stdout.write('3. Cancel\n');
85
+ while (true) {
86
+ const answer = (await rl.question('Choose 1, 2, or 3: ')).trim();
87
+ if (answer === '1')
88
+ return 'claude-code';
89
+ if (answer === '2')
90
+ return 'claude-desktop';
91
+ if (answer === '3')
92
+ return null;
93
+ process_1.stdout.write('Please enter 1, 2, or 3.\n');
94
+ }
95
+ }
96
+ async function askRequired(rl, label) {
97
+ while (true) {
98
+ const answer = (await rl.question(`${label}: `)).trim();
99
+ if (answer) {
100
+ return answer;
101
+ }
102
+ process_1.stdout.write(`${label} is required.\n`);
103
+ }
104
+ }
105
+ async function collectAnswers(rl) {
106
+ process_1.stdout.write('\nNullPay will configure Claude automatically. You only need to provide your wallet credentials here.\n\n');
107
+ const address = await askRequired(rl, 'Main wallet address');
108
+ const privateKey = await askRequired(rl, 'Main wallet private key');
109
+ const password = await askRequired(rl, 'NullPay password');
110
+ return {
111
+ address,
112
+ privateKey,
113
+ password,
114
+ };
115
+ }
116
+ async function runSetupWizard() {
117
+ const rl = promises_1.default.createInterface({ input: process_1.stdin, output: process_1.stdout });
118
+ try {
119
+ process_1.stdout.write('NullPay MCP setup\n\n');
120
+ const choice = await askChoice(rl);
121
+ if (!choice) {
122
+ process_1.stdout.write('Setup cancelled.\n');
123
+ return;
124
+ }
125
+ const answers = await collectAnswers(rl);
126
+ const entry = buildServerEntry(answers);
127
+ const configPath = choice === 'claude-code' ? getClaudeCodeConfigPath() : getClaudeDesktopConfigPath();
128
+ writeMcpConfig(configPath, 'nullpay', entry);
129
+ process_1.stdout.write(`\nNullPay MCP was added to ${configPath}\n`);
130
+ if (choice === 'claude-code') {
131
+ process_1.stdout.write('Next step: restart Claude Code or run `claude mcp list` to confirm the server is registered.\n');
132
+ }
133
+ else {
134
+ process_1.stdout.write('Next step: fully restart Claude Desktop so it reloads the new MCP config.\n');
135
+ }
136
+ }
137
+ finally {
138
+ rl.close();
139
+ }
140
+ }
@@ -1,3 +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>;
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>;
@@ -1,66 +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
- }
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
+ }
@@ -1,6 +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
- };
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
+ };
package/dist/utils/env.js CHANGED
@@ -1,15 +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
- }
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
+ }
@@ -1 +1 @@
1
- export declare function dynamicImport<T = any>(specifier: string): Promise<T>;
1
+ export declare function dynamicImport<T = any>(specifier: string): Promise<T>;
package/dist/utils/esm.js CHANGED
@@ -1,7 +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
- }
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
+ }
@@ -1,14 +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;
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;
@@ -1,132 +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
- }
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 CHANGED
@@ -1,39 +1,34 @@
1
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
- }
2
+ "name": "@nullpay/mcp",
3
+ "version": "1.0.1",
4
+ "description": "NullPay MCP server and Claude setup wizard for conversational payment flows",
5
+ "type": "commonjs",
6
+ "main": "dist/server.js",
7
+ "types": "dist/server.d.ts",
8
+ "bin": {
9
+ "nullpay-mcp": "./dist/cli.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.json",
17
+ "start": "node dist/cli.js server",
18
+ "dev": "ts-node src/cli.ts server",
19
+ "setup": "ts-node src/cli.ts setup",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "dependencies": {
26
+ "@provablehq/sdk": "^0.9.18",
27
+ "@provablehq/wasm": "^0.9.18"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^25.4.0",
31
+ "ts-node": "^10.9.2",
32
+ "typescript": "^5.9.3"
33
+ }
39
34
  }