x402-bazaar 1.1.0 → 1.2.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/bin/cli.js CHANGED
@@ -21,7 +21,7 @@ const program = new Command();
21
21
  program
22
22
  .name('x402-bazaar')
23
23
  .description(chalk.hex('#FF9900')('x402 Bazaar') + ' — Connect your AI agent to the marketplace in one command')
24
- .version('1.1.0');
24
+ .version('1.2.0');
25
25
 
26
26
  program
27
27
  .command('init')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-bazaar",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "CLI to set up x402 Bazaar MCP server for AI agents. One command to connect your agent to the marketplace.",
5
5
  "type": "module",
6
6
  "main": "bin/cli.js",
@@ -4,6 +4,7 @@ import chalk from 'chalk';
4
4
  import { existsSync, mkdirSync, writeFileSync, readFileSync, copyFileSync } from 'fs';
5
5
  import { join, dirname, resolve } from 'path';
6
6
  import { execSync } from 'child_process';
7
+ import { randomBytes } from 'crypto';
7
8
  import { fileURLToPath } from 'url';
8
9
  import { log } from '../utils/logger.js';
9
10
  import { isInteractive, promptOrDefault, printNonInteractiveHint } from '../utils/prompt.js';
@@ -126,8 +127,18 @@ export async function initCommand(options) {
126
127
  copyFileSync(mcpSource, mcpServerDest);
127
128
  spinner.text = 'Copied mcp-server.mjs from local project...';
128
129
  } else {
129
- spinner.text = 'Generating MCP server file...';
130
- writeFileSync(mcpServerDest, generateMcpServerFile());
130
+ spinner.text = 'Downloading MCP server from GitHub...';
131
+ try {
132
+ const dlRes = await fetch('https://raw.githubusercontent.com/Wintyx57/x402-backend/main/mcp-server.mjs');
133
+ if (!dlRes.ok) throw new Error(`HTTP ${dlRes.status}`);
134
+ writeFileSync(mcpServerDest, await dlRes.text());
135
+ } catch (dlErr) {
136
+ spinner.fail(`Could not download MCP server: ${dlErr.message}`);
137
+ log.error('Download the file manually from:');
138
+ log.dim(' https://github.com/Wintyx57/x402-backend/blob/main/mcp-server.mjs');
139
+ log.dim(` Save it to: ${mcpServerDest}`);
140
+ process.exit(1);
141
+ }
131
142
  }
132
143
 
133
144
  // Create package.json for the MCP server runtime
@@ -135,14 +146,16 @@ export async function initCommand(options) {
135
146
  if (!existsSync(pkgJsonPath)) {
136
147
  writeFileSync(pkgJsonPath, JSON.stringify({
137
148
  name: 'x402-bazaar-mcp',
138
- version: '1.0.0',
149
+ version: '2.0.0',
139
150
  type: 'module',
140
151
  private: true,
141
152
  dependencies: {
142
- '@coinbase/coinbase-sdk': '^0.25.0',
153
+ 'viem': '^2.0.0',
143
154
  '@modelcontextprotocol/sdk': '^1.26.0',
144
155
  'dotenv': '^17.2.4',
145
156
  'zod': '^4.3.6',
157
+ 'ed2curve': '^0.3.0',
158
+ '@scure/bip32': '^1.6.0',
146
159
  },
147
160
  }, null, 2));
148
161
  }
@@ -183,9 +196,9 @@ export async function initCommand(options) {
183
196
  console.log('');
184
197
 
185
198
  let walletMode = 'readonly';
199
+ let agentPrivateKey = '';
186
200
  let coinbaseApiKey = '';
187
201
  let coinbaseApiSecret = '';
188
- let seedPath = '';
189
202
  let maxBudget = '1.00';
190
203
  let network = 'mainnet';
191
204
  let serverUrl = options.serverUrl || 'https://x402-api.onrender.com';
@@ -200,31 +213,79 @@ export async function initCommand(options) {
200
213
  message: 'How do you want to configure payments?',
201
214
  choices: [
202
215
  {
203
- name: `${chalk.bold('I have Coinbase API keys')} — Full access (search, register, pay)`,
204
- value: 'existing',
216
+ name: `${chalk.bold('Generate a new wallet')} — Creates a fresh Ethereum wallet automatically (Recommended)`,
217
+ value: 'generate',
205
218
  },
206
219
  {
207
- name: `${chalk.bold('Create a new wallet')} — Guide me through setup`,
208
- value: 'new',
220
+ name: `${chalk.bold('Import private key')} — Use an existing Ethereum private key`,
221
+ value: 'import',
222
+ },
223
+ {
224
+ name: `${chalk.bold('Coinbase API keys')} — Legacy: use Coinbase CDP seed file`,
225
+ value: 'coinbase',
209
226
  },
210
227
  {
211
228
  name: `${chalk.bold('Read-only mode')} — Browse marketplace for free (no payments)`,
212
229
  value: 'readonly',
213
230
  },
214
231
  ],
215
- default: 'readonly',
232
+ default: 'generate',
216
233
  }]);
217
234
 
218
235
  walletMode = mode;
219
236
 
220
- if (mode === 'existing') {
237
+ if (mode === 'generate') {
238
+ agentPrivateKey = '0x' + randomBytes(32).toString('hex');
239
+ log.success('New wallet generated!');
240
+
241
+ // Derive address using viem (installed in step 2)
242
+ try {
243
+ const addr = execSync(
244
+ `node --input-type=module -e "import{privateKeyToAccount}from'viem/accounts';console.log(privateKeyToAccount('${agentPrivateKey}').address)"`,
245
+ { cwd: installDir, stdio: 'pipe', timeout: 15000 }
246
+ ).toString().trim();
247
+ log.info(`Wallet address: ${chalk.bold(addr)}`);
248
+ console.log('');
249
+ log.dim(' Fund this address with USDC on Base to start paying for APIs.');
250
+ log.dim(` View on BaseScan: https://basescan.org/address/${addr}`);
251
+ } catch {
252
+ log.info('Wallet address will be shown when you first use the MCP server.');
253
+ log.dim(' Use the get_wallet_balance tool to see your address.');
254
+ }
255
+ }
256
+
257
+ if (mode === 'import') {
258
+ if (!isInteractive()) {
259
+ log.warn('Cannot enter private key in a non-interactive terminal.');
260
+ log.info('Set AGENT_PRIVATE_KEY in your .env file manually after setup.');
261
+ walletMode = 'readonly';
262
+ } else {
263
+ const { key } = await promptOrDefault([{
264
+ type: 'password',
265
+ name: 'key',
266
+ message: 'Ethereum private key (0x...):',
267
+ mask: '*',
268
+ validate: (v) => {
269
+ const trimmed = v.trim();
270
+ if (trimmed.length === 0) return 'Private key is required';
271
+ const hex = trimmed.startsWith('0x') ? trimmed.slice(2) : trimmed;
272
+ if (!/^[0-9a-fA-F]{64}$/.test(hex)) return 'Invalid private key (expected 64 hex characters)';
273
+ return true;
274
+ },
275
+ }]);
276
+ agentPrivateKey = key.trim().startsWith('0x') ? key.trim() : `0x${key.trim()}`;
277
+ log.success('Private key imported.');
278
+ }
279
+ }
280
+
281
+ if (mode === 'coinbase') {
221
282
  if (!isInteractive()) {
222
283
  log.warn('Cannot enter API credentials in a non-interactive terminal.');
223
284
  log.info('Falling back to read-only mode.');
224
- log.dim(' To configure wallet, run in a standalone terminal:');
225
- log.dim(' npx x402-bazaar init');
226
285
  walletMode = 'readonly';
227
286
  } else {
287
+ log.dim(' Legacy mode: requires Coinbase CDP API keys + agent-seed.json');
288
+ console.log('');
228
289
  const walletAnswers = await promptOrDefault([
229
290
  {
230
291
  type: 'input',
@@ -243,43 +304,12 @@ export async function initCommand(options) {
243
304
  coinbaseApiKey = walletAnswers.coinbaseApiKey.trim();
244
305
  coinbaseApiSecret = walletAnswers.coinbaseApiSecret.trim();
245
306
 
246
- // Check if agent-seed.json exists
247
307
  const existingSeed = join(installDir, 'agent-seed.json');
248
308
  if (!existsSync(existingSeed)) {
249
- log.warn('No agent-seed.json found. You will need to create a wallet.');
250
- log.dim(' Run: cd "' + installDir + '" && node -e "const{Coinbase,Wallet}=require(\'@coinbase/coinbase-sdk\');...');
251
- log.dim(' Or copy your existing agent-seed.json to: ' + installDir);
252
- }
253
- }
254
- }
255
-
256
- if (mode === 'new') {
257
- console.log('');
258
- log.info('To get Coinbase API keys:');
259
- console.log('');
260
- log.dim(' 1. Go to https://portal.cdp.coinbase.com/');
261
- log.dim(' 2. Create a project (free)');
262
- log.dim(' 3. Go to "API Keys" and generate a key pair');
263
- log.dim(' 4. Save both the API Key Name and the Private Key');
264
- log.dim(' 5. Run npx x402-bazaar init again with your keys');
265
- console.log('');
266
-
267
- if (!isInteractive()) {
268
- log.info('Continuing in read-only mode (non-interactive terminal).');
269
- walletMode = 'readonly';
270
- } else {
271
- const { proceed } = await promptOrDefault([{
272
- type: 'confirm',
273
- name: 'proceed',
274
- message: 'Continue in read-only mode for now?',
275
- default: true,
276
- }]);
277
-
278
- if (!proceed) {
279
- log.info('Run npx x402-bazaar init when you have your API keys.');
280
- process.exit(0);
309
+ log.warn('No agent-seed.json found.');
310
+ log.dim(' Copy your existing agent-seed.json to: ' + installDir);
311
+ log.dim(' Or re-run init and choose "Generate a new wallet" instead.');
281
312
  }
282
- walletMode = 'readonly';
283
313
  }
284
314
  }
285
315
 
@@ -315,7 +345,6 @@ export async function initCommand(options) {
315
345
 
316
346
  network = configAnswers.network;
317
347
  maxBudget = configAnswers.maxBudget;
318
- seedPath = join(installDir, 'agent-seed.json');
319
348
  }
320
349
 
321
350
  console.log('');
@@ -330,9 +359,9 @@ export async function initCommand(options) {
330
359
  serverUrl,
331
360
  maxBudget,
332
361
  network,
362
+ agentPrivateKey,
333
363
  coinbaseApiKey,
334
364
  coinbaseApiSecret,
335
- seedPath,
336
365
  readOnly: walletMode === 'readonly',
337
366
  });
338
367
 
@@ -342,9 +371,9 @@ export async function initCommand(options) {
342
371
  serverUrl,
343
372
  maxBudget,
344
373
  network,
374
+ agentPrivateKey,
345
375
  coinbaseApiKey,
346
376
  coinbaseApiSecret,
347
- seedPath,
348
377
  });
349
378
  const envPath = join(installDir, '.env');
350
379
  writeFileSync(envPath, envContent);
@@ -487,319 +516,3 @@ function writeConfig(envInfo, newConfig) {
487
516
  }
488
517
  }
489
518
 
490
- /**
491
- * Generate a standalone MCP server file.
492
- * Used as fallback when the local x402-bazaar project is not found.
493
- */
494
- function generateMcpServerFile() {
495
- return `import 'dotenv/config';
496
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
497
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
498
- import { z } from 'zod';
499
- import { createRequire } from 'module';
500
-
501
- const require = createRequire(import.meta.url);
502
- const { Coinbase, Wallet } = require('@coinbase/coinbase-sdk');
503
-
504
- // ─── Config ──────────────────────────────────────────────────────────
505
- const SERVER_URL = process.env.X402_SERVER_URL || 'https://x402-api.onrender.com';
506
- const MAX_BUDGET = parseFloat(process.env.MAX_BUDGET_USDC || '1.00');
507
- const NETWORK = process.env.NETWORK || 'mainnet';
508
- const explorerBase = NETWORK === 'testnet'
509
- ? 'https://sepolia.basescan.org'
510
- : 'https://basescan.org';
511
- const networkLabel = NETWORK === 'testnet' ? 'Base Sepolia' : 'Base Mainnet';
512
-
513
- // ─── Budget Tracking ─────────────────────────────────────────────────
514
- let sessionSpending = 0;
515
- const sessionPayments = [];
516
-
517
- // ─── Wallet ──────────────────────────────────────────────────────────
518
- let wallet = null;
519
- let walletReady = false;
520
-
521
- async function initWallet() {
522
- if (walletReady) return;
523
-
524
- Coinbase.configure({
525
- apiKeyName: process.env.COINBASE_API_KEY,
526
- privateKey: process.env.COINBASE_API_SECRET,
527
- });
528
-
529
- const seedPath = process.env.AGENT_SEED_PATH || 'agent-seed.json';
530
- const fs = await import('fs');
531
- const seedData = JSON.parse(fs.readFileSync(seedPath, 'utf-8'));
532
- const seedWalletId = Object.keys(seedData)[0];
533
-
534
- wallet = await Wallet.fetch(seedWalletId);
535
- await wallet.loadSeed(seedPath);
536
- walletReady = true;
537
- }
538
-
539
- // ─── x402 Payment Flow ──────────────────────────────────────────────
540
- async function payAndRequest(url, options = {}) {
541
- const res = await fetch(url, options);
542
- const body = await res.json();
543
-
544
- if (res.status !== 402) {
545
- return body;
546
- }
547
-
548
- // HTTP 402 — Payment Required
549
- const details = body.payment_details;
550
- const cost = parseFloat(details.amount);
551
-
552
- // Budget check
553
- if (sessionSpending + cost > MAX_BUDGET) {
554
- throw new Error(
555
- \`Budget limit reached. Spent: \${sessionSpending.toFixed(2)} USDC / \${MAX_BUDGET.toFixed(2)} USDC limit. \` +
556
- \`This call costs \${cost} USDC. Increase MAX_BUDGET_USDC env var to allow more spending.\`
557
- );
558
- }
559
-
560
- await initWallet();
561
-
562
- const transfer = await wallet.createTransfer({
563
- amount: details.amount,
564
- assetId: Coinbase.assets.Usdc,
565
- destination: details.recipient,
566
- });
567
- const confirmed = await transfer.wait({ timeoutSeconds: 120 });
568
- const txHash = confirmed.getTransactionHash();
569
-
570
- // Track spending
571
- sessionSpending += cost;
572
- sessionPayments.push({
573
- amount: cost,
574
- txHash,
575
- timestamp: new Date().toISOString(),
576
- endpoint: url.replace(SERVER_URL, ''),
577
- });
578
-
579
- // Retry with payment proof
580
- const retryHeaders = { ...options.headers, 'X-Payment-TxHash': txHash };
581
- const retryRes = await fetch(url, { ...options, headers: retryHeaders });
582
- const result = await retryRes.json();
583
-
584
- // Enrich result with payment info
585
- result._payment = {
586
- amount: details.amount,
587
- currency: 'USDC',
588
- txHash,
589
- explorer: \`\${explorerBase}/tx/\${txHash}\`,
590
- session_spent: sessionSpending.toFixed(2),
591
- session_remaining: (MAX_BUDGET - sessionSpending).toFixed(2),
592
- };
593
-
594
- return result;
595
- }
596
-
597
- // ─── MCP Server ─────────────────────────────────────────────────────
598
- const server = new McpServer({
599
- name: 'x402-bazaar',
600
- version: '1.1.0',
601
- });
602
-
603
- // --- Tool: discover_marketplace (FREE) ---
604
- server.tool(
605
- 'discover_marketplace',
606
- 'Discover the x402 Bazaar marketplace. Returns available endpoints, total services, and protocol info. Free — no payment needed.',
607
- {},
608
- async () => {
609
- try {
610
- const res = await fetch(SERVER_URL);
611
- const data = await res.json();
612
- return {
613
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
614
- };
615
- } catch (err) {
616
- return {
617
- content: [{ type: 'text', text: \`Error: \${err.message}\` }],
618
- isError: true,
619
- };
620
- }
621
- }
622
- );
623
-
624
- // --- Tool: search_services (0.05 USDC) ---
625
- server.tool(
626
- 'search_services',
627
- \`Search for API services on x402 Bazaar by keyword. Costs 0.05 USDC (paid automatically). Budget: \${MAX_BUDGET.toFixed(2)} USDC per session. Check get_budget_status before calling if unsure about remaining budget.\`,
628
- { query: z.string().describe('Search keyword (e.g. "weather", "crypto", "ai")') },
629
- async ({ query }) => {
630
- try {
631
- const result = await payAndRequest(
632
- \`\${SERVER_URL}/search?q=\${encodeURIComponent(query)}\`
633
- );
634
- return {
635
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
636
- };
637
- } catch (err) {
638
- return {
639
- content: [{ type: 'text', text: \`Error: \${err.message}\` }],
640
- isError: true,
641
- };
642
- }
643
- }
644
- );
645
-
646
- // --- Tool: list_services (0.05 USDC) ---
647
- server.tool(
648
- 'list_services',
649
- \`List all API services available on x402 Bazaar. Costs 0.05 USDC (paid automatically). Budget: \${MAX_BUDGET.toFixed(2)} USDC per session.\`,
650
- {},
651
- async () => {
652
- try {
653
- const result = await payAndRequest(\`\${SERVER_URL}/services\`);
654
- return {
655
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
656
- };
657
- } catch (err) {
658
- return {
659
- content: [{ type: 'text', text: \`Error: \${err.message}\` }],
660
- isError: true,
661
- };
662
- }
663
- }
664
- );
665
-
666
- // --- Tool: find_tool_for_task (0.05 USDC — smart service lookup) ---
667
- server.tool(
668
- 'find_tool_for_task',
669
- \`Describe what you need in plain English and get the best matching API service ready to call. Returns the single best match with name, URL, price, and usage instructions. Costs 0.05 USDC. Budget: \${MAX_BUDGET.toFixed(2)} USDC per session.\`,
670
- { task: z.string().describe('What you need, in natural language (e.g. "get current weather for a city", "translate text to French")') },
671
- async ({ task }) => {
672
- try {
673
- const stopWords = new Set(['i', 'need', 'want', 'to', 'a', 'an', 'the', 'for', 'of', 'and', 'or', 'in', 'on', 'with', 'that', 'this', 'get', 'find', 'me', 'my', 'some', 'can', 'you', 'do', 'is', 'it', 'be', 'have', 'use', 'please', 'should', 'would', 'could']);
674
- const keywords = task.toLowerCase()
675
- .replace(/[^a-z0-9\\s]/g, '')
676
- .split(/\\s+/)
677
- .filter(w => w.length > 2 && !stopWords.has(w));
678
- const query = keywords.slice(0, 3).join(' ') || task.slice(0, 30);
679
-
680
- const result = await payAndRequest(
681
- \`\${SERVER_URL}/search?q=\${encodeURIComponent(query)}\`
682
- );
683
-
684
- const services = result.data || result.services || [];
685
- if (services.length === 0) {
686
- return {
687
- content: [{ type: 'text', text: JSON.stringify({
688
- found: false,
689
- query_used: query,
690
- message: \`No services found matching "\${task}". Try rephrasing or use search_services with different keywords.\`,
691
- _payment: result._payment,
692
- }, null, 2) }],
693
- };
694
- }
695
-
696
- const best = services[0];
697
- return {
698
- content: [{ type: 'text', text: JSON.stringify({
699
- found: true,
700
- query_used: query,
701
- service: {
702
- name: best.name,
703
- description: best.description,
704
- url: best.url,
705
- price_usdc: best.price_usdc,
706
- tags: best.tags,
707
- },
708
- action: \`Call this API using call_api("\${best.url}"). \${Number(best.price_usdc) === 0 ? 'This API is free.' : \`This API costs \${best.price_usdc} USDC per call.\`}\`,
709
- alternatives_count: services.length - 1,
710
- _payment: result._payment,
711
- }, null, 2) }],
712
- };
713
- } catch (err) {
714
- return {
715
- content: [{ type: 'text', text: \`Error: \${err.message}\` }],
716
- isError: true,
717
- };
718
- }
719
- }
720
- );
721
-
722
- // --- Tool: call_api (FREE — calls external APIs) ---
723
- server.tool(
724
- 'call_api',
725
- 'Call an external API URL and return the response. Use this to fetch real data from service URLs discovered on the marketplace. Free — no marketplace payment needed.',
726
- { url: z.string().url().describe('The full API URL to call') },
727
- async ({ url }) => {
728
- try {
729
- const res = await fetch(url);
730
- const text = await res.text();
731
- let parsed;
732
- try {
733
- parsed = JSON.parse(text);
734
- } catch {
735
- parsed = { response: text.slice(0, 5000) };
736
- }
737
- return {
738
- content: [{ type: 'text', text: JSON.stringify(parsed, null, 2) }],
739
- };
740
- } catch (err) {
741
- return {
742
- content: [{ type: 'text', text: \`Error: \${err.message}\` }],
743
- isError: true,
744
- };
745
- }
746
- }
747
- );
748
-
749
- // --- Tool: get_wallet_balance (FREE) ---
750
- server.tool(
751
- 'get_wallet_balance',
752
- 'Check the USDC balance of the agent wallet on-chain. Free.',
753
- {},
754
- async () => {
755
- try {
756
- await initWallet();
757
- const balance = await wallet.getBalance(Coinbase.assets.Usdc);
758
- const address = (await wallet.getDefaultAddress()).getId();
759
- return {
760
- content: [{
761
- type: 'text',
762
- text: JSON.stringify({
763
- address,
764
- balance_usdc: balance.toString(),
765
- network: networkLabel,
766
- explorer: \`\${explorerBase}/address/\${address}\`,
767
- }, null, 2),
768
- }],
769
- };
770
- } catch (err) {
771
- return {
772
- content: [{ type: 'text', text: \`Error: \${err.message}\` }],
773
- isError: true,
774
- };
775
- }
776
- }
777
- );
778
-
779
- // --- Tool: get_budget_status (FREE) ---
780
- server.tool(
781
- 'get_budget_status',
782
- 'Check the session spending budget. Shows how much USDC has been spent, remaining budget, and a list of all payments made this session. Free — call this before paid requests to verify budget.',
783
- {},
784
- async () => {
785
- return {
786
- content: [{
787
- type: 'text',
788
- text: JSON.stringify({
789
- budget_limit: MAX_BUDGET.toFixed(2) + ' USDC',
790
- spent: sessionSpending.toFixed(2) + ' USDC',
791
- remaining: (MAX_BUDGET - sessionSpending).toFixed(2) + ' USDC',
792
- payments_count: sessionPayments.length,
793
- payments: sessionPayments,
794
- network: networkLabel,
795
- }, null, 2),
796
- }],
797
- };
798
- }
799
- );
800
-
801
- // ─── Start ──────────────────────────────────────────────────────────
802
- const transport = new StdioServerTransport();
803
- await server.connect(transport);
804
- `;
805
- }
@@ -5,11 +5,11 @@ export function generateEnvContent({
5
5
  serverUrl = 'https://x402-api.onrender.com',
6
6
  maxBudget = '1.00',
7
7
  network = 'mainnet',
8
+ agentPrivateKey = '',
8
9
  coinbaseApiKey = '',
9
10
  coinbaseApiSecret = '',
10
- seedPath = 'agent-seed.json',
11
11
  }) {
12
- return `# x402 Bazaar MCP Server Configuration
12
+ let content = `# x402 Bazaar MCP Server Configuration
13
13
  # Generated by: npx x402-bazaar init
14
14
 
15
15
  # Marketplace server URL
@@ -20,13 +20,22 @@ MAX_BUDGET_USDC=${maxBudget}
20
20
 
21
21
  # Network: mainnet or testnet
22
22
  NETWORK=${network}
23
+ `;
23
24
 
24
- # Coinbase Developer Platform API credentials
25
+ if (agentPrivateKey) {
26
+ content += `
27
+ # Agent wallet private key (Ethereum)
28
+ # WARNING: Keep this secret! Never commit to git.
29
+ AGENT_PRIVATE_KEY=${agentPrivateKey}
30
+ `;
31
+ } else if (coinbaseApiKey) {
32
+ content += `
33
+ # Coinbase Developer Platform API credentials (legacy mode)
25
34
  # Get yours at: https://portal.cdp.coinbase.com/
26
35
  COINBASE_API_KEY=${coinbaseApiKey}
27
36
  COINBASE_API_SECRET=${coinbaseApiSecret}
28
-
29
- # Path to the agent wallet seed file
30
- AGENT_SEED_PATH=${seedPath}
31
37
  `;
38
+ }
39
+
40
+ return content;
32
41
  }
@@ -10,16 +10,12 @@ export function generateMcpConfig({
10
10
  serverUrl = 'https://x402-api.onrender.com',
11
11
  maxBudget = '1.00',
12
12
  network = 'mainnet',
13
+ agentPrivateKey = '',
13
14
  coinbaseApiKey = '',
14
15
  coinbaseApiSecret = '',
15
- seedPath = '',
16
16
  readOnly = false,
17
17
  }) {
18
- const os = platform();
19
- const sep = os === 'win32' ? '\\' : '/';
20
-
21
18
  const mcpServerPath = join(installDir, 'mcp-server.mjs');
22
- const defaultSeedPath = seedPath || join(installDir, 'agent-seed.json');
23
19
 
24
20
  const env = {
25
21
  X402_SERVER_URL: serverUrl,
@@ -28,9 +24,12 @@ export function generateMcpConfig({
28
24
  };
29
25
 
30
26
  if (!readOnly) {
31
- env.COINBASE_API_KEY = coinbaseApiKey || 'YOUR_COINBASE_API_KEY';
32
- env.COINBASE_API_SECRET = coinbaseApiSecret || 'YOUR_COINBASE_API_SECRET';
33
- env.AGENT_SEED_PATH = defaultSeedPath;
27
+ if (agentPrivateKey) {
28
+ env.AGENT_PRIVATE_KEY = agentPrivateKey;
29
+ } else if (coinbaseApiKey) {
30
+ env.COINBASE_API_KEY = coinbaseApiKey;
31
+ env.COINBASE_API_SECRET = coinbaseApiSecret;
32
+ }
34
33
  }
35
34
 
36
35
  const serverEntry = {
@@ -41,27 +40,6 @@ export function generateMcpConfig({
41
40
 
42
41
  // Format for the target environment
43
42
  switch (environment) {
44
- case 'claude-desktop':
45
- return {
46
- mcpServers: {
47
- 'x402-bazaar': serverEntry,
48
- },
49
- };
50
-
51
- case 'cursor':
52
- return {
53
- mcpServers: {
54
- 'x402-bazaar': serverEntry,
55
- },
56
- };
57
-
58
- case 'claude-code':
59
- return {
60
- mcpServers: {
61
- 'x402-bazaar': serverEntry,
62
- },
63
- };
64
-
65
43
  case 'vscode-continue':
66
44
  return {
67
45
  models: [],