@codespar/mcp-bitso 0.1.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/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # @codespar/mcp-bitso
2
+
3
+ > MCP server for **Bitso** — Latin American cryptocurrency exchange with trading, orders, and withdrawals
4
+
5
+ [![npm](https://img.shields.io/npm/v/@codespar/mcp-bitso)](https://www.npmjs.com/package/@codespar/mcp-bitso)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Quick Start
9
+
10
+ ### Claude Desktop
11
+
12
+ Add to `~/.config/claude/claude_desktop_config.json`:
13
+
14
+ ```json
15
+ {
16
+ "mcpServers": {
17
+ "bitso": {
18
+ "command": "npx",
19
+ "args": ["-y", "@codespar/mcp-bitso"],
20
+ "env": {
21
+ "BITSO_API_KEY": "your-key",
22
+ "BITSO_API_SECRET": "your-secret"
23
+ }
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ ### Claude Code
30
+
31
+ ```bash
32
+ claude mcp add bitso -- npx @codespar/mcp-bitso
33
+ ```
34
+
35
+ ### Cursor / VS Code
36
+
37
+ Add to `.cursor/mcp.json` or `.vscode/mcp.json`:
38
+
39
+ ```json
40
+ {
41
+ "servers": {
42
+ "bitso": {
43
+ "command": "npx",
44
+ "args": ["-y", "@codespar/mcp-bitso"],
45
+ "env": {
46
+ "BITSO_API_KEY": "your-key",
47
+ "BITSO_API_SECRET": "your-secret"
48
+ }
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ ## Tools
55
+
56
+ | Tool | Description |
57
+ |------|-------------|
58
+ | `get_ticker` | Get ticker data for a trading pair (price, volume, VWAP, etc.) |
59
+ | `list_orderbook` | Get order book (bids and asks) for a trading pair |
60
+ | `create_order` | Create a buy or sell order |
61
+ | `get_order` | Get order details by ID |
62
+ | `cancel_order` | Cancel an open order |
63
+ | `list_orders` | List orders with optional filters |
64
+ | `get_balances` | Get account balances for all assets |
65
+ | `list_trades` | List executed trades for an order book |
66
+ | `list_funding_sources` | List available funding sources (bank accounts, etc.) |
67
+ | `create_withdrawal` | Create a withdrawal request (crypto or fiat) |
68
+
69
+ ## Authentication
70
+
71
+ Bitso uses HMAC-SHA256 signed requests with an API key and secret.
72
+
73
+ ## Sandbox / Testing
74
+
75
+ Bitso provides a developer sandbox via the developer account.
76
+
77
+ ### Get your credentials
78
+
79
+ 1. Go to [Bitso](https://bitso.com)
80
+ 2. Create an account
81
+ 3. Navigate to API settings and generate key and secret
82
+ 4. Set the environment variables
83
+
84
+ ## Environment Variables
85
+
86
+ | Variable | Required | Description |
87
+ |----------|----------|-------------|
88
+ | `BITSO_API_KEY` | Yes | API key from Bitso |
89
+ | `BITSO_API_SECRET` | Yes | API secret for HMAC signature |
90
+
91
+ ## Roadmap
92
+
93
+ ### v0.2 (planned)
94
+ - `get_account_status` — Get account verification status
95
+ - `list_currencies` — List available cryptocurrencies
96
+ - `create_spei_withdrawal` — Create a SPEI (Mexican bank) withdrawal
97
+ - `get_phone_number` — Get phone number associated with account
98
+ - `list_open_orders` — List all open orders
99
+
100
+ ### v0.3 (planned)
101
+ - `recurring_orders` — Create and manage recurring buy/sell orders
102
+ - `advanced_orders` — Advanced order types (OCO, trailing stop)
103
+
104
+ Want to contribute? [Open a PR](https://github.com/codespar/mcp-dev-brasil) or [request a tool](https://github.com/codespar/mcp-dev-brasil/issues).
105
+
106
+ ## Links
107
+
108
+ - [Bitso Website](https://bitso.com)
109
+ - [Bitso API Documentation](https://bitso.com/developers)
110
+ - [MCP Dev Brasil](https://github.com/codespar/mcp-dev-brasil)
111
+ - [Landing Page](https://codespar.dev/mcp)
112
+
113
+ ## License
114
+
115
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Server for Bitso — Latin American cryptocurrency exchange.
4
+ *
5
+ * Tools:
6
+ * - get_ticker: Get ticker data for a trading pair
7
+ * - list_orderbook: Get order book for a trading pair
8
+ * - create_order: Create a buy or sell order
9
+ * - get_order: Get order details by ID
10
+ * - cancel_order: Cancel an open order
11
+ * - list_orders: List orders with filters
12
+ * - get_balances: Get account balances
13
+ * - list_trades: List executed trades
14
+ * - list_funding_sources: List available funding sources
15
+ * - create_withdrawal: Create a withdrawal request
16
+ *
17
+ * Environment:
18
+ * BITSO_API_KEY — API key from https://bitso.com/
19
+ * BITSO_API_SECRET — API secret for HMAC signature
20
+ */
21
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
22
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
23
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
24
+ import * as crypto from "node:crypto";
25
+ const API_KEY = process.env.BITSO_API_KEY || "";
26
+ const API_SECRET = process.env.BITSO_API_SECRET || "";
27
+ const BASE_URL = "https://api.bitso.com/v3";
28
+ function generateAuthHeader(method, path, body) {
29
+ const nonce = Date.now().toString();
30
+ const payload = nonce + method.toUpperCase() + path + (body || "");
31
+ const signature = crypto.createHmac("sha256", API_SECRET).update(payload).digest("hex");
32
+ return `Bitso ${API_KEY}:${nonce}:${signature}`;
33
+ }
34
+ async function bitsoRequest(method, path, body) {
35
+ const bodyStr = body ? JSON.stringify(body) : undefined;
36
+ const res = await fetch(`${BASE_URL}${path}`, {
37
+ method,
38
+ headers: {
39
+ "Content-Type": "application/json",
40
+ "Authorization": generateAuthHeader(method, `/v3${path}`, bodyStr),
41
+ },
42
+ body: bodyStr,
43
+ });
44
+ if (!res.ok) {
45
+ const err = await res.text();
46
+ throw new Error(`Bitso API ${res.status}: ${err}`);
47
+ }
48
+ return res.json();
49
+ }
50
+ const server = new Server({ name: "mcp-bitso", version: "0.1.0" }, { capabilities: { tools: {} } });
51
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
52
+ tools: [
53
+ {
54
+ name: "get_ticker",
55
+ description: "Get ticker data for a trading pair (price, volume, VWAP, etc.)",
56
+ inputSchema: {
57
+ type: "object",
58
+ properties: {
59
+ book: { type: "string", description: "Order book symbol (e.g. btc_mxn, eth_mxn, usdc_mxn)" },
60
+ },
61
+ required: ["book"],
62
+ },
63
+ },
64
+ {
65
+ name: "list_orderbook",
66
+ description: "Get order book (bids and asks) for a trading pair",
67
+ inputSchema: {
68
+ type: "object",
69
+ properties: {
70
+ book: { type: "string", description: "Order book symbol (e.g. btc_mxn)" },
71
+ aggregate: { type: "boolean", description: "Aggregate orders at same price level (default true)" },
72
+ },
73
+ required: ["book"],
74
+ },
75
+ },
76
+ {
77
+ name: "create_order",
78
+ description: "Create a buy or sell order",
79
+ inputSchema: {
80
+ type: "object",
81
+ properties: {
82
+ book: { type: "string", description: "Order book symbol (e.g. btc_mxn)" },
83
+ side: { type: "string", enum: ["buy", "sell"], description: "Order side" },
84
+ type: { type: "string", enum: ["limit", "market"], description: "Order type" },
85
+ major: { type: "string", description: "Amount of major currency (e.g. BTC quantity)" },
86
+ minor: { type: "string", description: "Amount of minor currency (e.g. MXN amount)" },
87
+ price: { type: "string", description: "Limit price (required for limit orders)" },
88
+ },
89
+ required: ["book", "side", "type"],
90
+ },
91
+ },
92
+ {
93
+ name: "get_order",
94
+ description: "Get order details by ID",
95
+ inputSchema: {
96
+ type: "object",
97
+ properties: {
98
+ oid: { type: "string", description: "Order ID" },
99
+ },
100
+ required: ["oid"],
101
+ },
102
+ },
103
+ {
104
+ name: "cancel_order",
105
+ description: "Cancel an open order",
106
+ inputSchema: {
107
+ type: "object",
108
+ properties: {
109
+ oid: { type: "string", description: "Order ID to cancel" },
110
+ },
111
+ required: ["oid"],
112
+ },
113
+ },
114
+ {
115
+ name: "list_orders",
116
+ description: "List orders with optional filters",
117
+ inputSchema: {
118
+ type: "object",
119
+ properties: {
120
+ book: { type: "string", description: "Filter by order book symbol" },
121
+ status: { type: "string", enum: ["open", "partially_filled", "completed", "cancelled"], description: "Filter by status" },
122
+ limit: { type: "number", description: "Number of results (default 25, max 100)" },
123
+ marker: { type: "string", description: "Pagination marker" },
124
+ sort: { type: "string", enum: ["asc", "desc"], description: "Sort direction" },
125
+ },
126
+ },
127
+ },
128
+ {
129
+ name: "get_balances",
130
+ description: "Get account balances for all assets",
131
+ inputSchema: { type: "object", properties: {} },
132
+ },
133
+ {
134
+ name: "list_trades",
135
+ description: "List executed trades for an order book",
136
+ inputSchema: {
137
+ type: "object",
138
+ properties: {
139
+ book: { type: "string", description: "Order book symbol (e.g. btc_mxn)" },
140
+ limit: { type: "number", description: "Number of results (default 25, max 100)" },
141
+ marker: { type: "string", description: "Pagination marker" },
142
+ sort: { type: "string", enum: ["asc", "desc"], description: "Sort direction" },
143
+ },
144
+ required: ["book"],
145
+ },
146
+ },
147
+ {
148
+ name: "list_funding_sources",
149
+ description: "List available funding sources (bank accounts, etc.)",
150
+ inputSchema: { type: "object", properties: {} },
151
+ },
152
+ {
153
+ name: "create_withdrawal",
154
+ description: "Create a withdrawal request (crypto or fiat)",
155
+ inputSchema: {
156
+ type: "object",
157
+ properties: {
158
+ currency: { type: "string", description: "Currency to withdraw (e.g. btc, eth, mxn)" },
159
+ amount: { type: "string", description: "Amount to withdraw" },
160
+ address: { type: "string", description: "Destination address (for crypto)" },
161
+ destination_tag: { type: "string", description: "Destination tag (for XRP, etc.)" },
162
+ network: { type: "string", description: "Blockchain network" },
163
+ },
164
+ required: ["currency", "amount"],
165
+ },
166
+ },
167
+ ],
168
+ }));
169
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
170
+ const { name, arguments: args } = request.params;
171
+ try {
172
+ switch (name) {
173
+ case "get_ticker":
174
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/ticker?book=${args?.book}`), null, 2) }] };
175
+ case "list_orderbook": {
176
+ const params = new URLSearchParams();
177
+ params.set("book", String(args?.book));
178
+ if (args?.aggregate !== undefined)
179
+ params.set("aggregate", String(args.aggregate));
180
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/order_book?${params}`), null, 2) }] };
181
+ }
182
+ case "create_order":
183
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("POST", "/orders", args), null, 2) }] };
184
+ case "get_order":
185
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/orders/${args?.oid}`), null, 2) }] };
186
+ case "cancel_order":
187
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("DELETE", `/orders/${args?.oid}`), null, 2) }] };
188
+ case "list_orders": {
189
+ const params = new URLSearchParams();
190
+ if (args?.book)
191
+ params.set("book", String(args.book));
192
+ if (args?.status)
193
+ params.set("status", String(args.status));
194
+ if (args?.limit)
195
+ params.set("limit", String(args.limit));
196
+ if (args?.marker)
197
+ params.set("marker", String(args.marker));
198
+ if (args?.sort)
199
+ params.set("sort", String(args.sort));
200
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/open_orders?${params}`), null, 2) }] };
201
+ }
202
+ case "get_balances":
203
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", "/balance"), null, 2) }] };
204
+ case "list_trades": {
205
+ const params = new URLSearchParams();
206
+ params.set("book", String(args?.book));
207
+ if (args?.limit)
208
+ params.set("limit", String(args.limit));
209
+ if (args?.marker)
210
+ params.set("marker", String(args.marker));
211
+ if (args?.sort)
212
+ params.set("sort", String(args.sort));
213
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/user_trades?${params}`), null, 2) }] };
214
+ }
215
+ case "list_funding_sources":
216
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", "/funding_destination"), null, 2) }] };
217
+ case "create_withdrawal":
218
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("POST", "/withdrawals", args), null, 2) }] };
219
+ default:
220
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
221
+ }
222
+ }
223
+ catch (err) {
224
+ return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
225
+ }
226
+ });
227
+ async function main() {
228
+ if (!API_KEY) {
229
+ console.error("BITSO_API_KEY environment variable is required");
230
+ process.exit(1);
231
+ }
232
+ if (!API_SECRET) {
233
+ console.error("BITSO_API_SECRET environment variable is required");
234
+ process.exit(1);
235
+ }
236
+ const transport = new StdioServerTransport();
237
+ await server.connect(transport);
238
+ }
239
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@codespar/mcp-bitso",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Bitso — Latin American crypto exchange, trading, funding, withdrawals",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "bin": {
8
+ "mcp-bitso": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/index.js"
13
+ },
14
+ "dependencies": {
15
+ "@modelcontextprotocol/sdk": "^1.0.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^22.0.0",
19
+ "typescript": "^5.8.0"
20
+ },
21
+ "license": "MIT",
22
+ "keywords": [
23
+ "mcp",
24
+ "bitso",
25
+ "crypto",
26
+ "exchange",
27
+ "trading",
28
+ "latam"
29
+ ]
30
+ }
package/src/index.ts ADDED
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MCP Server for Bitso — Latin American cryptocurrency exchange.
5
+ *
6
+ * Tools:
7
+ * - get_ticker: Get ticker data for a trading pair
8
+ * - list_orderbook: Get order book for a trading pair
9
+ * - create_order: Create a buy or sell order
10
+ * - get_order: Get order details by ID
11
+ * - cancel_order: Cancel an open order
12
+ * - list_orders: List orders with filters
13
+ * - get_balances: Get account balances
14
+ * - list_trades: List executed trades
15
+ * - list_funding_sources: List available funding sources
16
+ * - create_withdrawal: Create a withdrawal request
17
+ *
18
+ * Environment:
19
+ * BITSO_API_KEY — API key from https://bitso.com/
20
+ * BITSO_API_SECRET — API secret for HMAC signature
21
+ */
22
+
23
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
24
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
25
+ import {
26
+ CallToolRequestSchema,
27
+ ListToolsRequestSchema,
28
+ } from "@modelcontextprotocol/sdk/types.js";
29
+ import * as crypto from "node:crypto";
30
+
31
+ const API_KEY = process.env.BITSO_API_KEY || "";
32
+ const API_SECRET = process.env.BITSO_API_SECRET || "";
33
+ const BASE_URL = "https://api.bitso.com/v3";
34
+
35
+ function generateAuthHeader(method: string, path: string, body?: string): string {
36
+ const nonce = Date.now().toString();
37
+ const payload = nonce + method.toUpperCase() + path + (body || "");
38
+ const signature = crypto.createHmac("sha256", API_SECRET).update(payload).digest("hex");
39
+ return `Bitso ${API_KEY}:${nonce}:${signature}`;
40
+ }
41
+
42
+ async function bitsoRequest(method: string, path: string, body?: unknown): Promise<unknown> {
43
+ const bodyStr = body ? JSON.stringify(body) : undefined;
44
+ const res = await fetch(`${BASE_URL}${path}`, {
45
+ method,
46
+ headers: {
47
+ "Content-Type": "application/json",
48
+ "Authorization": generateAuthHeader(method, `/v3${path}`, bodyStr),
49
+ },
50
+ body: bodyStr,
51
+ });
52
+ if (!res.ok) {
53
+ const err = await res.text();
54
+ throw new Error(`Bitso API ${res.status}: ${err}`);
55
+ }
56
+ return res.json();
57
+ }
58
+
59
+ const server = new Server(
60
+ { name: "mcp-bitso", version: "0.1.0" },
61
+ { capabilities: { tools: {} } }
62
+ );
63
+
64
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
65
+ tools: [
66
+ {
67
+ name: "get_ticker",
68
+ description: "Get ticker data for a trading pair (price, volume, VWAP, etc.)",
69
+ inputSchema: {
70
+ type: "object",
71
+ properties: {
72
+ book: { type: "string", description: "Order book symbol (e.g. btc_mxn, eth_mxn, usdc_mxn)" },
73
+ },
74
+ required: ["book"],
75
+ },
76
+ },
77
+ {
78
+ name: "list_orderbook",
79
+ description: "Get order book (bids and asks) for a trading pair",
80
+ inputSchema: {
81
+ type: "object",
82
+ properties: {
83
+ book: { type: "string", description: "Order book symbol (e.g. btc_mxn)" },
84
+ aggregate: { type: "boolean", description: "Aggregate orders at same price level (default true)" },
85
+ },
86
+ required: ["book"],
87
+ },
88
+ },
89
+ {
90
+ name: "create_order",
91
+ description: "Create a buy or sell order",
92
+ inputSchema: {
93
+ type: "object",
94
+ properties: {
95
+ book: { type: "string", description: "Order book symbol (e.g. btc_mxn)" },
96
+ side: { type: "string", enum: ["buy", "sell"], description: "Order side" },
97
+ type: { type: "string", enum: ["limit", "market"], description: "Order type" },
98
+ major: { type: "string", description: "Amount of major currency (e.g. BTC quantity)" },
99
+ minor: { type: "string", description: "Amount of minor currency (e.g. MXN amount)" },
100
+ price: { type: "string", description: "Limit price (required for limit orders)" },
101
+ },
102
+ required: ["book", "side", "type"],
103
+ },
104
+ },
105
+ {
106
+ name: "get_order",
107
+ description: "Get order details by ID",
108
+ inputSchema: {
109
+ type: "object",
110
+ properties: {
111
+ oid: { type: "string", description: "Order ID" },
112
+ },
113
+ required: ["oid"],
114
+ },
115
+ },
116
+ {
117
+ name: "cancel_order",
118
+ description: "Cancel an open order",
119
+ inputSchema: {
120
+ type: "object",
121
+ properties: {
122
+ oid: { type: "string", description: "Order ID to cancel" },
123
+ },
124
+ required: ["oid"],
125
+ },
126
+ },
127
+ {
128
+ name: "list_orders",
129
+ description: "List orders with optional filters",
130
+ inputSchema: {
131
+ type: "object",
132
+ properties: {
133
+ book: { type: "string", description: "Filter by order book symbol" },
134
+ status: { type: "string", enum: ["open", "partially_filled", "completed", "cancelled"], description: "Filter by status" },
135
+ limit: { type: "number", description: "Number of results (default 25, max 100)" },
136
+ marker: { type: "string", description: "Pagination marker" },
137
+ sort: { type: "string", enum: ["asc", "desc"], description: "Sort direction" },
138
+ },
139
+ },
140
+ },
141
+ {
142
+ name: "get_balances",
143
+ description: "Get account balances for all assets",
144
+ inputSchema: { type: "object", properties: {} },
145
+ },
146
+ {
147
+ name: "list_trades",
148
+ description: "List executed trades for an order book",
149
+ inputSchema: {
150
+ type: "object",
151
+ properties: {
152
+ book: { type: "string", description: "Order book symbol (e.g. btc_mxn)" },
153
+ limit: { type: "number", description: "Number of results (default 25, max 100)" },
154
+ marker: { type: "string", description: "Pagination marker" },
155
+ sort: { type: "string", enum: ["asc", "desc"], description: "Sort direction" },
156
+ },
157
+ required: ["book"],
158
+ },
159
+ },
160
+ {
161
+ name: "list_funding_sources",
162
+ description: "List available funding sources (bank accounts, etc.)",
163
+ inputSchema: { type: "object", properties: {} },
164
+ },
165
+ {
166
+ name: "create_withdrawal",
167
+ description: "Create a withdrawal request (crypto or fiat)",
168
+ inputSchema: {
169
+ type: "object",
170
+ properties: {
171
+ currency: { type: "string", description: "Currency to withdraw (e.g. btc, eth, mxn)" },
172
+ amount: { type: "string", description: "Amount to withdraw" },
173
+ address: { type: "string", description: "Destination address (for crypto)" },
174
+ destination_tag: { type: "string", description: "Destination tag (for XRP, etc.)" },
175
+ network: { type: "string", description: "Blockchain network" },
176
+ },
177
+ required: ["currency", "amount"],
178
+ },
179
+ },
180
+ ],
181
+ }));
182
+
183
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
184
+ const { name, arguments: args } = request.params;
185
+
186
+ try {
187
+ switch (name) {
188
+ case "get_ticker":
189
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/ticker?book=${args?.book}`), null, 2) }] };
190
+ case "list_orderbook": {
191
+ const params = new URLSearchParams();
192
+ params.set("book", String(args?.book));
193
+ if (args?.aggregate !== undefined) params.set("aggregate", String(args.aggregate));
194
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/order_book?${params}`), null, 2) }] };
195
+ }
196
+ case "create_order":
197
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("POST", "/orders", args), null, 2) }] };
198
+ case "get_order":
199
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/orders/${args?.oid}`), null, 2) }] };
200
+ case "cancel_order":
201
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("DELETE", `/orders/${args?.oid}`), null, 2) }] };
202
+ case "list_orders": {
203
+ const params = new URLSearchParams();
204
+ if (args?.book) params.set("book", String(args.book));
205
+ if (args?.status) params.set("status", String(args.status));
206
+ if (args?.limit) params.set("limit", String(args.limit));
207
+ if (args?.marker) params.set("marker", String(args.marker));
208
+ if (args?.sort) params.set("sort", String(args.sort));
209
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/open_orders?${params}`), null, 2) }] };
210
+ }
211
+ case "get_balances":
212
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", "/balance"), null, 2) }] };
213
+ case "list_trades": {
214
+ const params = new URLSearchParams();
215
+ params.set("book", String(args?.book));
216
+ if (args?.limit) params.set("limit", String(args.limit));
217
+ if (args?.marker) params.set("marker", String(args.marker));
218
+ if (args?.sort) params.set("sort", String(args.sort));
219
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", `/user_trades?${params}`), null, 2) }] };
220
+ }
221
+ case "list_funding_sources":
222
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("GET", "/funding_destination"), null, 2) }] };
223
+ case "create_withdrawal":
224
+ return { content: [{ type: "text", text: JSON.stringify(await bitsoRequest("POST", "/withdrawals", args), null, 2) }] };
225
+ default:
226
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
227
+ }
228
+ } catch (err) {
229
+ return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
230
+ }
231
+ });
232
+
233
+ async function main() {
234
+ if (!API_KEY) {
235
+ console.error("BITSO_API_KEY environment variable is required");
236
+ process.exit(1);
237
+ }
238
+ if (!API_SECRET) {
239
+ console.error("BITSO_API_SECRET environment variable is required");
240
+ process.exit(1);
241
+ }
242
+ const transport = new StdioServerTransport();
243
+ await server.connect(transport);
244
+ }
245
+
246
+ main().catch(console.error);
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "esModuleInterop": true,
11
+ "declaration": true
12
+ },
13
+ "include": ["src"]
14
+ }