bsv-mcp 0.0.6 → 0.0.8

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/Dockerfile ADDED
@@ -0,0 +1,20 @@
1
+ # Use the official Bun image
2
+ FROM oven/bun:1
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Copy all application code first
8
+ COPY . .
9
+
10
+ # Install dependencies
11
+ RUN bun install --frozen-lockfile
12
+
13
+ # Set user for security
14
+ USER bun
15
+
16
+ # Expose port (if needed)
17
+ EXPOSE 3000
18
+
19
+ # Run the application
20
+ CMD ["bun", "run", "index.ts"]
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Bitcoin SV MCP Server
2
2
 
3
+ [![smithery badge](https://smithery.ai/badge/@b-open-io/bsv-mcp)](https://smithery.ai/server/@b-open-io/bsv-mcp)
4
+
3
5
  > **⚠️ NOTICE: Experimental Work in Progress**
4
6
  > This project is in an early experimental stage. Features may change, and the API is not yet stable.
5
7
  > Contributions, feedback, and bug reports are welcome! Feel free to open issues or submit pull requests.
@@ -14,16 +16,6 @@ To install dependencies:
14
16
  bun install
15
17
  ```
16
18
 
17
- For global installation (recommended for MCP client integration):
18
-
19
- ```bash
20
- # Install globally with bun
21
- bun install -g bsv-mcp
22
-
23
- # Or with npm
24
- npm install -g bsv-mcp
25
- ```
26
-
27
19
  ## External Dependencies
28
20
 
29
21
  For full functionality of all tools, the following additional dependencies are installed:
@@ -38,11 +30,7 @@ js-1sat-ord
38
30
  Start the MCP server:
39
31
 
40
32
  ```bash
41
- # If installed locally
42
33
  bun run index.ts
43
-
44
- # If installed globally
45
- bunx bsv-mcp
46
34
  ```
47
35
 
48
36
  ## Connecting to MCP Clients
@@ -54,7 +42,7 @@ This server implements the [Model Context Protocol](https://modelcontextprotocol
54
42
  To use the BSV MCP server with [Cursor](https://cursor.sh/):
55
43
 
56
44
  1. Install Cursor if you haven't already
57
- 2. Install this package globally: `bun install -g bsv-mcp`
45
+ 2. Clone this repository and run `bun install` in the project directory
58
46
  3. Open Cursor and navigate to Settings → Extensions → Model Context Protocol
59
47
  4. Click "Add a new global MCP server"
60
48
  5. Enter the following configuration in JSON format:
@@ -65,15 +53,17 @@ To use the BSV MCP server with [Cursor](https://cursor.sh/):
65
53
  "command": "env",
66
54
  "args": [
67
55
  "PRIVATE_KEY_WIF=<your_private_key_wif>",
68
- "bunx",
69
- "bsv-mcp"
56
+ "bun",
57
+ "run",
58
+ "<path_to_project>/index.ts"
70
59
  ]
71
60
  }
72
61
  }
73
62
  ```
74
63
 
75
64
  6. Replace `<your_private_key_wif>` with your actual private key WIF (keep this secure!)
76
- 7. Click "Save"
65
+ 7. Replace `<path_to_project>` with the full path to where you cloned this repository
66
+ 8. Click "Save"
77
67
 
78
68
  The BSV tools will now be available to Cursor's AI assistant under the "Bitcoin SV" namespace.
79
69
 
@@ -82,7 +72,7 @@ The BSV tools will now be available to Cursor's AI assistant under the "Bitcoin
82
72
  To connect this server to Claude for Desktop:
83
73
 
84
74
  1. Ensure you have [Claude for Desktop](https://claude.ai/desktop) installed and updated to the latest version
85
- 2. Install this package globally: `bun install -g bsv-mcp`
75
+ 2. Clone this repository and run `bun install` in the project directory
86
76
  3. Open your Claude for Desktop configuration file:
87
77
  ```bash
88
78
  # macOS/Linux
@@ -99,16 +89,18 @@ To connect this server to Claude for Desktop:
99
89
  "command": "env",
100
90
  "args": [
101
91
  "PRIVATE_KEY_WIF=<your_private_key_wif>",
102
- "bunx",
103
- "bsv-mcp"
92
+ "bun",
93
+ "run",
94
+ "<path_to_project>/index.ts"
104
95
  ]
105
96
  }
106
97
  }
107
98
  }
108
99
  ```
109
100
  5. Replace `<your_private_key_wif>` with your actual private key WIF
110
- 6. Save the file and restart Claude for Desktop
111
- 7. The BSV tools will appear when you click the tools icon (hammer) in Claude for Desktop
101
+ 6. Replace `<path_to_project>` with the full path to where you cloned this repository
102
+ 7. Save the file and restart Claude for Desktop
103
+ 8. The BSV tools will appear when you click the tools icon (hammer) in Claude for Desktop
112
104
 
113
105
  ### Generic MCP Client Integration
114
106
 
@@ -120,8 +112,9 @@ For other MCP clients that support JSON configuration:
120
112
  "command": "env",
121
113
  "args": [
122
114
  "PRIVATE_KEY_WIF=<your_private_key_wif>",
123
- "bunx",
124
- "bsv-mcp"
115
+ "bun",
116
+ "run",
117
+ "<path_to_project>/index.ts"
125
118
  ]
126
119
  }
127
120
  }
@@ -134,7 +127,7 @@ If running the server directly:
134
127
  export PRIVATE_KEY_WIF=<your_private_key_wif>
135
128
 
136
129
  # Then run the server
137
- bunx bsv-mcp
130
+ bun run index.ts
138
131
  ```
139
132
 
140
133
  ## Available Tools
@@ -150,8 +143,7 @@ Wallet tools provide core BSV wallet functionality:
150
143
  | `wallet_getPublicKey` | Retrieves a public key for a specified protocol and key ID |
151
144
  | `wallet_createSignature` | Creates a cryptographic signature for the provided data |
152
145
  | `wallet_verifySignature` | Verifies a cryptographic signature against the provided data |
153
- | `wallet_encrypt` | Encrypts data using a specified protocol and key |
154
- | `wallet_decrypt` | Decrypts data using a specified protocol and key |
146
+ | `wallet_encryption` | Combined tool for encrypting and decrypting data using the wallet's cryptographic keys (replaces separate encrypt/decrypt tools) |
155
147
  | `wallet_getAddress` | Returns a BSV address for the current wallet or a derived path |
156
148
  | `wallet_sendToAddress` | Sends BSV to a specified address (supports BSV or USD amounts) |
157
149
  | `wallet_purchaseListing` | Purchases NFTs or BSV-20/BSV-21 tokens from marketplace listings |
@@ -194,6 +186,8 @@ Once connected, you can use natural language to interact with Bitcoin SV through
194
186
  - "Get my Bitcoin SV address"
195
187
  - "Send 0.01 BSV to 1ExampleBsvAddressXXXXXXXXXXXXXXXXX"
196
188
  - "Send $5 USD worth of BSV to 1ExampleBsvAddressXXXXXXXXXXXXXXXXX"
189
+ - "Encrypt this message using my wallet's keys"
190
+ - "Decrypt this data that was previously encrypted for me"
197
191
  - "Purchase this NFT listing: txid_vout"
198
192
  - "Purchase this BSV-20 token listing: txid_vout"
199
193
 
@@ -225,7 +219,7 @@ When you interact with an MCP-enabled AI assistant:
225
219
 
226
220
  If you're having issues connecting to the server:
227
221
 
228
- 1. Ensure the package is properly installed: `bun install -g bsv-mcp`
222
+ 1. Ensure the package dependencies are properly installed: `bun install`
229
223
  2. Verify your WIF private key is correctly set in the environment
230
224
  3. Check that your client supports MCP and is properly configured
231
225
  4. Look for error messages in the client's console output
@@ -239,6 +233,9 @@ For Cursor, check the Cursor MCP logs in Settings → Extensions → Model Conte
239
233
 
240
234
  ## Recent Updates
241
235
 
236
+ ### Unified Encryption Tool
237
+ - **Combined Wallet Encryption**: The `wallet_encrypt` and `wallet_decrypt` tools have been merged into a single `wallet_encryption` tool with a mode parameter to switch between encryption and decryption operations.
238
+
242
239
  ### Enhanced Marketplace Tools
243
240
  - **Unified Market Listings**: The `ordinals_marketListings` tool now supports NFTs, BSV-20, and BSV-21 tokens through a single interface with appropriate filtering.
244
241
  - **Improved Market Sales**: The `ordinals_marketSales` tool (renamed from `ordinals_bsv20MarketSales`) now supports both BSV-20 and BSV-21 token sales.
@@ -254,18 +251,7 @@ This project was created using `bun init` in bun v1.2.9. [Bun](https://bun.sh) i
254
251
 
255
252
  ### Package Configuration
256
253
 
257
- To ensure the package can be run with `bunx bsv-mcp`, make sure your `package.json` includes:
258
-
259
- ```json
260
- {
261
- "name": "bsv-mcp",
262
- "bin": {
263
- "bsv-mcp": "./index.ts"
264
- },
265
- "type": "module"
266
- // ...other configuration
267
- }
268
- ```
254
+ The main entry point for this package is `index.ts`.
269
255
 
270
256
  ### Running Tests
271
257
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "bsv-mcp",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.0.6",
5
+ "version": "0.0.8",
6
6
  "bin": {
7
7
  "bsv-mcp": "./index.ts"
8
8
  },
package/smithery.yaml ADDED
@@ -0,0 +1,21 @@
1
+ build:
2
+ dockerBuildPath: ./
3
+
4
+ startCommand:
5
+ type: stdio
6
+ configSchema:
7
+ type: object
8
+ required:
9
+ - privateKeyWif
10
+ properties:
11
+ privateKeyWif:
12
+ type: string
13
+ description: "The private key WIF (Wallet Import Format) for Bitcoin SV transactions. This key is used to sign transactions and is required for wallet operations."
14
+ commandFunction: |
15
+ (config) => ({
16
+ command: 'bun',
17
+ args: ['run', 'index.ts'],
18
+ env: {
19
+ PRIVATE_KEY_WIF: config.privateKeyWif
20
+ }
21
+ })
@@ -72,6 +72,19 @@ export const walletDecryptArgsSchema = z.object({
72
72
  privileged: z.boolean().optional(),
73
73
  });
74
74
 
75
+ // Combined wallet encryption/decryption args
76
+ export const walletEncryptionArgsSchema = z.object({
77
+ mode: z.enum(["encrypt", "decrypt"]).describe("Operation mode: 'encrypt' to encrypt data or 'decrypt' to decrypt data"),
78
+ data: z.array(z.number()).describe("Data to process: plaintext for encryption or ciphertext for decryption"),
79
+ protocolID: walletProtocolSchema,
80
+ keyID: z.string(),
81
+ privilegedReason: z.string().optional(),
82
+ counterparty: z
83
+ .union([z.string(), z.literal("self"), z.literal("anyone")])
84
+ .optional(),
85
+ privileged: z.boolean().optional(),
86
+ }).describe("Combined schema for encryption and decryption operations, with a mode parameter to switch between functions");
87
+
75
88
  // Create HMAC arguments
76
89
  export const createHmacArgsSchema = z.object({
77
90
  message: z.string(),
@@ -296,3 +309,4 @@ export const purchaseListingArgsSchema = z.object({
296
309
  // Export types
297
310
  export type SendToAddressArgs = z.infer<typeof sendToAddressArgsSchema>;
298
311
  export type PurchaseListingArgs = z.infer<typeof purchaseListingArgsSchema>;
312
+ export type WalletEncryptionArgs = z.infer<typeof walletEncryptionArgsSchema>;
@@ -31,8 +31,7 @@ import {
31
31
  type purchaseListingArgsSchema,
32
32
  type sendToAddressArgsSchema,
33
33
  verifySignatureArgsSchema,
34
- walletDecryptArgsSchema,
35
- walletEncryptArgsSchema,
34
+ walletEncryptionArgsSchema,
36
35
  } from "./schemas";
37
36
 
38
37
  import { registerCreateOrdinalsTool } from "./createOrdinals";
@@ -46,8 +45,7 @@ type ToolArgSchemas = {
46
45
  wallet_getPublicKey: typeof getPublicKeyArgsSchema;
47
46
  wallet_createSignature: typeof createSignatureArgsSchema;
48
47
  wallet_verifySignature: typeof verifySignatureArgsSchema;
49
- wallet_encrypt: typeof walletEncryptArgsSchema;
50
- wallet_decrypt: typeof walletDecryptArgsSchema;
48
+ wallet_encryption: typeof walletEncryptionArgsSchema;
51
49
  wallet_listActions: typeof listActionsArgsSchema;
52
50
  wallet_listOutputs: typeof listOutputsArgsSchema;
53
51
  wallet_getNetwork: typeof emptyArgsSchema;
@@ -94,11 +92,12 @@ export function registerWalletTools(
94
92
  // Handle tools registration with properly typed parameters
95
93
  function registerTool<T extends z.ZodType>(
96
94
  name: keyof ToolArgSchemas,
95
+ description: string,
97
96
  schema: { args: T },
98
97
  handler: ToolCallback<{ args: T }>,
99
98
  ): void {
100
99
  // Register all tools normally
101
- server.tool(name, schema, handler);
100
+ server.tool(name, description, schema, handler);
102
101
  handlers[name] = handler as ToolHandler;
103
102
  }
104
103
 
@@ -117,6 +116,7 @@ export function registerWalletTools(
117
116
  // Register wallet_getPublicKey
118
117
  registerTool(
119
118
  "wallet_getPublicKey",
119
+ "Retrieves the current wallet's public key. This public key can be used for cryptographic operations like signature verification or encryption.",
120
120
  { args: getPublicKeyArgsSchema },
121
121
  async (
122
122
  { args }: { args: z.infer<typeof getPublicKeyArgsSchema> },
@@ -135,6 +135,7 @@ export function registerWalletTools(
135
135
  // Register wallet_createSignature
136
136
  registerTool(
137
137
  "wallet_createSignature",
138
+ "Creates a cryptographic signature using the wallet's private key. This tool enables secure message signing and transaction authorization, supporting various signature protocols.",
138
139
  { args: createSignatureArgsSchema },
139
140
  async (
140
141
  { args }: { args: z.infer<typeof createSignatureArgsSchema> },
@@ -153,6 +154,7 @@ export function registerWalletTools(
153
154
  // Register wallet_verifySignature
154
155
  registerTool(
155
156
  "wallet_verifySignature",
157
+ "Verifies a cryptographic signature against a message or data. This tool supports various verification protocols and can validate signatures from both the wallet's own keys and external public keys.",
156
158
  { args: verifySignatureArgsSchema },
157
159
  async (
158
160
  { args }: { args: z.infer<typeof verifySignatureArgsSchema> },
@@ -168,16 +170,38 @@ export function registerWalletTools(
168
170
  },
169
171
  );
170
172
 
171
- // Register wallet_encrypt
173
+ // Register combined wallet_encryption tool
172
174
  registerTool(
173
- "wallet_encrypt",
174
- { args: walletEncryptArgsSchema },
175
+ "wallet_encryption",
176
+ "Combined tool for encrypting and decrypting data using the wallet's cryptographic keys. Supports both encryption of plaintext data and decryption of previously encrypted content. Use the 'mode' parameter to switch between operations.",
177
+ { args: walletEncryptionArgsSchema },
175
178
  async (
176
- { args }: { args: z.infer<typeof walletEncryptArgsSchema> },
179
+ { args }: { args: z.infer<typeof walletEncryptionArgsSchema> },
177
180
  extra: RequestHandlerExtra,
178
181
  ) => {
179
182
  try {
180
- const result = await wallet.encrypt(args);
183
+ let result: { ciphertext?: number[]; plaintext?: number[] };
184
+ if (args.mode === "encrypt") {
185
+ // For encryption, the data is treated as plaintext
186
+ result = await wallet.encrypt({
187
+ plaintext: args.data,
188
+ protocolID: args.protocolID,
189
+ keyID: args.keyID,
190
+ privilegedReason: args.privilegedReason,
191
+ counterparty: args.counterparty,
192
+ privileged: args.privileged,
193
+ });
194
+ } else {
195
+ // For decryption, the data is treated as ciphertext
196
+ result = await wallet.decrypt({
197
+ ciphertext: args.data,
198
+ protocolID: args.protocolID,
199
+ keyID: args.keyID,
200
+ privilegedReason: args.privilegedReason,
201
+ counterparty: args.counterparty,
202
+ privileged: args.privileged,
203
+ });
204
+ }
181
205
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
182
206
  } catch (err: unknown) {
183
207
  const msg = err instanceof Error ? err.message : String(err);
@@ -186,27 +210,8 @@ export function registerWalletTools(
186
210
  },
187
211
  );
188
212
 
189
- // Register wallet_decrypt
190
- registerTool(
191
- "wallet_decrypt",
192
- { args: walletDecryptArgsSchema },
193
- async (
194
- { args }: { args: z.infer<typeof walletDecryptArgsSchema> },
195
- extra: RequestHandlerExtra,
196
- ) => {
197
- try {
198
- const result = await wallet.decrypt(args);
199
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
200
- } catch (err: unknown) {
201
- const msg = err instanceof Error ? err.message : String(err);
202
- return { content: [{ type: "text", text: msg }], isError: true };
203
- }
204
- },
205
- );
206
-
207
- // Register ordinals extension tools
208
- // Register the wallet_createOrdinals tool
213
+ // Register createOrdinals tool
209
214
  registerCreateOrdinalsTool(server, wallet);
210
-
215
+
211
216
  return handlers;
212
217
  }
@@ -38,6 +38,7 @@ import type {
38
38
  ListOutputsResult,
39
39
  ProveCertificateArgs,
40
40
  ProveCertificateResult,
41
+ PubKeyHex,
41
42
  RelinquishCertificateArgs,
42
43
  RelinquishCertificateResult,
43
44
  RelinquishOutputArgs,
@@ -127,7 +128,15 @@ export class Wallet extends ProtoWallet implements WalletInterface {
127
128
  }
128
129
 
129
130
  async getPublicKey(args: GetPublicKeyArgs): Promise<GetPublicKeyResult> {
130
- return Promise.reject(new Error("Not implemented"));
131
+ const privateKey = this.getPrivateKey();
132
+ if (!privateKey) {
133
+ throw new Error("No private key available");
134
+ }
135
+
136
+ const publicKey = privateKey.toPublicKey();
137
+ return {
138
+ publicKey: publicKey.toDER("hex") as PubKeyHex,
139
+ };
131
140
  }
132
141
  async revealCounterpartyKeyLinkage(
133
142
  args: RevealCounterpartyKeyLinkageArgs,