agenticbtc-mcp 1.0.10 → 1.0.11
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/package.json +1 -1
- package/src/server.js +44 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agenticbtc-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "Privacy-intelligent payments for AI agents — your privacy, your choice. Universal payment router with Lightning, Strike, Coinbase, PayPal, Venmo support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bitcoin",
|
package/src/server.js
CHANGED
|
@@ -11,8 +11,8 @@ import crypto from "crypto";
|
|
|
11
11
|
|
|
12
12
|
const API_URL = process.env.AGENTICBTC_API_URL || process.env.AGENTBTC_API_URL || "http://localhost:8000";
|
|
13
13
|
const API_KEY = process.env.AGENTICBTC_API_KEY || process.env.AGENTBTC_API_KEY || "";
|
|
14
|
-
const LND_HOST = process.env.AGENTBTC_LND_HOST || "";
|
|
15
|
-
const LND_MACAROON = process.env.AGENTBTC_LND_MACAROON || "";
|
|
14
|
+
const LND_HOST = process.env.AGENTICBTC_LND_HOST || process.env.AGENTBTC_LND_HOST || "";
|
|
15
|
+
const LND_MACAROON = process.env.AGENTICBTC_LND_MACAROON || process.env.AGENTBTC_LND_MACAROON || "";
|
|
16
16
|
|
|
17
17
|
// X (Twitter) credentials — optional, enables social posting tools
|
|
18
18
|
const X_CONSUMER_KEY = process.env.TWITTER_CONSUMER_KEY || "";
|
|
@@ -849,20 +849,58 @@ server.tool(
|
|
|
849
849
|
} else if (isStrikeHandle) {
|
|
850
850
|
const handle = recipient.slice(1); // strip "$"
|
|
851
851
|
if (!amount_usd && !amount_sats) return { content: [{ type: "text", text: "Error: amount_usd or amount_sats required for Strike payments" }] };
|
|
852
|
-
|
|
853
|
-
|
|
852
|
+
const satsToSend = amount_sats || 0;
|
|
853
|
+
if (resolvedAgent && satsToSend) {
|
|
854
|
+
const policy = await checkSpendingPolicy(resolvedAgent.id, satsToSend);
|
|
854
855
|
if (!policy.allowed) return { content: [{ type: "text", text: `Payment blocked: ${policy.reason}` }] };
|
|
855
856
|
}
|
|
857
|
+
|
|
858
|
+
// Try Lightning-first: resolve handle@strike.me via LNURL
|
|
859
|
+
if (satsToSend > 0) {
|
|
860
|
+
try {
|
|
861
|
+
const lightningAddr = `${handle}@strike.me`;
|
|
862
|
+
const lnurlRes = await fetch(`https://strike.me/.well-known/lnurlp/${handle}`, { signal: AbortSignal.timeout(5000) });
|
|
863
|
+
if (lnurlRes.ok) {
|
|
864
|
+
const lnurlData = await lnurlRes.json();
|
|
865
|
+
if (lnurlData.status !== "ERROR") {
|
|
866
|
+
const minSats = Math.ceil((lnurlData.minSendable || 1000) / 1000);
|
|
867
|
+
const maxSats = Math.floor((lnurlData.maxSendable || 100000000000) / 1000);
|
|
868
|
+
if (satsToSend >= minSats && satsToSend <= maxSats) {
|
|
869
|
+
let callbackUrl = `${lnurlData.callback}${lnurlData.callback.includes("?") ? "&" : "?"}amount=${satsToSend * 1000}`;
|
|
870
|
+
if (memo && lnurlData.commentAllowed) callbackUrl += `&comment=${encodeURIComponent(memo)}`;
|
|
871
|
+
const invoiceRes = await fetch(callbackUrl, { signal: AbortSignal.timeout(5000) });
|
|
872
|
+
if (invoiceRes.ok) {
|
|
873
|
+
const invoiceData = await invoiceRes.json();
|
|
874
|
+
if (invoiceData.pr) {
|
|
875
|
+
const { status: payStatus, data: payData } = await apiCall("/api/v1/payments", {
|
|
876
|
+
method: "POST",
|
|
877
|
+
body: JSON.stringify({ invoice: invoiceData.pr, fee_limit_sats: Math.max(100, Math.floor(satsToSend * 0.01)) }),
|
|
878
|
+
});
|
|
879
|
+
if (payStatus === 200 && payData.success) {
|
|
880
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: true, type: "strike_handle_via_lightning", recipient, lightning_address: lightningAddr, amount_sats: satsToSend, fee_sats: payData.fee_sats || 0, payment_hash: payData.payment_hash, message: `Sent ${satsToSend} sats to ${recipient} via Lightning (${lightningAddr}) ⚡ — cheaper than Strike API` }) }] };
|
|
881
|
+
}
|
|
882
|
+
// Lightning failed — fall through to Strike API
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
} catch (_) {
|
|
889
|
+
// LNURL resolution failed — fall through to Strike API
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// Fall back to Strike API
|
|
856
894
|
const body = { handle, description: memo || `Payment to $${handle}` };
|
|
857
895
|
if (amount_usd) body.amount_usd = amount_usd;
|
|
858
|
-
if (
|
|
896
|
+
if (satsToSend) body.amount_sats = satsToSend;
|
|
859
897
|
if (resolvedAgent) body.agent_id = resolvedAgent.id;
|
|
860
898
|
const { status, data } = await apiCall("/api/v1/strike/pay", {
|
|
861
899
|
method: "POST",
|
|
862
900
|
body: JSON.stringify(body),
|
|
863
901
|
});
|
|
864
902
|
if (status === 200 && data.success) {
|
|
865
|
-
return { content: [{ type: "text", text: JSON.stringify({ success: true, type: "
|
|
903
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: true, type: "strike_handle_via_api", recipient, amount_usd: data.amount_usd, fee_usd: data.fee_usd || 0, payment_id: data.payment_id, message: `Sent to ${recipient} via Strike API 💸 (Lightning not available for this recipient)` }) }] };
|
|
866
904
|
}
|
|
867
905
|
return { content: [{ type: "text", text: `Payment failed: ${data?.detail || data?.error || JSON.stringify(data)}` }] };
|
|
868
906
|
|