agent402-mcp 0.13.10 → 0.13.12

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  MCP server for [Agent402](https://agent402.tools), the applied layer of [Agentic Finance](https://agent402.tools/agentic-finance) - a catalog of **500+ pay-per-call web tools and curated multi-tool skill packs** for AI agents, paid per call in USDC via the [x402 protocol](https://www.x402.org), **with compute (proof-of-work)** when no wallet is configured, or through a prepaid credits key already issued. (The hosted API is dual-stack: it also accepts [MPP](https://agent402.tools/what-is-mpp) clients on the same 402, settling on Base/Celo or natively on Tempo; this package pays via x402 or credits.) Built by [Havok Holdings LLC](https://github.com/MikeyPetrillo/Agent402).
4
4
 
5
- Your agent gets browser rendering, screenshots, PDF text extraction, URL→markdown, live web search **+ web answers with citations**, live **financial/crypto/macro data** (US equity quotes and daily bars from Databento, CoinGecko, FRED, ECB FX, World Bank, yield curve), **SEC EDGAR filings** (10-K/10-Q text, XBRL, insider, 13F, IPO calendar), **deterministic stats & forecasting** (Pearson correlation, OLS, Holt-Winters), **compression** (gzip/brotli), DNS/TLS/WHOIS + email-deliverability checks, wallet-keyed shared memory, and the pure-CPU utilities - plus **skill packs** like `security-audit`, `trend-analysis`, `structured-scrape`, `decode-blob`, and `forecasting-bake-off` callable as MCP prompts, and the **report products** (deep research, company dossier, 13F fund report, domain audit, token risk, FDA recall, insider flow, market brief) as ordinary catalog slugs. Payment handled invisibly underneath the MCP calls. No signup, no API key.
5
+ Your agent gets browser rendering, screenshots, PDF text extraction, URL→markdown, live web search **+ web answers with citations**, live **financial/crypto/macro data** (US equity quotes and daily bars from a licensed feed, CoinGecko, FRED, ECB FX, World Bank, yield curve), **SEC EDGAR filings** (10-K/10-Q text, XBRL, insider, 13F, IPO calendar), **deterministic stats & forecasting** (Pearson correlation, OLS, Holt-Winters), **compression** (gzip/brotli), DNS/TLS/WHOIS + email-deliverability checks, wallet-keyed shared memory, and the pure-CPU utilities - plus **skill packs** like `security-audit`, `trend-analysis`, `structured-scrape`, `decode-blob`, and `forecasting-bake-off` callable as MCP prompts, and the **report products** (deep research, company dossier, 13F fund report, domain audit, token risk, FDA recall, insider flow, market brief) as ordinary catalog slugs. Payment handled invisibly underneath the MCP calls. No signup, no API key.
6
6
 
7
7
  ## Quick start
8
8
 
@@ -90,7 +90,7 @@ so set `AGENT402_MAX_PER_CALL` if you want a hard per-call ceiling.
90
90
  - `payment.info` tells the model which mode it's in and what a wallet or a credits key would unlock.
91
91
  - `server.describe` returns orientation (flagship-first tools, install one-liners, free vs paid, discovery URLs). Call it first.
92
92
  - `sellers.list` returns the live leaderboards - `wire: "x402"` (default) ranks x402 sellers settling the most USDC (primarily on Base) in the last ~24h from on-chain transfers; `wire: "mpp"` ranks live-verified MPP sellers by inbound USDC.e transfers on Tempo. Free to call (no payment, no proof-of-work). Useful for agents discovering the wider x402 / MPP economy beyond this single service's catalog.
93
- - `route_and_execute` reaches tools **outside** this catalog in one call: give it a plain-language `task` and Agent402 resolves a proven external x402 seller (one with real on-chain settled volume), buys the result from that seller and sells it to you, marked `untrustedContent`. Wallet-only. Flat price, cheapest covering tier chosen from `maxUsd`:
93
+ - `router.execute` (formerly `route_and_execute`, still accepted) reaches tools **outside** this catalog in one call: give it a plain-language `task` and Agent402 resolves a proven external x402 seller (one with real on-chain settled volume), buys the result from that seller and sells it to you, marked `untrustedContent`. Wallet-only. Flat price, cheapest covering tier chosen from `maxUsd`:
94
94
 
95
95
  | Underlying seller price | Fee | Route |
96
96
  | --- | --- | --- |
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // Agent402 MCP server — exposes the agent402.tools catalog (1000+ pay-per-call
2
+ // Agent402 MCP server, exposes the agent402.tools catalog (1000+ pay-per-call
3
3
  // web tools) to any MCP client (Claude, ChatGPT, custom agents) and settles
4
4
  // payment underneath, so the model never sees the 402 dance:
5
5
  //
@@ -13,15 +13,15 @@
13
13
  //
14
14
  // Config (env):
15
15
  // AGENT402_URL target service (default https://agent402.tools)
16
- // AGENT_KEY hex private key of a funded EVM wallet (USDC on Base/Polygon/Arbitrum) — optional
17
- // SOLANA_AGENT_KEY base58 (or JSON byte-array) secret key of a funded Solana wallet (USDC on Solana) — optional
16
+ // AGENT_KEY hex private key of a funded EVM wallet (USDC on Base/Polygon/Arbitrum), optional
17
+ // SOLANA_AGENT_KEY base58 (or JSON byte-array) secret key of a funded Solana wallet (USDC on Solana), optional
18
18
  // AGENT402_TOOLS comma-separated slugs to expose first-class (overrides default)
19
19
  // AGENT402_MAX_PER_CALL refuse any single call priced above this many USD (e.g. 0.01)
20
20
  // AGENT402_CREDITS_KEY a prepaid credits key (a402_...) already issued (new credits are not on
21
21
  // sale); pays per successful call with no wallet
22
22
  // AGENT402_BUDGET hard cap on total USDC spent this session (e.g. 1.00)
23
23
  // AGENT402_NETWORKS restrict + order the chains to pay on (e.g. "robinhood" for USDG on
24
- // Robinhood Chain, "base,solana", or a raw CAIP-2 like eip155:4663) — optional
24
+ // Robinhood Chain, "base,solana", or a raw CAIP-2 like eip155:4663), optional
25
25
  import { createHash } from "node:crypto";
26
26
  import { readFileSync } from "node:fs";
27
27
  import { parseNetworkPrefs, withNetworkPreference } from "./networks.js";
@@ -58,12 +58,12 @@ const HAS_WALLET = Boolean(AGENT_KEY || SOLANA_AGENT_KEY);
58
58
  // list price only on a successful (200) call and returns X-Credits-Balance.
59
59
  const CREDITS_KEY = (process.env.AGENT402_CREDITS_KEY || "").trim();
60
60
  const HAS_CREDITS = /^a402_[A-Za-z0-9_-]{32,64}$/.test(CREDITS_KEY);
61
- // Version comes from package.json — the serverInfo self-report drifted from
61
+ // Version comes from package.json, the serverInfo self-report drifted from
62
62
  // the published version once (0.11.5 vs 0.12.1) because this was a hardcoded
63
63
  // string bumped by hand. Reading the manifest makes drift impossible.
64
64
  const VERSION = JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8")).version;
65
65
 
66
- // Spend controls — enforced BEFORE a payment is ever signed, so a confused or
66
+ // Spend controls, enforced BEFORE a payment is ever signed, so a confused or
67
67
  // runaway model cannot drain the wallet. Unset = unlimited (back-compat).
68
68
  const num = (v) => (v !== undefined && v !== "" && Number.isFinite(Number(v)) ? Number(v) : undefined);
69
69
  const MAX_PER_CALL = num(process.env.AGENT402_MAX_PER_CALL) ?? Infinity;
@@ -71,7 +71,7 @@ const BUDGET = num(process.env.AGENT402_BUDGET) ?? Infinity;
71
71
  let spentUsd = 0;
72
72
 
73
73
  const DEFAULT_CURATED = [
74
- // Flagship demand set — keep aligned with src/mcp-flagship.js FLAGSHIP_SLUGS.
74
+ // Flagship demand set, keep aligned with src/mcp-flagship.js FLAGSHIP_SLUGS.
75
75
  // Search/answer is the front door; long tail stays behind catalog.search/catalog.call.
76
76
  "search", "answer", "search-news", "render",
77
77
  "stock-quote", "transcribe", "memory-read", "memory-write",
@@ -79,13 +79,13 @@ const DEFAULT_CURATED = [
79
79
  "decide", "decide-execute",
80
80
  ];
81
81
 
82
- // stdout is the MCP protocol channel — all logging goes to stderr.
82
+ // stdout is the MCP protocol channel, all logging goes to stderr.
83
83
  const log = (...a) => console.error("[agent402-mcp]", ...a);
84
84
 
85
85
  // ---------------------------------------------------------------------------
86
86
  // Catalog: built from the service's own machine-readable surfaces.
87
87
  const catalog = new Map(); // slug -> { slug, method, path, price, description, category, computePayable, inputSchema }
88
- // Skill packs — curated multi-tool workflows, fetched at startup from the
88
+ // Skill packs, curated multi-tool workflows, fetched at startup from the
89
89
  // hosted service so the npm package picks up new packs without a republish.
90
90
  // Empty if the discovery fetch fails (older services or transient errors);
91
91
  // prompts/list will just return an empty array in that case.
@@ -162,7 +162,7 @@ function getPayFetch() {
162
162
  return payFetchPromise;
163
163
  }
164
164
 
165
- // @solana/kit KeyPairSigner from SOLANA_AGENT_KEY — base58 64-byte secret key
165
+ // @solana/kit KeyPairSigner from SOLANA_AGENT_KEY, base58 64-byte secret key
166
166
  // (Phantom / solana-keygen export) or a JSON byte array ([12,34,…]).
167
167
  let solanaSignerPromise;
168
168
  function solanaSigner() {
@@ -197,7 +197,7 @@ function walletRequiredText(tool) {
197
197
  `"${tool.slug}" costs ${tool.price}/call and requires a USDC wallet (it is not eligible for the proof-of-work tier).`,
198
198
  `To enable it: set AGENT_KEY on this MCP server to the hex private key of an EVM wallet funded with USDC`,
199
199
  `on Base (or Polygon/Arbitrum), and/or SOLANA_AGENT_KEY to the base58 secret key of a Solana wallet funded`,
200
- `with USDC on Solana. Payment is per call via the x402 protocol — no signup or API key.`,
200
+ `with USDC on Solana. Payment is per call via the x402 protocol: no signup or API key.`,
201
201
  `Already hold a prepaid credits key? Set AGENT402_CREDITS_KEY to the a402_ key and it pays per successful call (new credits are not on sale).`,
202
202
  `Pricing and details: ${BASE}/tools/${tool.slug}`,
203
203
  ].join(" ");
@@ -340,10 +340,10 @@ async function callEndpoint(tool, args = {}) {
340
340
  const payFetch = await getPayFetch();
341
341
  res = await payFetch(url, init);
342
342
  // Count spend when the server confirms settlement (payment receipt header),
343
- // falling back to any 2xx — conservative in the buyer's favor.
343
+ // falling back to any 2xx, conservative in the buyer's favor.
344
344
  if (res.headers.get("payment-response") || res.headers.get("x-payment-response") || res.ok) spentUsd += price;
345
345
  } else if (tool.computePayable) {
346
- // No wallet: pay with compute up front — solving before the call skips the
346
+ // No wallet: pay with compute up front, solving before the call skips the
347
347
  // 402 round-trip entirely (challenges are single-use and tool-scoped).
348
348
  const challenge = await (await fetch(`${BASE}/api/pow/challenge?slug=${encodeURIComponent(tool.slug)}`)).json();
349
349
  const nonce = solvePow(challenge);
@@ -382,7 +382,7 @@ function applyFrontDoorTerms(terms, q) {
382
382
  if (!terms.includes("websearch") && (
383
383
  /\b(search\s+the\s+web|web\s+search|search\s+online|google\s+|bing\s+|look\s+up\s+online|find\s+on\s+the\s+web)\b/.test(ql)
384
384
  )) {
385
- // pricing descriptions carry "web search" / "Live web search" — boost those.
385
+ // pricing descriptions carry "web search" / "Live web search", boost those.
386
386
  terms.push("web", "search");
387
387
  }
388
388
  if (!terms.includes("answer") && (
@@ -427,8 +427,8 @@ function searchTools(query, limit = 10) {
427
427
 
428
428
  // Rank the curated multi-tool skill packs against the same query, so a single
429
429
  // search_tools call also tells the agent "this looks like a `security-audit`
430
- // or `email-deliverability` job — fetch the whole template via prompts/get".
431
- // Weighted slug/title/tagline/useCase/toolSlugs match — same shape as the
430
+ // or `email-deliverability` job, fetch the whole template via prompts/get".
431
+ // Weighted slug/title/tagline/useCase/toolSlugs match, same shape as the
432
432
  // hosted /api/find ranking, kept inline here so the stdio package stays
433
433
  // dependency-free. Returns [] when no pack scores above the noise floor.
434
434
  function rankWorkflows(query, k = 2) {
@@ -482,7 +482,7 @@ const server = new Server(
482
482
  { capabilities: { tools: {}, prompts: {} }, instructions: INIT_INSTRUCTIONS },
483
483
  );
484
484
 
485
- // Skill packs are exposed as MCP prompts — discoverable in slash menus on any
485
+ // Skill packs are exposed as MCP prompts, discoverable in slash menus on any
486
486
  // MCP-aware client. The list is fetched once at boot in loadCatalog(); the
487
487
  // per-prompt rendering is delegated to the hosted service so the npm package
488
488
  // stays thin and prompt text stays canonical with the website at /skills.
@@ -622,7 +622,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
622
622
  outputSchema: META_OUTPUT_SCHEMAS["sellers.list"],
623
623
  },
624
624
  {
625
- name: "route_and_execute",
625
+ // Dotted like every other listed tool; route_and_execute stays a CallTool alias.
626
+ name: "router.execute",
626
627
  title: "Route and execute an external x402 tool",
627
628
  annotations: { title: "Route and execute an external x402 tool", ...OPEN },
628
629
  description:
@@ -636,7 +637,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
636
637
  },
637
638
  required: ["task"],
638
639
  },
639
- outputSchema: META_OUTPUT_SCHEMAS.route_and_execute,
640
+ outputSchema: META_OUTPUT_SCHEMAS["router.execute"],
640
641
  }
641
642
  );
642
643
  return { tools };
@@ -815,7 +816,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
815
816
  const include = args.include === "all" ? "all" : "external";
816
817
  // /api/leaderboard is free + unpaywalled, so this stays free regardless
817
818
  // of payment mode. Honor its query params verbatim so the surface is a
818
- // thin pass-through — single source of truth for ranking + filtering.
819
+ // thin pass-through, single source of truth for ranking + filtering.
819
820
  const url = new URL(`${BASE}/api/leaderboard`);
820
821
  url.searchParams.set("top", String(limit));
821
822
  url.searchParams.set("sort", sort);
@@ -825,7 +826,7 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
825
826
  return { content: [{ type: "text", text: `Failed to fetch leaderboard from ${BASE}: HTTP ${res.status}` }], isError: true };
826
827
  }
827
828
  const snap = await res.json();
828
- // Trim to the same compact row shape the hosted MCP connector returns —
829
+ // Trim to the same compact row shape the hosted MCP connector returns,
829
830
  // cross-surface agents see one mental model. Full row (origins,
830
831
  // endpoints, scan metadata) stays accessible at /api/leaderboard.
831
832
  // Same untrusted-content marking as the hosted connector: a seller's
@@ -850,13 +851,13 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
850
851
  include: snap.include || include,
851
852
  totalSellers: snap.totalSellers ?? (snap.leaderboard || []).length,
852
853
  results: rows,
853
- ...(snap.warming || snap.scanSkipped ? { note: "Cache is warming — results may be partial. Retry in ~60s." } : {}),
854
+ ...(snap.warming || snap.scanSkipped ? { note: "Cache is warming: results may be partial. Retry in ~60s." } : {}),
854
855
  source: `${BASE}/api/leaderboard`,
855
856
  });
856
857
  }
857
- if (name === "route_and_execute") {
858
+ if (name === "router.execute") {
858
859
  const task = String(args.task ?? "").trim();
859
- if (!task) return { content: [{ type: "text", text: "route_and_execute requires a 'task' (plain-language description of what you need)." }], isError: true };
860
+ if (!task) return { content: [{ type: "text", text: "router.execute requires a 'task' (plain-language description of what you need)." }], isError: true };
860
861
  const maxUsd = Number(args.maxUsd) > 0 ? Number(args.maxUsd) : 0.005;
861
862
  // Pick the CHEAPEST tier whose underlying cap covers maxUsd. The ladder
862
863
  // has three rungs; skipping the middle one billed 11x for a mid-priced
@@ -866,13 +867,13 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
866
867
  : maxUsd > 0.005 ? "route-execute-plus"
867
868
  : "route-execute";
868
869
  const tool = catalog.get(slug);
869
- if (!tool) return { content: [{ type: "text", text: `External routing (${slug}) is not in the catalog from ${BASE} yet — it may be rolling out. Retry shortly.` }], isError: true };
870
+ if (!tool) return { content: [{ type: "text", text: `External routing (${slug}) is not in the catalog from ${BASE} yet. It may be rolling out; retry shortly.` }], isError: true };
870
871
  // Body matches the route-execute input schema; include:"external" is what
871
872
  // pays an OUTSIDE seller (vs this host's catalog). Paid via callEndpoint.
872
873
  return await callEndpoint(tool, { task, include: "external", maxUsd, ...(args.params && typeof args.params === "object" ? { params: args.params } : {}) });
873
874
  }
874
875
  // Curated tools are exposed verb_noun for tools/list consistency, but the
875
- // real slug is kebab — accept exposed name, plain snake, or raw slug.
876
+ // real slug is kebab, accept exposed name, plain snake, or raw slug.
876
877
  const mcpToSlug = new Map(Object.entries(FLAGSHIP_MCP_NAMES).map(([slug, mcp]) => [mcp, slug]));
877
878
  const wanted = name === "catalog.call"
878
879
  ? String(args.slug ?? "")
@@ -902,11 +903,11 @@ try {
902
903
  pricingInfo = await loadCatalog();
903
904
  } catch (err) {
904
905
  // Don't hard-exit: starting with an empty catalog still lets the server
905
- // connect and answer introspection (tools/list) — required to pass directory
906
+ // connect and answer introspection (tools/list), required to pass directory
906
907
  // health checks (e.g. Glama) and more resilient if the catalog endpoint is
907
908
  // briefly unreachable. catalog.search/catalog.call just return nothing until the
908
909
  // catalog is reachable again.
909
- log(`Could not load the catalog from ${BASE}: ${err.message} — starting with an empty catalog`);
910
+ log(`Could not load the catalog from ${BASE}: ${err.message}: starting with an empty catalog`);
910
911
  }
911
912
  const requested = (process.env.AGENT402_TOOLS || DEFAULT_CURATED.join(","))
912
913
  .split(",").map((s) => s.trim()).filter(Boolean);
package/networks.js CHANGED
@@ -1,9 +1,9 @@
1
- // Network preference for the x402 buyer — pure helpers, no side effects.
1
+ // Network preference for the x402 buyer, pure helpers, no side effects.
2
2
  //
3
3
  // AGENT402_NETWORKS (comma-separated, e.g. "robinhood" or "base,solana" or a
4
4
  // raw CAIP-2 like "eip155:4663") restricts AND orders which payment options
5
5
  // the buyer will consider from a seller's 402 `accepts`. Without it the
6
- // underlying @x402 client picks whichever registered scheme matches first —
6
+ // underlying @x402 client picks whichever registered scheme matches first,
7
7
  // which on a multi-chain seller is effectively always Base, making rails like
8
8
  // USDG on Robinhood Chain unreachable no matter what the wallet holds.
9
9
 
@@ -30,7 +30,7 @@ export function parseNetworkPrefs(raw) {
30
30
 
31
31
  /** Filter a 402's accepts to the preferred networks, ordered by preference
32
32
  * (all accepts for the 1st preferred chain, then the 2nd, …). Throws with an
33
- * actionable message when nothing matches — better than silently paying on a
33
+ * actionable message when nothing matches, better than silently paying on a
34
34
  * chain the operator excluded. No prefs → accepts unchanged. */
35
35
  export function filterAcceptsByNetworks(accepts, prefs) {
36
36
  if (!prefs?.length) return accepts;
@@ -39,14 +39,14 @@ export function filterAcceptsByNetworks(accepts, prefs) {
39
39
  if (!picked.length) {
40
40
  const offered = [...new Set(list.map((a) => a?.network).filter(Boolean))];
41
41
  throw new Error(
42
- `AGENT402_NETWORKS matched none of the seller's payment options — wanted [${prefs.join(", ")}], offered [${offered.join(", ")}]. ` +
42
+ `AGENT402_NETWORKS matched none of the seller's payment options: wanted [${prefs.join(", ")}], offered [${offered.join(", ")}]. ` +
43
43
  "Remove the restriction or add one of the offered networks."
44
44
  );
45
45
  }
46
46
  return picked;
47
47
  }
48
48
 
49
- /** Apply the preference to an @x402 client (duck-typed — any version with
49
+ /** Apply the preference to an @x402 client (duck-typed, any version with
50
50
  * createPaymentPayload works): the client only ever sees the filtered,
51
51
  * preference-ordered accepts. Returns the same client for chaining. */
52
52
  export function withNetworkPreference(client, prefs) {
package/output-schemas.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // (stdio package cannot import src/ when published). Keep in sync manually
3
3
  // when flagship names or output schemas change.
4
4
 
5
- // Flagship MCP surface — the small default tools/list agents see first.
5
+ // Flagship MCP surface, the small default tools/list agents see first.
6
6
  //
7
7
  // Product intent: Agent402 is a tools and models layer for agents -
8
8
  // deterministic utilities, a metered model gateway, finished reports. Default
@@ -26,7 +26,7 @@ export const FLAGSHIP_SLUGS = [
26
26
  "memory-write",
27
27
  ];
28
28
 
29
- // Smithery Naming grades DOT notation (domain.action tree), not snake_case —
29
+ // Smithery Naming grades DOT notation (domain.action tree), not snake_case,
30
30
  // stuck-at-98 lesson: "Tool names should form a navigable tree using
31
31
  // dot-notation (e.g. admin.tools.list)". CallTool still accepts prior snake /
32
32
  // digit names via MCP_CALL_ALIASES.
@@ -43,7 +43,7 @@ export const FLAGSHIP_MCP_NAMES = {
43
43
  "decide-execute": "decide.execute",
44
44
  };
45
45
 
46
- /** Meta tools listed alongside flagships — dotted canonical names. */
46
+ /** Meta tools listed alongside flagships, dotted canonical names. */
47
47
  export const META_MCP_NAMES = {
48
48
  search_tools: "catalog.search",
49
49
  find_tool: "catalog.find",
@@ -82,6 +82,7 @@ export const MCP_CALL_ALIASES = {
82
82
  list_top_sellers: "sellers.list",
83
83
  list_x402_sellers: "sellers.list",
84
84
  top_x402_sellers: "sellers.list",
85
+ route_and_execute: "router.execute",
85
86
  };
86
87
 
87
88
  /** Resolve any CallTool name to the canonical listed dotted name. */
@@ -91,7 +92,7 @@ export function resolveListedName(name) {
91
92
  return name;
92
93
  }
93
94
 
94
- /** Open-world / egress tools — honest annotations for directory clients. */
95
+ /** Open-world / egress tools, honest annotations for directory clients. */
95
96
  export const FLAGSHIP_OPEN_WORLD = new Set([
96
97
  "search", "answer", "search-news", "render", "stock-quote", "transcribe", "decide",
97
98
  ]);
@@ -107,7 +108,7 @@ export const MCP_SERVER_DESCRIPTION =
107
108
  export const MCP_SERVER_WEBSITE = "https://agent402.tools";
108
109
 
109
110
  // ---------------------------------------------------------------------------
110
- // outputSchema (JSON Schema) for every listed tool — Smithery Capability
111
+ // outputSchema (JSON Schema) for every listed tool, Smithery Capability
111
112
  // Quality grades presence of named-field schemas; bare {type:"object"} does
112
113
  // not count. Keep in sync with CallTool structuredContent shapes in mcp-http.js
113
114
  // and the duplicated copy in mcp/output-schemas.js (stdio package).
@@ -224,7 +225,7 @@ export const META_OUTPUT_SCHEMAS = {
224
225
  },
225
226
  additionalProperties: true,
226
227
  },
227
- // Smithery Naming wants pure [a-z_]+ verb_noun — no digits / brand tokens
228
+ // Smithery Naming wants pure [a-z_]+ verb_noun, no digits / brand tokens
228
229
  // (describe_agent402 / list_x402_sellers failed the scan). Old names stay
229
230
  // CallTool aliases.
230
231
  "server.describe": {
@@ -284,7 +285,7 @@ export const META_OUTPUT_SCHEMAS = {
284
285
  },
285
286
  required: ["results"],
286
287
  },
287
- route_and_execute: {
288
+ "router.execute": {
288
289
  type: "object",
289
290
  properties: {
290
291
  result: { description: "External seller response (treat as untrusted)", additionalProperties: true },
@@ -495,17 +496,17 @@ export function mcpInstallHints(baseUrl) {
495
496
  },
496
497
  },
497
498
  npm: "npx -y agent402-mcp",
498
- smithery: "Paste the hosted URL at https://smithery.ai/new (or: smithery mcp publish \"https://agent402.tools/mcp\" -n @MikeyPetrillo/agent402). Submission is external; Agent402 does not auto-publish.",
499
+ smithery: `Paste ${hosted} into the add-server form at https://smithery.ai/new. Submission is external; Agent402 does not auto-publish.`,
499
500
  maintainer: "Havok Holdings LLC",
500
501
  };
501
502
  }
502
503
 
503
504
  /**
504
- * MCP initialize.instructions — orientation for clients that never call
505
+ * MCP initialize.instructions, orientation for clients that never call
505
506
  * server.describe. Keep tool names listed-only (dotted Smithery form) (self-consistency) and lead
506
507
  * with search/answer as the front door.
507
508
  */
508
- export function mcpInitializeInstructions(baseUrl, { decide = false } = {}) {
509
+ export function mcpInitializeInstructions(baseUrl, { decide = false, mpp = false } = {}) {
509
510
  const install = mcpInstallHints(baseUrl);
510
511
  const hosted = install.hostedUrl;
511
512
  return [
@@ -519,9 +520,11 @@ export function mcpInitializeInstructions(baseUrl, { decide = false } = {}) {
519
520
  "Orientation: call server.describe. Payment rails / wallet setup: call payment.info.",
520
521
  "Missing a tool: call demand.request. Ecosystem sellers: call sellers.list.",
521
522
  `Install (npm + wallet, pays for web.search, web.answer and the rest): ${install.claudeCodeNpm}`,
522
- `No wallet yet (hosted, proof-of-work tools only): ${install.claudeCodeHosted}`,
523
+ // The hosted line says what that connector takes: with MPP on it, a wallet
524
+ // can pay the other tools there too.
525
+ `${mpp ? "Hosted (proof-of-work tools free; the rest payable there over MPP from a wallet)" : "No wallet yet (hosted, proof-of-work tools only)"}: ${install.claudeCodeHosted}`,
523
526
  `Cursor mcp.json: { "mcpServers": { "agent402": { "url": "${hosted}" } } }`,
524
- `Why pay here (usage priced under a quoted ceiling, a failed call is not charged and the receipt proves it, keyed retries never pay twice, one key for tools + models + reports, no wallet needed for the proof-of-work tools or a report by card, proof at /status and /revenue): ${baseUrl}/why`,
527
+ `Why pay here (usage priced under a quoted ceiling, a failed call is not charged and the receipt proves it, keyed retries never pay twice, one key for tools + models + reports, no wallet needed for the proof-of-work tools or a report by card, proof at /status and /revenue): ${baseUrl}/#why`,
525
528
  `Docs: ${baseUrl}/llms.txt · ${baseUrl}/api/find?q=… · status ${baseUrl}/status`,
526
529
  ].join("\n");
527
530
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent402-mcp",
3
- "version": "0.13.10",
3
+ "version": "0.13.12",
4
4
  "mcpName": "io.github.MikeyPetrillo/agent402",
5
5
  "author": "Havok Holdings LLC <mike@agent402.tools> (https://agent402.tools)",
6
6
  "homepage": "https://agent402.tools",