Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,5 @@ Thumbs.db

# AI Agents or Tools
CLAUDE.md
.claude
*PLAN.md
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "phoenixd-mcp-server",
"version": "1.1.0",
"version": "1.2.0",
"description": "Connect a phoenixd bitcoin lightning wallet to your LLM.",
"keywords": [
"phoenixd",
Expand Down
18 changes: 11 additions & 7 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ If phoenixd runs on a remote server behind a reverse proxy with TLS:
- `create-invoice`
- Create a bolt11 invoice with a specified amount and description.
- Inputs:
- `description` (string): The description of the invoice (max. 128 characters).
- `description` (string, optional): The description of the invoice (max. 128 characters). Either `description` or `descriptionHash` must be provided.
- `descriptionHash` (string, optional): SHA256 hash of the description. Use instead of `description`.
- `amountSat` (number, optional): The amount requested by the invoice, in satoshi. If not set, the invoice can be paid by any amount.
- `expirySeconds` (number, optional): The invoice expiry in seconds, default 3600 (1 hour).
- `externalId` (string, optional): A custom identifier to link the invoice to an external system.
Expand All @@ -90,22 +91,26 @@ If phoenixd runs on a remote server behind a reverse proxy with TLS:
- Pay a bolt11 invoice.
- Inputs:
- `invoice` (string): The bolt11 invoice to pay.
- `amountMsat` (number, optional): Amount to pay in millisatoshis (only for zero-amount invoices).
- `amountSat` (number, optional): Amount to pay in satoshis (only for zero-amount invoices). Mutually exclusive with `sendAll`.
- `sendAll` (boolean, optional): If true, empties the wallet. Mutually exclusive with `amountSat`.
- `externalId` (string, optional): A custom identifier to link the payment to an external system.

- `pay-offer`
- Pay a bolt12 offer.
- Inputs:
- `offer` (string): The bolt12 offer to pay.
- `amountMsat` (number): Amount to pay in millisatoshis. Required because BOLT12 offers can be reusable and variable-amount.
- `amountSat` (number, optional): Amount to pay in satoshis. Mutually exclusive with `sendAll`.
- `sendAll` (boolean, optional): If true, empties the wallet. Mutually exclusive with `amountSat`.
- `message` (string, optional): A message for the recipient.
- `externalId` (string, optional): A custom identifier to link the payment to an external system.

- `pay-lightning-address`
- Pay a Lightning Address.
- Inputs:
- `address` (string): The Lightning Address to pay (e.g., swamppawpaw18@phoenixwallet.me).
- `amountSat` (number): Amount to pay in satoshis.
- `comment` (string, optional): Optional comment to include with the payment.
- `amountSat` (number, optional): Amount to pay in satoshis. Mutually exclusive with `sendAll`.
- `sendAll` (boolean, optional): If true, empties the wallet. Mutually exclusive with `amountSat`.
- `message` (string, optional): Optional message to include with the payment.

- `pay-on-chain`
- Send an on-chain Bitcoin payment.
Expand All @@ -115,9 +120,8 @@ If phoenixd runs on a remote server behind a reverse proxy with TLS:
- `feerateSatByte` (number, optional): Fee rate in satoshis per byte.

- `bump-fee`
- Bump the fee of an unconfirmed on-chain transaction.
- Bumps the fee rate of all unconfirmed on-chain transactions using CPFP. Returns the ID of the child transaction.
- Inputs:
- `txId` (string): The transaction ID to bump.
- `feerateSatByte` (number): New fee rate in satoshis per byte.

- `list-incoming-payments`
Expand Down
16 changes: 12 additions & 4 deletions src/tools/create_invoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,25 @@ export function registerCreateInvoiceTool(
'create-invoice',
'Create a bolt11 invoice with a specified amount and description',
{
description: z.string().describe('The description of the invoice (max. 128 characters).'),
description: z.string().optional()
.describe('The description of the invoice (max. 128 characters). Either description or descriptionHash must be provided.'),
descriptionHash: z.string().optional().describe('SHA256 hash of the description. Use instead of description.'),
amountSat: z.number().optional()
.describe('The amount requested by the invoice, in satoshi. If not set, the invoice can be paid by any amount.'),
expirySeconds: z.number().optional().describe('The invoice expiry in seconds, by default 3600 (1 hour).'),
externalId: z.string().optional().describe('A custom identifier. Use that to link the invoice to an external system.'),
webhookUrl: z.string().optional().describe('A webhook url that will be notified when this specific payment has been received. '),
webhookUrl: z.string().optional().describe('A webhook url that will be notified when this specific payment has been received.'),
},
async ({ description, amountSat, expirySeconds, externalId, webhookUrl }) => {
async ({ description, descriptionHash, amountSat, expirySeconds, externalId, webhookUrl }) => {
validateEnv(config);

const paramsObj: Record<string, string> = { description };
if (!description && !descriptionHash) {
return formatToolError('Either description or descriptionHash must be provided.');
}

const paramsObj: Record<string, string> = {};
if (description !== undefined) paramsObj.description = description;
if (descriptionHash !== undefined) paramsObj.descriptionHash = descriptionHash;
if (amountSat !== undefined) paramsObj.amountSat = amountSat.toString();
if (expirySeconds !== undefined) paramsObj.expirySeconds = expirySeconds.toString();
if (externalId !== undefined) paramsObj.externalId = externalId;
Expand Down
7 changes: 5 additions & 2 deletions src/tools/pay_invoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ export function registerPayInvoiceTool(
'pay-invoice',
'Pay a bolt11 invoice with a specified amount and description',
{
amountSat: z.number().optional().describe('The amount to pay, in satoshi. If not set, will pay the amount requested in the invoice.'),
invoice: z.string().describe('The bolt11 invoice to pay.'),
amountSat: z.number().optional()
.describe('The amount to pay, in satoshi. If not set, will pay the amount requested in the invoice. Mutually exclusive with sendAll.'),
sendAll: z.boolean().optional().describe('If true, empties the wallet. Mutually exclusive with amountSat.'),
},
async ({ amountSat, invoice }) => {
async ({ amountSat, invoice, sendAll }) => {
validateEnv(config);

const paramsObj: Record<string, string> = { invoice };
if (amountSat !== undefined) paramsObj.amountSat = amountSat.toString();
if (sendAll !== undefined) paramsObj.sendAll = sendAll.toString();

const result = await fetchPhoenixd(config, '/payinvoice', {
method: 'POST',
Expand Down
7 changes: 5 additions & 2 deletions src/tools/pay_lightning_address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@ export function registerPayLightningAddressTool(
'pay-lightning-address',
'Pays an email-like Lightning address, either based on BIP-353 or LNURL',
{
amountSat: z.number().optional().describe('The amount in satoshi. If unset, will pay the amount requested in the offer.'),
address: z.string().describe('The Lightning address to pay.'),
amountSat: z.number().optional()
.describe('The amount in satoshi. If unset, will pay the amount requested. Mutually exclusive with sendAll.'),
sendAll: z.boolean().optional().describe('If true, empties the wallet. Mutually exclusive with amountSat.'),
message: z.string().optional().describe('A message for the recipient.'),
},
async ({ amountSat, address, message }) => {
async ({ amountSat, address, message, sendAll }) => {
validateEnv(config);

const paramsObj: Record<string, string> = { address };
if (amountSat !== undefined) paramsObj.amountSat = amountSat.toString();
if (sendAll !== undefined) paramsObj.sendAll = sendAll.toString();
if (message !== undefined) paramsObj.message = message;

const result = await fetchPhoenixd(config, '/paylnaddress', {
Expand Down
7 changes: 5 additions & 2 deletions src/tools/pay_offer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@ export function registerPayOfferTool(
'pay-offer',
'Pay a bolt12 offer',
{
amountSat: z.number().optional().describe('The amount in satoshi. If unset, will pay the amount requested in the offer.'),
offer: z.string().describe('The bolt12 offer to pay.'),
amountSat: z.number().optional()
.describe('The amount in satoshi. If unset, will pay the amount requested in the offer. Mutually exclusive with sendAll.'),
sendAll: z.boolean().optional().describe('If true, empties the wallet. Mutually exclusive with amountSat.'),
message: z.string().optional().describe('A message for the recipient.'),
},
async ({ amountSat, offer, message }) => {
async ({ amountSat, offer, message, sendAll }) => {
validateEnv(config);

const paramsObj: Record<string, string> = { offer };
if (amountSat !== undefined) paramsObj.amountSat = amountSat.toString();
if (sendAll !== undefined) paramsObj.sendAll = sendAll.toString();
if (message !== undefined) paramsObj.message = message;

const result = await fetchPhoenixd(config, '/payoffer', {
Expand Down
Loading