x402-toolpick / tree / test/app.test.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
import test from 'node:test';
import assert from 'node:assert/strict';
import { wrapFetchWithPaymentFromConfig } from '@x402/fetch';
import { ExactEvmScheme } from '@x402/evm';
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
import { validateDiscoveryExtension } from '@x402/extensions/bazaar';
import { makeApp, seededStore, BASE, PAY_TO, mockNet } from './helpers.js';
import { headAsGet } from '../src/head.js';
import { handle as stdioHandle, TOOLS as STDIO_TOOLS } from '../src/mcp-stdio.js';
import { toQuery } from '../src/lite.js';

const decode = (h) => JSON.parse(Buffer.from(h, 'base64').toString('utf8'));
const v2pay = (fetchApp) => wrapFetchWithPaymentFromConfig(fetchApp, { schemes: [{ network: 'eip155:8453', client: new ExactEvmScheme(privateKeyToAccount(generatePrivateKey())) }] });
const json = (body) => ({ method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
const ROUTES = [['lite', '3000', 'need=web+search'], ['pick', '10000', 'need=web+search'], ['market', '20000', 'need=token+safety']];
const mcp = (fetchApp, body) => fetchApp(`${BASE}/mcp`, { method: 'POST', headers: { 'content-type': 'application/json', accept: 'application/json, text/event-stream' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, ...body }) });

test('unpaid: every paid route answers 402 on GET, POST, empty POST and bare probes (v2 header <= 8192 B + valid Bazaar, v1 body); no upstream call', async () => {
  const net = mockNet(); const { fetchApp } = await makeApp({ net }); const before = net.calls.length;
  for (const [tier, amount, qs] of ROUTES) {
    for (const [u, init] of [[`${BASE}/v1/${tier}?${qs}`], [`${BASE}/v1/${tier}`], [`${BASE}/v1/${tier}`, json(Object.fromEntries(new URLSearchParams(qs)))], [`${BASE}/v1/${tier}`, { method: 'POST' }], [`${BASE}/v1/${tier}`, json({})]]) {
      const r = await fetchApp(u, init);
      assert.equal(r.status, 402, `${init?.method || 'GET'} ${u}`);
      const req = decode(r.headers.get('PAYMENT-REQUIRED')); const a = req.accepts[0];
      assert.deepEqual([req.x402Version, a.scheme, a.network, a.amount, a.payTo, a.asset], [2, 'exact', 'eip155:8453', amount, PAY_TO, '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913']);
      assert.equal(req.resource.url, `${BASE}/v1/${tier}`);
      assert.ok(validateDiscoveryExtension(req.extensions.bazaar).valid, 'bazaar declaration valid');
      assert.ok(r.headers.get('PAYMENT-REQUIRED').length <= 8192, 'header size');
      const b = await r.json(); assert.equal(b.x402Version, 1); assert.equal(b.accepts[0].maxAmountRequired, amount); assert.equal(b.accepts[0].network, 'base');
    }
  }
  assert.equal(net.calls.length, before);
});

test('HEAD = 402 + PAYMENT-REQUIRED with no body and never settles', async () => {
  const { app, facilitator } = await makeApp();
  const h = headAsGet((req) => app.fetch(req));
  for (const [tier, amount, qs] of ROUTES) {
    const r = await h(new Request(`${BASE}/v1/${tier}?${qs}`, { method: 'HEAD', headers: { 'payment-signature': 'junk', 'x-payment': 'junk' } }));
    assert.equal(r.status, 402); assert.equal(decode(r.headers.get('payment-required')).accepts[0].amount, amount); assert.equal(await r.text(), '');
  }
  assert.equal(facilitator.verified.length, 0);
});

test('bad input: 400 before payment (never a 402, never charged)', async () => {
  const { fetchApp, facilitator } = await makeApp();
  for (const tier of ['lite', 'pick', 'preview']) for (const q of ['need=x', `need=${'a'.repeat(201)}`, 'need=the+and+of', 'need=web&max_price=-1', 'need=web&max_price=abc', 'need=web&network=tron']) {
    assert.equal((await fetchApp(`${BASE}/v1/${tier}?${q}`)).status, 400, `${tier} ${q}`);
  }
  for (const q of ['need=web&min_payers=-2', 'need=web&min_payers=1.5']) assert.equal((await fetchApp(`${BASE}/v1/pick?${q}`)).status, 400, q);
  for (const q of ['limit=0', 'limit=99', 'network=doge']) assert.equal((await fetchApp(`${BASE}/v1/market?${q}`)).status, 400, q);
  assert.equal((await fetchApp(`${BASE}/v1/pick`, json({ need: 5 }))).status, 400);
  assert.equal((await fetchApp(`${BASE}/v1/lite`, json({ foo: 1 }))).status, 400);
  assert.equal(facilitator.verified.length, 0);
});

test('paid v2 lite + pick + market: ranked results, live checks, best verified pick, settled once each at the right price', async () => {
  const { fetchApp, facilitator } = await makeApp();
  const pay = v2pay(fetchApp);
  const l = await pay(`${BASE}/v1/lite?need=web+search`); assert.equal(l.status, 200); const lj = await l.json();
  assert.equal(lj.tier, 'lite'); assert.equal(lj.results[0].service, 'SearchCo'); assert.ok(lj.results.length <= 5); assert.equal(lj.confidence, 'high');
  assert.ok(lj.results.every((x) => !x.resource.includes('testnet')), 'testnet-only resources excluded');
  assert.equal(lj.results[0].live_check, undefined, 'no live checks on lite'); assert.ok(l.headers.get('payment-response'));
  assert.deepEqual(lj.results[0].indexed_on, ['cdp', 'payai']); assert.ok(lj.results[0].networks.includes('solana'));
  const p = await pay(`${BASE}/v1/pick`, json({ need: 'web search', max_price: 0.02 })); assert.equal(p.status, 200); const pj = await p.json();
  assert.equal(pj.best_pick.service, 'SearchCo'); assert.equal(pj.best_pick.price_usd, 0.01);
  const dead = pj.results.find((x) => x.service === 'DeadSearch'); assert.equal(dead.verified_live, false); assert.ok(pj.sources_failed.includes('live_check:deadsearch.example.com'));
  const ours = pj.results.find((x) => x.ours); if (ours) assert.equal(ours.verified_live ?? null, null);
  assert.equal(pj.cheapest_verified?.service, 'newsearch.example.com'); assert.equal(pj.cheapest_verified.price_usd, 0.001); assert.ok(pj.stats.resources >= 3);
  assert.ok(!/0x(11){20}/.test(JSON.stringify(pj)), 'seller payTo never returned');
  const m = await pay(`${BASE}/v1/market?need=web+search`); assert.equal(m.status, 200); const mj = await m.json();
  assert.equal(mj.top_sellers[0].host, 'search.example.com'); assert.ok(mj.stats.price_usd.median > 0); assert.ok(mj.stats.price_with_buyers_usd.payer_weighted_median > 0);
  const all = await pay(`${BASE}/v1/market`); assert.equal(all.status, 200); assert.ok((await all.json()).stats.resources >= 7);
  assert.deepEqual(facilitator.settled.map((x) => x.amount), ['3000', '10000', '20000', '20000']);
});

test('NO FAIL-OPEN: a candidate whose live check fails or hangs is never verified; none verified = best_pick null + low confidence', async () => {
  const net = mockNet({ live: { 'https://search.example.com/v1/search': 'hang', 'https://cheapsearch.example.com/search': '200', 'https://newsearch.example.com/q': 'down' } });
  const { fetchApp, facilitator } = await makeApp({ net });
  const r = await v2pay(fetchApp)(`${BASE}/v1/pick?need=web+search`); assert.equal(r.status, 200); const j = await r.json();
  assert.equal(j.best_pick, null); assert.equal(j.confidence, 'low'); assert.match(j.pick_note, /Not verified/);
  for (const x of j.results.slice(0, 5)) assert.notEqual(x.verified_live, true, x.service);
  assert.ok(j.sources_failed.includes('live_check:search.example.com')); assert.ok(j.sources_failed.includes('live_check:deadsearch.example.com'));
  assert.equal(j.results.find((x) => x.service === 'CheapSearch').live_check.status, 'no_402');
  // price changed vs the listing: not picked
  const net2 = mockNet({ live: { 'https://search.example.com/v1/search': 'price' } });
  const j2 = await (await v2pay((await makeApp({ net: net2 })).fetchApp)(`${BASE}/v1/pick?need=web+search`)).json();
  assert.notEqual(j2.best_pick?.service, 'SearchCo'); assert.equal(j2.results[0].live_check.price_matches_index, false);
  assert.equal(facilitator.settled.length, 1);
});

test('FAIL-CLOSED: no index / index > 72 h / store down = 503 never settled; 12-72 h = stale flag + lower confidence; no matches = 404 never settled', async () => {
  const empty = await makeApp({ seed: false });
  for (const [tier, , qs] of ROUTES) {
    const r = await v2pay(empty.fetchApp)(`${BASE}/v1/${tier}?${qs}`);
    assert.equal(r.status, 503, tier); const j = await r.json(); assert.equal(j.charged, false); assert.ok(j.sources_failed.includes('index_not_ready'));
  }
  assert.equal(empty.facilitator.settled.length, 0);
  const old = await makeApp({ store: (await seededStore({ ageMs: 80 * 3600_000 })).store });
  const o = await v2pay(old.fetchApp)(`${BASE}/v1/lite?need=web+search`); assert.equal(o.status, 503); assert.ok((await o.json()).sources_failed.includes('index_stale'));
  const stale = await makeApp({ store: (await seededStore({ ageMs: 30 * 3600_000 })).store });
  const s = await (await v2pay(stale.fetchApp)(`${BASE}/v1/lite?need=web+search`)).json(); assert.equal(s.confidence, 'low'); assert.equal(s.index.stale, true); assert.ok(s.sources_failed.includes('index_stale'));
  const down = await makeApp({ store: { query: async () => { throw new Error('boom'); } } });
  const d = await v2pay(down.fetchApp)(`${BASE}/v1/pick?need=web+search`); assert.equal(d.status, 503); assert.ok((await d.json()).sources_failed.includes('index_store'));
  const n = await v2pay(stale.fetchApp)(`${BASE}/v1/lite?need=zebra+quantum+knitting`); assert.equal(n.status, 404); assert.equal((await n.json()).error, 'no_matches');
  assert.equal(old.facilitator.settled.length + down.facilitator.settled.length + stale.facilitator.settled.length, 1);
});

test('free preview: counts + top 3 names only (no URLs), rate limit', async () => {
  let n = 0; const limiter = { limit: async () => ({ success: ++n <= 2 }) };
  const { fetchApp } = await makeApp({ limiter });
  const r = await fetchApp(`${BASE}/v1/preview?need=web+search`);
  assert.equal(r.status, 200); const j = await r.json();
  assert.ok(j.matches >= 3); assert.equal(j.top[0].service, 'SearchCo'); assert.ok(!/https:\/\/[a-z]+\.example\.com/.test(JSON.stringify(j.top)), 'no URLs in preview');
  assert.equal(j.full.prices.pick, '$0.01');
  assert.equal((await fetchApp(`${BASE}/v1/preview?need=pdf`)).status, 200);
  assert.equal((await fetchApp(`${BASE}/v1/preview?need=pdf`)).status, 429);
});

test('remote MCP: initialize, tools/list, tools/call (preview tier)', async () => {
  const { fetchApp } = await makeApp();
  const init = await (await mcp(fetchApp, { method: 'initialize', params: { protocolVersion: '2025-06-18' } })).json();
  assert.equal(init.result.serverInfo.name, 'toolpick');
  const list = await (await mcp(fetchApp, { method: 'tools/list' })).json();
  assert.deepEqual(list.result.tools.map((t) => t.name), ['find_paid_api']);
  const call = await (await mcp(fetchApp, { method: 'tools/call', params: { name: 'find_paid_api', arguments: { need: 'solana token safety' } } })).json();
  assert.equal(call.result.isError, false); assert.match(call.result.content[0].text, /SolSafe/);
  const bad = await (await mcp(fetchApp, { method: 'tools/call', params: { name: 'find_paid_api', arguments: { need: '!' } } })).json();
  assert.equal(bad.result.isError, true);
});

test('discovery: info JSON, landing HTML, openapi (paid + preview only), /.well-known/x402, favicon PNG, health', async () => {
  const { fetchApp } = await makeApp();
  const info = await (await fetchApp(`${BASE}/`, { headers: { accept: 'application/json' } })).json();
  assert.equal(info.name, 'ToolPick'); assert.deepEqual(info.paid.map((p) => [p.path, p.price]), [['/v1/lite', '$0.003'], ['/v1/pick', '$0.01'], ['/v1/market', '$0.02']]);
  assert.match(info.policy.custody, /never pays/);
  const html = await (await fetchApp(`${BASE}/`, { headers: { accept: 'text/html' } })).text();
  assert.match(html, /Tool<span>Pick/); assert.match(html, /\/logo\.png/); assert.ok(!/<svg/.test(html), 'no code-drawn logo');
  const oa = await (await fetchApp(`${BASE}/openapi.json`)).json();
  assert.deepEqual(Object.keys(oa.paths).sort(), ['/v1/lite', '/v1/market', '/v1/pick', '/v1/preview']);
  assert.equal(oa.paths['/v1/pick'].get['x-payment-info'].price.amount, '0.01'); assert.equal(oa.servers[0].url, BASE);
  const wk = await (await fetchApp(`${BASE}/.well-known/x402`)).json();
  assert.deepEqual(wk.resources, ['lite', 'pick', 'market'].map((t) => `${BASE}/v1/${t}`));
  for (const p of ['/favicon.ico', '/favicon.png', '/logo.png']) { const r = await fetchApp(`${BASE}${p}`); assert.equal(r.headers.get('content-type'), 'image/png'); const b = new Uint8Array(await r.arrayBuffer()); assert.deepEqual([...b.slice(1, 4)], [80, 78, 71]); }
  assert.equal((await fetchApp(`${BASE}/health`)).status, 200);
  const hs = await (await fetchApp(`${BASE}/health?sources=1`)).json(); assert.equal(hs.sources.cdp_discovery.status, 200); assert.equal(hs.sources.payai_discovery.status, 200);
});

test('stdio MCP: validates locally, uses the hosted preview, no key = free mode, market is paid-only', async () => {
  assert.deepEqual(STDIO_TOOLS.map((t) => t.name), ['find_paid_api', 'x402_market_report']);
  assert.equal(toQuery({ need: ' web search ' }).need, 'web search'); assert.ok(toQuery({}).error); assert.ok(toQuery({ need: 'web', network: 'tron' }).error);
  const seen = [];
  const fetchImpl = async (u) => { seen.push(String(u)); return Response.json({ need: 'pdf to text', matches: 12, hosts: 7, top: [{ service: 'PdfCo', price_usd: 0.02, payers_30d: 2, networks: ['base'] }], confidence: 'high' }); };
  const r = await stdioHandle({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: 'find_paid_api', arguments: { need: 'pdf to text' } } }, { fetchImpl, env: {} });
  assert.match(r.result.content[0].text, /ToolPick "pdf to text": 12 matching/);
  assert.equal(seen[0], 'https://api.youraitools.co/toolpick/v1/preview?need=pdf+to+text');
  const s = await stdioHandle({ jsonrpc: '2.0', id: 2, method: 'tools/call', params: { name: 'x402_market_report', arguments: {} } }, { fetchImpl, env: {} });
  assert.equal(s.result.isError, true); assert.match(s.result.content[0].text, /paid only/);
});

test('route descriptions fit facilitator limits (<=500 chars, CDP rejects longer)', async () => {
  const { ROUTES } = await import('../src/tool.js');
  for (const r of ROUTES) assert.ok(r.desc.length <= 500, `${r.tier} desc ${r.desc.length}`);
});

test('empty need on lite and pick is a 400 before the paywall (GET ?need=, POST {"need":""}); bare probes still 402; market unaffected', async () => {
  const net = mockNet(); const { fetchApp } = await makeApp({ net }); const before = net.calls.length;
  for (const tier of ['lite', 'pick']) {
    for (const [u, init] of [[`${BASE}/v1/${tier}?need=`], [`${BASE}/v1/${tier}?q=`], [`${BASE}/v1/${tier}`, json({ need: '' })]]) {
      const r = await fetchApp(u, init);
      assert.equal(r.status, 400, `${init?.method || 'GET'} ${u}`);
      assert.equal(r.headers.get('PAYMENT-REQUIRED'), null);
      assert.match(JSON.stringify(await r.json()), /need/);
    }
    assert.equal((await fetchApp(`${BASE}/v1/${tier}`)).status, 402);
  }
  assert.equal((await fetchApp(`${BASE}/v1/market?need=`)).status, 402);
  assert.equal(net.calls.length, before, 'no upstream call');
});

test('engine label is toolpick-0.1.2 on /health and the root page; free MCP answer names all 4 networks', async () => {
  const net = mockNet(); const { fetchApp } = await makeApp({ net });
  assert.equal((await (await fetchApp(`${BASE}/health`)).json()).engine, 'toolpick-0.1.2');
  const root = await fetchApp(`${BASE}/`, { headers: { accept: 'application/json' } });
  assert.match(await root.text(), /toolpick-0\.1\.2/);
  const r = await mcp(fetchApp, { jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: 'find_paid_api', arguments: { need: 'web search' } } });
  const text = (await r.json()).result.content[0].text;
  assert.match(text, /Base, Polygon, Arbitrum One or Solana/);
  assert.doesNotMatch(text, /Base or Solana\./);
});

agentgate-source: code mirror on Cloudflare Pages. All repos