@hypawave/mcp 0.1.1 → 0.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/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
+ ## [0.2.0] - 2026-07-06
7
+
8
+ ### Added
9
+
10
+ - `setup_wallet` tool (16 tools total): agent-driven wallet provisioning. `create_hosted` registers a fresh Coinos account (registration auto-creates the NWC connection; requires explicit operator consent via `confirm: true`) and saves credentials to `~/.hypawave/wallet.json` (0600, local-only — Hypawave servers never receive them). `connect_own` saves an existing NWC string instead and live-verifies it with a balance probe. Called with no arguments, it returns operator-facing options to present verbatim.
11
+ - `getNwcUrl()` now falls back to `~/.hypawave/wallet.json` when `NWC_URL` / `HYPAWAVE_NWC_URL` are unset (env always wins). `wallet_status` and the startup log report the config source; manual-mode messages point to `setup_wallet`.
12
+ - `COINOS_API_URL` env var (default `https://coinos.io/api`).
13
+
14
+ ### Security
15
+
16
+ - Wallet file is written 0600 and never overwritten while it exists (it may hold a funded wallet's only credentials); corrupt files degrade to manual mode instead of throwing.
17
+
18
+ ## [0.1.2] - 2026-07-02
19
+
20
+ ### Added
21
+
22
+ - `server.json` + `mcpName` in package.json — MCP Registry (registry.modelcontextprotocol.io) publication metadata under `io.github.hypawave/mcp`.
23
+
6
24
  ## [0.1.1] - 2026-07-02
7
25
 
8
26
  ### Added
package/README.md CHANGED
@@ -45,7 +45,7 @@ env = { NWC_URL = "nostr+walletconnect://...", HYPAWAVE_MAX_SPEND_SATS = "10000"
45
45
 
46
46
  All env vars are optional — with no `NWC_URL` the server runs in manual mode (see Wallet below).
47
47
 
48
- ## Tools (15)
48
+ ## Tools (16)
49
49
 
50
50
  | Tool | What it does |
51
51
  |---|---|
@@ -67,6 +67,7 @@ All env vars are optional — with no `NWC_URL` the server runs in manual mode (
67
67
  | `list_sales` | List your settled sales (payments/invoices) — reconcile missed webhooks |
68
68
  | **Utility** | |
69
69
  | `wallet_status` | Wallet balance, seller pubkey, spending cap, live platform fees/limits |
70
+ | `setup_wallet` | One-time wallet setup: create a hosted Coinos wallet (with operator consent) or connect your own NWC string |
70
71
 
71
72
  ## Buy in three calls
72
73
 
@@ -100,13 +101,16 @@ Selling needs **no special wallet** — payouts go straight to your Lightning Ad
100
101
 
101
102
  Paying requires a wallet that returns the settlement **preimage**. Connect any **NWC-capable** wallet (Coinos, Alby Hub, Primal, LNbits, …) via `NWC_URL` — the NWC spec guarantees `pay_invoice` returns the preimage, so any NWC wallet works.
102
103
 
104
+ **No wallet yet? `setup_wallet`.** With explicit operator consent it registers a fresh hosted wallet at coinos.io (custodial — keep only small amounts) and saves the credentials to `~/.hypawave/wallet.json` (0600, local only; Hypawave's servers never receive them — **back this file up: it holds the only copy**). Fund it by sending sats to the returned Lightning address. Or pass your own NWC string via `{action:"connect_own"}`. `NWC_URL`, when set, always wins over the wallet file.
105
+
103
106
  **No wallet configured? Manual mode.** `buy_offer` / `pay_invoice` return the bolt11; pay it with any preimage-returning wallet and submit the preimage via `confirm_payment` (or re-call `pay_invoice` with it).
104
107
 
105
108
  ## Environment variables
106
109
 
107
110
  | Variable | Required | Meaning |
108
111
  |---|---|---|
109
- | `NWC_URL` | no | Nostr Wallet Connect string for automatic payments. Absent → manual mode. |
112
+ | `NWC_URL` | no | Nostr Wallet Connect string for automatic payments. Absent → falls back to `~/.hypawave/wallet.json` (from `setup_wallet`), else manual mode. |
113
+ | `COINOS_API_URL` | no | Coinos API base for `setup_wallet` (default `https://coinos.io/api`). |
110
114
  | `HYPAWAVE_MAX_SPEND_SATS` | no | Per-payment cap enforced in code. Unset → derived live from the platform's `max_invoice_usd` at the current BTC price (so the default never blocks a platform-allowed amount). Payments above it are refused. |
111
115
  | `HYPAWAVE_PRIVKEY` | no | 64-char hex secp256k1 key = your seller identity. Auto-generated to `~/.hypawave/identity.json` (0600) if unset. **Back it up — it controls your offers.** |
112
116
  | `HYPAWAVE_API_URL` | no | API base (default `https://hypawave.com`). |
package/SECURITY.md CHANGED
@@ -8,7 +8,7 @@ A **local stdio MCP server** for Hypawave's accountless Lightning paths (3a/3b).
8
8
 
9
9
  **What stays on your machine (never transmitted):**
10
10
  - **Your seller signing key** — `HYPAWAVE_PRIVKEY` or the auto-generated `~/.hypawave/identity.json` (written with `0600` permissions). Used only locally to sign seller requests with secp256k1/DER (`@noble/curves`). No Hypawave endpoint accepts a private key. **Back it up — it IS your identity and controls your offers.**
11
- - **Your wallet credentials** — the `NWC_URL` connection string. The server speaks NIP-47 directly to your wallet over its Nostr relay; the string is never sent to Hypawave.
11
+ - **Your wallet credentials** — the `NWC_URL` connection string, and `~/.hypawave/wallet.json` when `setup_wallet` provisions a wallet (written `0600`). The server speaks NIP-47 directly to your wallet over its Nostr relay; neither the string nor the file contents are ever sent to Hypawave. For a hosted wallet, `wallet.json` holds the **only copy** of the Coinos username/password — back it up, and never delete it while the wallet holds funds.
12
12
  - **Plaintext files** — encryption and decryption are local AES-256-GCM. Hypawave stores only ciphertext.
13
13
 
14
14
  **What Hypawave's server sees:** ordinary API requests — offer terms, signed request headers (public key + signatures), preimages submitted as settlement proof, and encrypted blobs. Nothing that lets anyone spend from your wallet or impersonate your identity.
@@ -30,6 +30,8 @@ A **local stdio MCP server** for Hypawave's accountless Lightning paths (3a/3b).
30
30
 
31
31
  The recommended buyer setup (a custodial NWC wallet such as Coinos) means the wallet provider holds those funds and can freeze or censor them. Keep only a small working balance there. Sellers are unaffected: payouts go directly to whatever Lightning Address you control.
32
32
 
33
+ `setup_wallet` automates exactly this setup: with explicit operator consent (`confirm: true`) it registers a Coinos account in the operator's name and stores the credentials locally. Hypawave is not the custodian — Coinos is — and Hypawave's servers never receive the credentials. The tool refuses to run without consent and refuses to overwrite an existing wallet file. The only network destination it adds is `coinos.io` (or `COINOS_API_URL`).
34
+
33
35
  ## Dependencies
34
36
 
35
37
  Runtime dependencies are pinned, widely-used libraries: `@modelcontextprotocol/sdk` (MCP transport), `@getalby/sdk` (NIP-47 client), `@noble/curves`/`@noble/hashes` (audited cryptography), `zod`, `ws`. The only network destinations at runtime are the Hypawave API over HTTPS, your wallet's Nostr relay, and presigned storage URLs returned by the API.
package/dist/index.js CHANGED
@@ -18,8 +18,36 @@ var API_BASE = process.env.HYPAWAVE_API_URL || "https://hypawave.com";
18
18
  var FALLBACK_SPEND_CAP_SATS = 5e4;
19
19
  var KEY_DIR = join(homedir(), ".hypawave");
20
20
  var KEY_FILE = join(KEY_DIR, "identity.json");
21
+ var WALLET_FILE = join(KEY_DIR, "wallet.json");
21
22
  function getNwcUrl() {
22
- return process.env.NWC_URL || process.env.HYPAWAVE_NWC_URL || void 0;
23
+ return process.env.NWC_URL || process.env.HYPAWAVE_NWC_URL || readWalletFile()?.nwc_url;
24
+ }
25
+ function getNwcSource() {
26
+ if (process.env.NWC_URL || process.env.HYPAWAVE_NWC_URL) return "env";
27
+ if (readWalletFile()) return "wallet_file";
28
+ return null;
29
+ }
30
+ function readWalletFile() {
31
+ try {
32
+ if (!existsSync(WALLET_FILE)) return void 0;
33
+ const parsed = JSON.parse(readFileSync(WALLET_FILE, "utf8"));
34
+ if (typeof parsed?.nwc_url === "string" && parsed.nwc_url.startsWith("nostr+walletconnect://")) {
35
+ return parsed;
36
+ }
37
+ } catch {
38
+ }
39
+ return void 0;
40
+ }
41
+ function saveWalletFile(wallet) {
42
+ mkdirSync(KEY_DIR, { recursive: true, mode: 448 });
43
+ writeFileSync(WALLET_FILE, JSON.stringify(wallet, null, 2), { mode: 384 });
44
+ return WALLET_FILE;
45
+ }
46
+ function walletFileExists() {
47
+ return existsSync(WALLET_FILE);
48
+ }
49
+ function walletFilePath() {
50
+ return WALLET_FILE;
23
51
  }
24
52
  function getMaxSpendSatsEnv() {
25
53
  const raw = process.env.HYPAWAVE_MAX_SPEND_SATS;
@@ -807,8 +835,161 @@ function registerSellTools(server2) {
807
835
  );
808
836
  }
809
837
 
810
- // src/tools/status.ts
838
+ // src/tools/setup-wallet.ts
811
839
  import { z as z5 } from "zod";
840
+
841
+ // src/coinos.ts
842
+ import { randomBytes as randomBytes4 } from "crypto";
843
+ var COINOS_API = process.env.COINOS_API_URL || "https://coinos.io/api";
844
+ async function coinos(path, opts = {}) {
845
+ const res = await fetch(`${COINOS_API}${path}`, {
846
+ method: opts.body ? "POST" : "GET",
847
+ headers: {
848
+ "content-type": "application/json",
849
+ ...opts.token ? { authorization: `Bearer ${opts.token}` } : {}
850
+ },
851
+ body: opts.body ? JSON.stringify(opts.body) : void 0
852
+ });
853
+ const text = await res.text();
854
+ if (!res.ok) {
855
+ throw new Error(`coinos ${path}: HTTP ${res.status}${text ? ` \u2014 ${text.slice(0, 200)}` : ""}`);
856
+ }
857
+ try {
858
+ return JSON.parse(text);
859
+ } catch {
860
+ throw new Error(`coinos ${path}: non-JSON response`);
861
+ }
862
+ }
863
+ async function createCoinosWallet() {
864
+ const username = `hw${randomBytes4(6).toString("hex")}`;
865
+ const password = randomBytes4(24).toString("base64url");
866
+ const { token } = await coinos("/register", {
867
+ body: { user: { username, password } }
868
+ });
869
+ if (!token) throw new Error("coinos /register returned no auth token");
870
+ const apps = await coinos("/apps", { token });
871
+ const nwc = apps?.find((a) => typeof a?.nwc === "string")?.nwc;
872
+ if (!nwc || !nwc.startsWith("nostr+walletconnect://")) {
873
+ throw new Error("coinos returned no NWC connection for the new account");
874
+ }
875
+ return {
876
+ provider: "coinos",
877
+ username,
878
+ password,
879
+ nwc_url: nwc,
880
+ lightning_address: `${username}@${new URL(COINOS_API).host}`,
881
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
882
+ };
883
+ }
884
+
885
+ // src/tools/setup-wallet.ts
886
+ var OPERATOR_OPTIONS = [
887
+ "To buy things automatically, your agent needs a Lightning wallet it can spend from. Three options:",
888
+ "1. CREATE ONE NOW (recommended for getting started) \u2014 creates a hosted wallet at coinos.io (think prepaid card: funds are held by that service, so keep only small amounts, e.g. $10\u201320 worth of sats; the operator spending cap applies to every payment). Credentials are generated and stored only on this machine \u2014 Hypawave's servers never receive them.",
889
+ "2. CONNECT YOUR OWN WALLET \u2014 if you already use an NWC-capable wallet (Alby Hub, Primal, LNbits, your own node), provide its NWC connection string; no account is created anywhere. Note: self-hosted nodes need channel liquidity even for tiny payments.",
890
+ "3. SKIP \u2014 purchases will return a Lightning invoice to pay manually from any wallet (you'll also need the preimage from your wallet to confirm \u2014 fine for testing, clunky as a routine)."
891
+ ].join("\n");
892
+ var NWC_URI_RE = /^nostr\+walletconnect:\/\/[0-9a-f]{64}\?/i;
893
+ async function tryBalance() {
894
+ try {
895
+ const balance_sats = await Promise.race([
896
+ getBalanceSats(),
897
+ new Promise((_, reject) => setTimeout(() => reject(new Error("timed out after 15s")), 15e3))
898
+ ]);
899
+ return { balance_sats };
900
+ } catch (e) {
901
+ return { balance_sats: null, wallet_error: e instanceof Error ? e.message : String(e) };
902
+ }
903
+ }
904
+ function registerSetupWalletTools(server2) {
905
+ server2.registerTool(
906
+ "setup_wallet",
907
+ {
908
+ title: "Set up the agent's Lightning wallet",
909
+ description: "One-time wallet setup so purchases can pay automatically. Call with no arguments first: it returns the operator-facing options \u2014 present them to the operator verbatim and let them choose; do not choose for them. Then call {action:'create_hosted', confirm:true} ONLY after the operator explicitly agreed (creates a hosted custodial wallet at coinos.io; credentials are stored locally in ~/.hypawave/wallet.json and never sent to Hypawave), or {action:'connect_own', nwc_url:'nostr+walletconnect://\u2026'} to use an existing NWC wallet. The NWC_URL env var, when set, always takes precedence over anything configured here.",
910
+ inputSchema: {
911
+ action: z5.enum(["create_hosted", "connect_own"]).optional().describe("Omit to get the options to present to the operator"),
912
+ confirm: z5.boolean().optional().describe("Required true for create_hosted \u2014 set only after the operator explicitly agreed"),
913
+ nwc_url: z5.string().optional().describe("For connect_own: the wallet's NWC connection string")
914
+ }
915
+ },
916
+ async ({ action, confirm, nwc_url }) => {
917
+ const envSet = Boolean(process.env.NWC_URL || process.env.HYPAWAVE_NWC_URL);
918
+ if (!action) {
919
+ const configured = Boolean(getNwcUrl());
920
+ return jsonResult({
921
+ configured,
922
+ source: getNwcSource(),
923
+ ...configured ? { message: "A wallet is already configured \u2014 no setup needed. Call wallet_status for the balance." } : { present_to_operator: OPERATOR_OPTIONS }
924
+ });
925
+ }
926
+ if (envSet) {
927
+ return jsonResult({
928
+ ok: false,
929
+ message: "NWC_URL is set in the environment and always takes precedence \u2014 unset it in the MCP config first if you want a different wallet."
930
+ });
931
+ }
932
+ if (action === "connect_own") {
933
+ if (!nwc_url || !NWC_URI_RE.test(nwc_url) || !/[?&]secret=[0-9a-f]{64}/i.test(nwc_url)) {
934
+ throw new Error(
935
+ "connect_own requires a valid NWC connection string: nostr+walletconnect://<64-hex-pubkey>?relay=\u2026&secret=<64-hex>"
936
+ );
937
+ }
938
+ if (walletFileExists()) {
939
+ throw new Error(
940
+ `${walletFilePath()} already exists and may hold a funded wallet's only credentials \u2014 back it up and remove it manually first.`
941
+ );
942
+ }
943
+ const path2 = saveWalletFile({
944
+ provider: "custom",
945
+ nwc_url,
946
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
947
+ });
948
+ const check = await tryBalance();
949
+ return jsonResult({
950
+ ok: true,
951
+ provider: "custom",
952
+ saved_to: path2,
953
+ connection_verified: check.balance_sats !== null,
954
+ ...check,
955
+ next: check.balance_sats !== null ? "Wallet connected \u2014 purchases now pay automatically under the spending cap." : "Saved, but the connection could not be verified yet \u2014 check the NWC string and wallet, then call wallet_status."
956
+ });
957
+ }
958
+ if (walletFileExists()) {
959
+ const existing = readWalletFile();
960
+ return jsonResult({
961
+ ok: true,
962
+ already_exists: true,
963
+ provider: existing?.provider ?? "unknown",
964
+ lightning_address: existing?.lightning_address ?? null,
965
+ credentials_file: walletFilePath(),
966
+ message: "A wallet file already exists \u2014 reusing it. Fund it or remove the file manually to start over."
967
+ });
968
+ }
969
+ if (!confirm) {
970
+ return jsonResult({
971
+ ok: false,
972
+ needs_confirmation: true,
973
+ present_to_operator: OPERATOR_OPTIONS,
974
+ message: "create_hosted opens a custodial account at coinos.io in the operator's name. Present the options above, and retry with confirm:true only after the operator explicitly chose option 1."
975
+ });
976
+ }
977
+ const wallet = await createCoinosWallet();
978
+ const path = saveWalletFile(wallet);
979
+ return jsonResult({
980
+ ok: true,
981
+ provider: "coinos",
982
+ lightning_address: wallet.lightning_address,
983
+ credentials_file: path,
984
+ next: `Fund it by sending sats to ${wallet.lightning_address} (start small \u2014 5,000\u201350,000 sats). Then wallet_status shows the balance and purchases pay automatically under the spending cap.`,
985
+ important: `Custodial wallet \u2014 coinos.io holds the funds; keep only small amounts. ${path} contains the ONLY copy of the credentials: back it up, and never delete it while the wallet holds funds.`
986
+ });
987
+ }
988
+ );
989
+ }
990
+
991
+ // src/tools/status.ts
992
+ import { z as z6 } from "zod";
812
993
  function registerStatusTools(server2) {
813
994
  server2.registerTool(
814
995
  "my_offers",
@@ -816,7 +997,7 @@ function registerStatusTools(server2) {
816
997
  title: "List your own offers (seller)",
817
998
  description: "List all offers created by this server's seller identity (pubkey-signed). Shows each offer's status, capacity usage, and activation window \u2014 use manage_offer for details/renewal.",
818
999
  inputSchema: {
819
- status: z5.string().optional().describe("Filter by offer status")
1000
+ status: z6.string().optional().describe("Filter by offer status")
820
1001
  }
821
1002
  },
822
1003
  async ({ status }) => jsonResult(await hw("/api/offers/list", { method: "GET", signed: true, query: { status } }))
@@ -827,11 +1008,11 @@ function registerStatusTools(server2) {
827
1008
  title: "List your sales (seller reconciliation)",
828
1009
  description: "List settled/pending sales for this seller identity (pubkey-signed). kind=offers \u2192 Path 3b payment intents (via /api/offers/list-payments, filterable by offer_id); kind=invoices \u2192 Path 3a invoices (via /api/offers/list-invoices). Returns payment_hash/preimage per sale \u2014 the authoritative way to reconcile missed execution_webhook deliveries.",
829
1010
  inputSchema: {
830
- kind: z5.enum(["offers", "invoices"]),
831
- offer_id: z5.string().uuid().optional().describe("Filter to one offer (kind=offers only)"),
832
- status: z5.string().optional(),
833
- limit: z5.number().int().min(1).max(100).optional(),
834
- offset: z5.number().int().min(0).optional()
1011
+ kind: z6.enum(["offers", "invoices"]),
1012
+ offer_id: z6.string().uuid().optional().describe("Filter to one offer (kind=offers only)"),
1013
+ status: z6.string().optional(),
1014
+ limit: z6.number().int().min(1).max(100).optional(),
1015
+ offset: z6.number().int().min(0).optional()
835
1016
  }
836
1017
  },
837
1018
  async ({ kind, offer_id, status, limit, offset }) => {
@@ -851,10 +1032,10 @@ function registerStatusTools(server2) {
851
1032
  title: "Fetch a settlement receipt for a past purchase",
852
1033
  description: "Retrieve the durable settlement record for a purchase you made. For an offer purchase (Path 3b) pass payment_intent_id + payer_secret (both returned by buy_offer). For an invoice (Path 2/3a) pass invoice_id + preimage (pay_invoice returned the preimage).",
853
1034
  inputSchema: {
854
- payment_intent_id: z5.string().uuid().optional(),
855
- payer_secret: z5.string().optional().describe("Required with payment_intent_id"),
856
- invoice_id: z5.string().optional(),
857
- preimage: z5.string().regex(/^[0-9a-fA-F]{64}$/).optional().describe("Required with invoice_id")
1035
+ payment_intent_id: z6.string().uuid().optional(),
1036
+ payer_secret: z6.string().optional().describe("Required with payment_intent_id"),
1037
+ invoice_id: z6.string().optional(),
1038
+ preimage: z6.string().regex(/^[0-9a-fA-F]{64}$/).optional().describe("Required with invoice_id")
858
1039
  }
859
1040
  },
860
1041
  async ({ payment_intent_id, payer_secret, invoice_id, preimage }) => {
@@ -879,9 +1060,9 @@ function registerStatusTools(server2) {
879
1060
  title: "Check settlement/unlock status of a purchase",
880
1061
  description: "Non-destructive status check. For an offer purchase (Path 3b) pass payment_intent_id + payer_secret \u2014 returns status and the claim_token once settled. For invoices (Path 2/3a) pass invoice_ids \u2014 returns unlock status per invoice.",
881
1062
  inputSchema: {
882
- payment_intent_id: z5.string().uuid().optional(),
883
- payer_secret: z5.string().optional().describe("Required with payment_intent_id"),
884
- invoice_ids: z5.array(z5.string()).optional().describe("Invoice ids to check (Path 2/3a)")
1063
+ payment_intent_id: z6.string().uuid().optional(),
1064
+ payer_secret: z6.string().optional().describe("Required with payment_intent_id"),
1065
+ invoice_ids: z6.array(z6.string()).optional().describe("Invoice ids to check (Path 2/3a)")
885
1066
  }
886
1067
  },
887
1068
  async ({ payment_intent_id, payer_secret, invoice_ids }) => {
@@ -929,9 +1110,10 @@ function registerWalletTools(server2) {
929
1110
  return jsonResult({
930
1111
  wallet: {
931
1112
  nwc_configured: nwcConfigured(),
1113
+ source: getNwcSource(),
932
1114
  balance_sats,
933
1115
  ...wallet_error ? { error: wallet_error } : {},
934
- mode: nwcConfigured() ? "automatic payments" : "manual mode \u2014 tools return bolt11s to pay externally"
1116
+ mode: nwcConfigured() ? "automatic payments" : "manual mode \u2014 tools return bolt11s to pay externally; call setup_wallet to configure a wallet"
935
1117
  },
936
1118
  spending_cap: await getSpendCapSats().catch((e) => ({ error: String(e) })),
937
1119
  seller_pubkey,
@@ -945,7 +1127,7 @@ function registerWalletTools(server2) {
945
1127
  // src/index.ts
946
1128
  var server = new McpServer({
947
1129
  name: "hypawave",
948
- version: "0.1.1"
1130
+ version: "0.2.0"
949
1131
  });
950
1132
  registerDiscoverTools(server);
951
1133
  registerBuyTools(server);
@@ -953,6 +1135,10 @@ registerInvoiceBuyTools(server);
953
1135
  registerSellTools(server);
954
1136
  registerStatusTools(server);
955
1137
  registerWalletTools(server);
1138
+ registerSetupWalletTools(server);
956
1139
  var transport = new StdioServerTransport();
957
1140
  await server.connect(transport);
958
- console.error("hypawave-mcp ready (15 tools; NWC " + (process.env.NWC_URL || process.env.HYPAWAVE_NWC_URL ? "configured" : "not configured \u2014 manual mode") + ")");
1141
+ var nwcSource = getNwcSource();
1142
+ console.error(
1143
+ "hypawave-mcp ready (16 tools; NWC " + (nwcSource ? `configured via ${nwcSource}` : "not configured \u2014 manual mode; setup_wallet available") + ")"
1144
+ );
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@hypawave/mcp",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
+ "mcpName": "io.github.hypawave/mcp",
4
5
  "description": "MCP server for Hypawave — agents buy, sell, and discover over Bitcoin Lightning: search the public offer marketplace, list offers in it or sell agent-to-agent, and settle non-custodially wallet-to-wallet. Verified preimage unlocks files, data, APIs, and compute.",
5
6
  "type": "module",
6
7
  "bin": {