#
tokens: 18604/50000 19/19 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .dockerignore
├── .gitignore
├── .npmrc
├── Dockerfile
├── package-lock.json
├── package.json
├── pnpm-lock.yaml
├── README_CN.md
├── README.md
├── smithery.yaml
├── src
│   ├── index.ts
│   ├── models
│   │   └── db.ts
│   ├── services
│   │   ├── binance.ts
│   │   ├── binanceFutures.ts
│   │   ├── keystore.ts
│   │   └── tools.ts
│   └── types
│       ├── binance-connector.d.ts
│       ├── binance.ts
│       ├── errors.ts
│       └── futures.ts
├── start-bn-service.sh
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
1 | node_modules/
2 | build/
3 | *.log
4 | .env*
5 | data/*
6 | .vscode/*
7 | .env
```

--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------

```
1 | node_modules
2 | npm-debug.log
3 | build
4 | .env
5 | .git
6 | .gitignore
7 | README.md
8 | .DS_Store 
```

--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------

```
1 | enable-pre-post-scripts=true
2 | unsafe-perm=true
3 | node-linker=hoisted
4 | ignore-scripts=false
5 | public-hoist-pattern[]=* 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # mcp-server-cex-bn
  2 | 
  3 | [![smithery badge](https://smithery.ai/badge/mcp-server-cex-bn)](https://smithery.ai/server/mcp-server-cex-bn)
  4 | 
  5 | This MCP Server provides comprehensive integration with Binance's spot and futures trading operations.
  6 | 
  7 | [中文说明](README_CN.md)
  8 | 
  9 | ## Features
 10 | 
 11 | ### Spot Trading Operations
 12 | - Execute spot trading operations (LIMIT/MARKET orders)
 13 | - Monitor account balances
 14 | - Track and manage open orders
 15 | - Cancel existing orders
 16 | 
 17 | ### Futures Trading Operations
 18 | - Create various types of futures orders (LIMIT, MARKET, STOP, TAKE_PROFIT, etc.)
 19 | - Manage leverage settings (1-125x)
 20 | - Monitor futures positions and account information
 21 | - Track funding rates
 22 | - Support for both one-way and hedge mode positions
 23 | - Advanced order types including trailing stops and reduce-only orders
 24 | 
 25 | ### Tools
 26 | 
 27 | #### API Configuration
 28 | 
 29 | ##### `configure_api_keys`
 30 | Securely store your Binance API credentials:
 31 | ```typescript
 32 | await configureBinanceApiKeys({
 33 |   apiKey: 'your-api-key',
 34 |   apiSecret: 'your-api-secret'
 35 | });
 36 | ```
 37 | 
 38 | #### Spot Trading Tools
 39 | 
 40 | ##### `create_spot_order`
 41 | Create LIMIT or MARKET orders:
 42 | ```typescript
 43 | // LIMIT order
 44 | await createSpotOrder({
 45 |   symbol: 'BTCUSDT',
 46 |   side: 'BUY',
 47 |   type: 'LIMIT',
 48 |   quantity: '0.001',
 49 |   price: '40000'
 50 | });
 51 | 
 52 | // MARKET order
 53 | await createSpotOrder({
 54 |   symbol: 'BTCUSDT',
 55 |   side: 'BUY',
 56 |   type: 'MARKET',
 57 |   quantity: '0.001'
 58 | });
 59 | ```
 60 | 
 61 | ##### `cancel_order`
 62 | Cancel an existing order:
 63 | ```typescript
 64 | await cancelOrder({
 65 |   symbol: 'BTCUSDT',
 66 |   orderId: '12345678'
 67 | });
 68 | ```
 69 | 
 70 | ##### `get_balances`
 71 | Check your account balances:
 72 | ```typescript
 73 | const balances = await getBalances();
 74 | // Returns: { BTC: '0.1', USDT: '1000', ... }
 75 | ```
 76 | 
 77 | ##### `get_open_orders`
 78 | List all open orders:
 79 | ```typescript
 80 | const orders = await getOpenOrders({
 81 |   symbol: 'BTCUSDT' // Optional: specify symbol
 82 | });
 83 | ```
 84 | 
 85 | #### Futures Trading Tools
 86 | 
 87 | ##### `create_futures_order`
 88 | Create various types of futures orders:
 89 | ```typescript
 90 | // LIMIT order
 91 | await createFuturesOrder({
 92 |   symbol: 'BTCUSDT',
 93 |   side: 'BUY',
 94 |   type: 'LIMIT',
 95 |   quantity: '0.001',
 96 |   price: '40000',
 97 |   timeInForce: 'GTC'
 98 | });
 99 | 
100 | // STOP MARKET order
101 | await createFuturesOrder({
102 |   symbol: 'BTCUSDT',
103 |   side: 'SELL',
104 |   type: 'STOP_MARKET',
105 |   quantity: '0.001',
106 |   stopPrice: '38000'
107 | });
108 | 
109 | // TRAILING STOP order
110 | await createFuturesOrder({
111 |   symbol: 'BTCUSDT',
112 |   side: 'SELL',
113 |   type: 'TRAILING_STOP_MARKET',
114 |   quantity: '0.001',
115 |   callbackRate: '1.0' // 1% callback rate
116 | });
117 | ```
118 | 
119 | ##### `set_futures_leverage`
120 | Adjust leverage for a trading pair:
121 | ```typescript
122 | await setFuturesLeverage({
123 |   symbol: 'BTCUSDT',
124 |   leverage: 10  // 1-125x
125 | });
126 | ```
127 | 
128 | ##### `get_futures_positions`
129 | Get all open futures positions:
130 | ```typescript
131 | const positions = await getFuturesPositions();
132 | ```
133 | 
134 | ##### `get_futures_account`
135 | Get detailed futures account information:
136 | ```typescript
137 | const account = await getFuturesAccount();
138 | ```
139 | 
140 | ##### `get_funding_rate`
141 | Get funding rate for a futures symbol:
142 | ```typescript
143 | const fundingRate = await getFundingRate({
144 |   symbol: 'BTCUSDT'
145 | });
146 | ```
147 | 
148 | ##### `cancel_futures_order`
149 | Cancel an existing futures order:
150 | ```typescript
151 | await cancelFuturesOrder({
152 |   symbol: 'BTCUSDT',
153 |   orderId: '12345678'
154 | });
155 | ```
156 | 
157 | ## Futures Trading Details
158 | 
159 | ### Position Modes
160 | - One-way Mode: Single position per symbol
161 |   * Default mode, simpler position management
162 |   * Total position size is the sum of all orders
163 | - Hedge Mode: Separate long and short positions
164 |   * Allows holding both long and short positions simultaneously
165 |   * Each position has independent margin requirements
166 | 
167 | ### Margin Types
168 | - Isolated Margin: Fixed margin per position
169 |   * Risk is limited to the allocated margin
170 |   * Each position has its own leverage setting
171 | - Cross Margin: Shared margin across positions
172 |   * Higher capital efficiency
173 |   * Shared risk across all positions
174 | 
175 | ### Funding Rate
176 | Perpetual futures contracts use funding rates to keep futures prices aligned with spot prices:
177 | - Positive rate: Longs pay shorts
178 | - Negative rate: Shorts pay longs
179 | - Payments occur every 8 hours
180 | 
181 | ## Security Considerations
182 | 
183 | ### Spot Trading Security
184 | - Never commit API keys to version control
185 | - Use environment variables or secure key storage
186 | - Restrict API key permissions to only required operations
187 | - Regularly rotate your API keys
188 | 
189 | ### Futures Trading Security
190 | - Set appropriate leverage limits based on risk tolerance
191 | - Always use stop-loss orders to limit potential losses
192 | - Monitor liquidation prices carefully
193 | - Regularly check position risks and margin ratios
194 | - Consider using reduce-only orders for risk management
195 | - Be cautious with cross-margin due to shared risk
196 | 
197 | ## Rate Limits
198 | 
199 | - Respect Binance API rate limits
200 | - Default rate limits:
201 |   - 1200 requests per minute for order operations
202 |   - 100 requests per second for market data
203 | - Implement proper error handling for rate limit errors
204 | 
205 | ## Error Handling
206 | 
207 | ### Common Error Scenarios
208 | - Invalid API credentials
209 | - Insufficient balance or margin
210 | - Invalid order parameters
211 | - Rate limit exceeded
212 | - Network connectivity issues
213 | 
214 | ### Futures-Specific Errors
215 | - InsufficientMarginError: Not enough margin for operation
216 | - InvalidPositionModeError: Wrong position mode setting
217 | - OrderValidationError: Invalid futures order parameters
218 | 
219 | Example error handling:
220 | ```typescript
221 | try {
222 |   await createFuturesOrder({
223 |     symbol: 'BTCUSDT',
224 |     side: 'BUY',
225 |     type: 'LIMIT',
226 |     quantity: '0.001',
227 |     price: '40000',
228 |     timeInForce: 'GTC'
229 |   });
230 | } catch (error) {
231 |   if (error instanceof InsufficientMarginError) {
232 |     console.error('Insufficient margin available');
233 |   } else if (error instanceof InvalidPositionModeError) {
234 |     console.error('Invalid position mode');
235 |   } else if (error instanceof OrderValidationError) {
236 |     console.error('Invalid order parameters');
237 |   }
238 | }
239 | ```
240 | 
241 | ## Project Structure
242 | 
243 | ```
244 | .
245 | ├── src/
246 | │   ├── index.ts                 # Server entry point
247 | │   ├── services/
248 | │   │   ├── binance.ts          # Binance API integration
249 | │   │   ├── keystore.ts         # API key management
250 | │   │   └── tools.ts            # Trading tools implementation
251 | │   └── types/
252 | │       ├── binance.ts          # Binance types
253 | │       └── binance-connector.d.ts  # API client types
254 | ├── README.md
255 | ├── README_CN.md
256 | ├── package.json
257 | ├── pnpm-lock.yaml
258 | └── tsconfig.json
259 | ```
260 | 
261 | ## Development
262 | 
263 | 1. Set up environment variables:
264 | 
265 | create `.env` file in the root directory, and set your Binance API credentials:
266 | 
267 | ```txt
268 | BINANCE_API_KEY=your_api_key_here
269 | BINANCE_API_SECRET=your_secret_key_here
270 | ```
271 | 
272 | 2. Install dependencies:
273 | 
274 | ```bash
275 | pnpm install
276 | ```
277 | 
278 | Build the server:
279 | 
280 | ```bash
281 | pnpm build
282 | ```
283 | 
284 | For development with auto-rebuild:
285 | 
286 | ```bash
287 | pnpm watch
288 | ```
289 | 
290 | ## Installation
291 | 
292 | ### Installing via Smithery
293 | 
294 | To install Binance Trading Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/mcp-server-cex-bn):
295 | 
296 | ```bash
297 | npx -y @smithery/cli install mcp-server-cex-bn --client claude
298 | ```
299 | 
300 | ### Installing manually
301 | 1. Clone the repository
302 | 2. Install dependencies:
303 | ```bash
304 | pnpm install
305 | ```
306 | 3. Configure your Binance API credentials in `.env`
307 | 4. Build and start the server:
308 | ```bash
309 | pnpm build
310 | pnpm start
311 | ```
312 | 
313 | ### Debugging
314 | 
315 | Since MCP servers communicate over stdio, debugging can be challenging. We recommend using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector), which is available as a package script:
316 | 
317 | ```bash
318 | pnpm inspector
319 | ```
320 | 
321 | The Inspector will provide a URL to access debugging tools in your browser.
322 | 
323 | 
324 | # mcp-server-bn
325 | 
```

--------------------------------------------------------------------------------
/start-bn-service.sh:
--------------------------------------------------------------------------------

```bash
1 | #!/bin/bash
2 | cd "$(dirname "$0")"
3 | export BINANCE_API_KEY="rLV9ffU8oyqanh5znqit08j8CnILLvDCkRgcxdx2ePdVBxmxSYqgvSNeybyx2mtL"
4 | export BINANCE_API_SECRET="ukawP66HgMDvLnSJOYAk7qkJEbdIvlcDwQuc2WxoD7E0FZJ5TupKhP4WsCbAeECd"
5 | node build/index.js
6 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "outDir": "./build",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/src/models/db.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import sqlite3 from "sqlite3";
 2 | 
 3 | export function getDb(): sqlite3.Database {
 4 |   const dbName = process.env.BINANCE_DB_PATH || "";
 5 |   if (!dbName) {
 6 |     throw new Error("BINANCE_DB_PATH is not set");
 7 |   }
 8 | 
 9 |   const db = new sqlite3.Database(dbName, (err) => {
10 |     if (err) {
11 |       console.error("binance db connect failed: ", dbName, err.message);
12 |       return;
13 |     }
14 |   });
15 | 
16 |   return db;
17 | }
18 | 
```

--------------------------------------------------------------------------------
/src/types/errors.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export class BinanceClientError extends Error {
 2 |   constructor(message: string) {
 3 |     super(message);
 4 |     this.name = 'BinanceClientError';
 5 |   }
 6 | }
 7 | 
 8 | export class ApiKeyError extends Error {
 9 |   constructor(message: string) {
10 |     super(message);
11 |     this.name = 'ApiKeyError';
12 |   }
13 | }
14 | 
15 | export class OrderValidationError extends Error {
16 |   constructor(message: string) {
17 |     super(message);
18 |     this.name = 'OrderValidationError';
19 |   }
20 | }
21 | 
22 | export class InsufficientMarginError extends Error {
23 |   constructor(message: string) {
24 |     super(message);
25 |     this.name = 'InsufficientMarginError';
26 |   }
27 | }
28 | 
29 | export class InvalidPositionModeError extends Error {
30 |   constructor(message: string) {
31 |     super(message);
32 |     this.name = 'InvalidPositionModeError';
33 |   }
34 | }
35 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml
 2 | 
 3 | startCommand:
 4 |   type: stdio
 5 |   configSchema:
 6 |     # JSON Schema defining the configuration options for the MCP.
 7 |     type: object
 8 |     required:
 9 |       - binanceApiKey
10 |       - binanceApiSecret
11 |     properties:
12 |       binanceApiKey:
13 |         type: string
14 |         description: The API key for accessing the Binance API.
15 |       binanceApiSecret:
16 |         type: string
17 |         description: The secret key for accessing the Binance API.
18 |   commandFunction:
19 |     # A function that produces the CLI command to start the MCP on stdio.
20 |     |-
21 |     (config) => ({ command: 'pnpm', args: ['start'], env: { BINANCE_API_KEY: config.binanceApiKey, BINANCE_API_SECRET: config.binanceApiSecret } })
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # Build stage
 2 | FROM node:20-alpine AS builder
 3 | 
 4 | # Set the working directory
 5 | WORKDIR /app
 6 | 
 7 | # Install build dependencies
 8 | RUN apk add --no-cache python3 make g++ git
 9 | 
10 | # Install pnpm
11 | RUN npm install -g pnpm@latest typescript
12 | 
13 | # Copy package files
14 | COPY package.json pnpm-lock.yaml ./
15 | 
16 | # Install dependencies
17 | RUN pnpm install --frozen-lockfile --ignore-scripts
18 | 
19 | # Copy source files
20 | COPY . .
21 | 
22 | # Build TypeScript
23 | RUN pnpm exec tsc
24 | 
25 | # Production stage
26 | FROM node:20-alpine
27 | 
28 | WORKDIR /app
29 | 
30 | # Install runtime dependencies
31 | RUN apk add --no-cache python3 make g++
32 | 
33 | # Copy package files and install production dependencies
34 | COPY package.json pnpm-lock.yaml ./
35 | RUN npm install -g pnpm@latest && \
36 |     pnpm install --prod --frozen-lockfile --ignore-scripts
37 | 
38 | # Copy built files
39 | COPY --from=builder /app/build ./build
40 | 
41 | # Set environment variables
42 | ENV NODE_ENV=production
43 | 
44 | # Start the application
45 | CMD ["node", "build/index.js"]
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "@kydfeng/mcp-server-cex-bn",
 3 |   "version": "0.1.2",
 4 |   "description": "MCP Server for Binance Spot Trading",
 5 |   "type": "module",
 6 |   "bin": {
 7 |     "mcp-server-cex-bn": "./build/index.js"
 8 |   },
 9 |   "files": [
10 |     "build"
11 |   ],
12 |   "scripts": {
13 |     "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
14 |     "prepare": "npm run build",
15 |     "watch": "tsc --watch",
16 |     "inspector": "npx @modelcontextprotocol/inspector build/index.js"
17 |   },
18 |   "dependencies": {
19 |     "@binance/connector": "^3.6.1",
20 |     "@modelcontextprotocol/inspector": "^0.4.1",
21 |     "@modelcontextprotocol/sdk": "1.6.0",
22 |     "@types/keytar": "^4.4.2",
23 |     "dotenv": "^16.4.6",
24 |     "keytar": "^7.9.0",
25 |     "node-binance-api": "^0.13.1",
26 |     "sqlite3": "^5.1.7"
27 |   },
28 |   "devDependencies": {
29 |     "@types/node": "^20.17.9",
30 |     "typescript": "^5.3.3"
31 |   },
32 |   "keywords": [
33 |     "mcp",
34 |     "binance",
35 |     "trading",
36 |     "crypto",
37 |     "model-context-protocol"
38 |   ],
39 |   "author": "kydfeng",
40 |   "license": "MIT",
41 |   "repository": {
42 |     "type": "git",
43 |     "url": "https://github.com/kydfeng/mcp-server-bn.git"
44 |   }
45 | }
46 | 
```

--------------------------------------------------------------------------------
/src/types/binance-connector.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | declare module '@binance/connector' {
 2 |   export class Spot {
 3 |     constructor(apiKey: string, apiSecret: string);
 4 |     
 5 |     usdmFutures: {
 6 |       ping(): Promise<any>;
 7 |       account(): Promise<any>;
 8 |       positionRisk(): Promise<any>;
 9 |       openOrders(params?: { symbol?: string }): Promise<any>;
10 |       newOrder(params: any): Promise<any>;
11 |       cancelOrder(params: any): Promise<any>;
12 |       leverage(params: any): Promise<any>;
13 |       fundingRate(params: any): Promise<any>;
14 |     };
15 | 
16 |     newOrder(params: {
17 |       symbol: string;
18 |       side: 'BUY' | 'SELL';
19 |       type: 'LIMIT' | 'MARKET';
20 |       quantity?: string;
21 |       price?: string;
22 |       timeInForce?: 'GTC' | 'IOC' | 'FOK';
23 |     }): Promise<{ data: any }>;
24 | 
25 |     cancelOrder(symbol: string, params: { orderId: number }): Promise<void>;
26 | 
27 |     account(): Promise<{
28 |       data: {
29 |         balances: Array<{
30 |           asset: string;
31 |           free: string;
32 |           locked: string;
33 |         }>;
34 |       };
35 |     }>;
36 | 
37 |     openOrders(params?: { symbol?: string }): Promise<{
38 |       data: Array<{
39 |         symbol: string;
40 |         orderId: number;
41 |         orderListId: number;
42 |         clientOrderId: string;
43 |         price: string;
44 |         origQty: string;
45 |         executedQty: string;
46 |         status: string;
47 |         timeInForce: string;
48 |         type: string;
49 |         side: string;
50 |       }>;
51 |     }>;
52 |   }
53 | }
54 | 
```

--------------------------------------------------------------------------------
/src/services/keystore.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import dotenv from 'dotenv';
 2 | import * as fs from 'fs';
 3 | import * as path from 'path';
 4 | 
 5 | // Load environment variables
 6 | dotenv.config();
 7 | 
 8 | const logFile = path.join(process.cwd(), 'logs', 'keystore.log');
 9 | 
10 | // 确保日志目录存在
11 | if (!fs.existsSync(path.dirname(logFile))) {
12 |   fs.mkdirSync(path.dirname(logFile), { recursive: true });
13 | }
14 | 
15 | function log(message: string) {
16 |   const timestamp = new Date().toISOString();
17 |   fs.appendFileSync(logFile, `${timestamp} - ${message}\n`);
18 | }
19 | 
20 | function logError(message: string, error?: unknown) {
21 |   const timestamp = new Date().toISOString();
22 |   const errorMessage = error instanceof Error ? error.message : String(error);
23 |   fs.appendFileSync(logFile, `${timestamp} - ERROR: ${message} ${error ? `- ${errorMessage}` : ''}\n`);
24 | }
25 | 
26 | export async function storeApiKeys(apiKey: string, apiSecret: string): Promise<void> {
27 |   process.env.BINANCE_API_KEY = apiKey;
28 |   process.env.BINANCE_API_SECRET = apiSecret;
29 |   log('API keys stored in environment variables');
30 | }
31 | 
32 | export async function getApiKeys(): Promise<{ apiKey: string; apiSecret: string } | null> {
33 |   const envApiKey = process.env.BINANCE_API_KEY;
34 |   const envApiSecret = process.env.BINANCE_API_SECRET;
35 | 
36 |   if (envApiKey && envApiSecret) {
37 |     log('Found API keys in environment variables');
38 |     return { apiKey: envApiKey, apiSecret: envApiSecret };
39 |   }
40 | 
41 |   log('No API keys found in environment variables');
42 |   return null;
43 | }
44 | 
45 | export async function deleteApiKeys(): Promise<void> {
46 |   delete process.env.BINANCE_API_KEY;
47 |   delete process.env.BINANCE_API_SECRET;
48 |   log('Cleared API keys from environment variables');
49 | }
50 | 
```

--------------------------------------------------------------------------------
/src/types/binance.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export interface BinanceCredentials {
 2 |   apiKey: string;
 3 |   apiSecret: string;
 4 | }
 5 | 
 6 | export interface SpotOrder {
 7 |   symbol: string;
 8 |   side: 'BUY' | 'SELL';
 9 |   type: 'LIMIT' | 'MARKET';
10 |   quantity?: string;
11 |   quoteOrderQty?: string;
12 |   price?: string;
13 |   timeInForce?: 'GTC' | 'IOC' | 'FOK';
14 | }
15 | 
16 | export interface OrderResponse {
17 |   symbol: string;
18 |   orderId: number;
19 |   orderListId: number;
20 |   clientOrderId: string;
21 |   transactTime: number;
22 |   price: string;
23 |   origQty: string;
24 |   executedQty: string;
25 |   status: string;
26 |   timeInForce: string;
27 |   type: string;
28 |   side: string;
29 | }
30 | 
31 | export interface AccountBalance {
32 |   asset: string;
33 |   free: string;
34 |   locked: string;
35 | }
36 | 
37 | export interface SymbolFilter {
38 |   filterType: string;
39 |   minPrice?: string;
40 |   maxPrice?: string;
41 |   tickSize?: string;
42 |   minQty?: string;
43 |   maxQty?: string;
44 |   stepSize?: string;
45 |   minNotional?: string;
46 |   applyToMarket?: boolean;
47 |   limit?: number;
48 |   maxNumOrders?: number;
49 |   maxNumAlgoOrders?: number;
50 | }
51 | 
52 | export interface SymbolInfo {
53 |   symbol: string;
54 |   status: string;
55 |   baseAsset: string;
56 |   baseAssetPrecision: number;
57 |   quoteAsset: string;
58 |   quotePrecision: number;
59 |   quoteAssetPrecision: number;
60 |   orderTypes: string[];
61 |   icebergAllowed: boolean;
62 |   ocoAllowed: boolean;
63 |   isSpotTradingAllowed: boolean;
64 |   isMarginTradingAllowed: boolean;
65 |   filters: SymbolFilter[];
66 |   permissions: string[];
67 | }
68 | 
69 | export interface ExchangeInfo {
70 |   timezone: string;
71 |   serverTime: number;
72 |   rateLimits: any[];
73 |   exchangeFilters: any[];
74 |   symbols: SymbolInfo[];
75 | }
76 | 
77 | export interface KlineData {
78 |   openTime: number;
79 |   open: string;
80 |   high: string;
81 |   low: string;
82 |   close: string;
83 |   volume: string;
84 |   closeTime: number;
85 |   quoteAssetVolume: string;
86 |   trades: number;
87 |   takerBuyBaseAssetVolume: string;
88 |   takerBuyQuoteAssetVolume: string;
89 | }
90 | 
```

--------------------------------------------------------------------------------
/src/types/futures.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export enum PositionSide {
  2 |   BOTH = 'BOTH',
  3 |   LONG = 'LONG',
  4 |   SHORT = 'SHORT'
  5 | }
  6 | 
  7 | export enum MarginType {
  8 |   ISOLATED = 'ISOLATED',
  9 |   CROSSED = 'CROSSED'
 10 | }
 11 | 
 12 | export enum WorkingType {
 13 |   MARK_PRICE = 'MARK_PRICE',
 14 |   CONTRACT_PRICE = 'CONTRACT_PRICE'
 15 | }
 16 | 
 17 | export enum TimeInForce {
 18 |   GTC = 'GTC',  // Good Till Cancel
 19 |   IOC = 'IOC',  // Immediate or Cancel
 20 |   FOK = 'FOK',  // Fill or Kill
 21 |   GTX = 'GTX'   // Good Till Crossing
 22 | }
 23 | 
 24 | export interface FuturesOrder {
 25 |   symbol: string;
 26 |   side: 'BUY' | 'SELL';
 27 |   positionSide?: PositionSide;
 28 |   type: 'LIMIT' | 'MARKET' | 'STOP' | 'STOP_MARKET' | 'TAKE_PROFIT' | 'TAKE_PROFIT_MARKET' | 'TRAILING_STOP_MARKET';
 29 |   quantity: string;
 30 |   price?: string;
 31 |   stopPrice?: string;
 32 |   reduceOnly?: boolean;
 33 |   workingType?: WorkingType;
 34 |   timeInForce?: TimeInForce;
 35 |   activationPrice?: string;
 36 |   callbackRate?: string;
 37 |   closePosition?: boolean;
 38 |   priceProtect?: boolean;
 39 | }
 40 | 
 41 | export interface FuturesPosition {
 42 |   symbol: string;
 43 |   positionAmt: string;
 44 |   entryPrice: string;
 45 |   markPrice: string;
 46 |   unRealizedProfit: string;
 47 |   liquidationPrice: string;
 48 |   leverage: number;
 49 |   marginType: MarginType;
 50 |   isolatedMargin: string;
 51 |   positionSide: PositionSide;
 52 |   updateTime: number;
 53 | }
 54 | 
 55 | export interface FundingRate {
 56 |   symbol: string;
 57 |   fundingRate: string;
 58 |   fundingTime: number;
 59 |   nextFundingTime: number;
 60 | }
 61 | 
 62 | export interface LeverageSettings {
 63 |   symbol: string;
 64 |   leverage: number;
 65 |   maxNotionalValue?: string;
 66 | }
 67 | 
 68 | export interface FuturesAccountBalance {
 69 |   asset: string;
 70 |   walletBalance: string;
 71 |   unrealizedProfit: string;
 72 |   marginBalance: string;
 73 |   maintMargin: string;
 74 |   initialMargin: string;
 75 |   positionInitialMargin: string;
 76 |   openOrderInitialMargin: string;
 77 |   maxWithdrawAmount: string;
 78 |   crossWalletBalance: string;
 79 |   crossUnPnl: string;
 80 |   availableBalance: string;
 81 | }
 82 | 
 83 | export interface FuturesAccountInformation {
 84 |   feeTier: number;
 85 |   canTrade: boolean;
 86 |   canDeposit: boolean;
 87 |   canWithdraw: boolean;
 88 |   updateTime: number;
 89 |   totalInitialMargin: string;
 90 |   totalMaintMargin: string;
 91 |   totalWalletBalance: string;
 92 |   totalUnrealizedProfit: string;
 93 |   totalMarginBalance: string;
 94 |   totalPositionInitialMargin: string;
 95 |   totalOpenOrderInitialMargin: string;
 96 |   totalCrossWalletBalance: string;
 97 |   totalCrossUnPnl: string;
 98 |   availableBalance: string;
 99 |   maxWithdrawAmount: string;
100 |   assets: FuturesAccountBalance[];
101 |   positions: FuturesPosition[];
102 | }
103 | 
```

--------------------------------------------------------------------------------
/src/services/binance.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { Spot } from '@binance/connector';
  2 | import { BinanceCredentials, SpotOrder, OrderResponse, AccountBalance, ExchangeInfo } from '../types/binance.js';
  3 | import { BinanceClientError, OrderValidationError } from '../types/errors.js';
  4 | import { getApiKeys } from './keystore.js';
  5 | import * as fs from 'fs';
  6 | import * as path from 'path';
  7 | 
  8 | const logFile = path.join(process.cwd(), 'logs', 'binance.log');
  9 | 
 10 | // 确保日志目录存在
 11 | if (!fs.existsSync(path.dirname(logFile))) {
 12 |   fs.mkdirSync(path.dirname(logFile), { recursive: true });
 13 | }
 14 | 
 15 | function log(message: string) {
 16 |   const timestamp = new Date().toISOString();
 17 |   fs.appendFileSync(logFile, `${timestamp} - ${message}\n`);
 18 | }
 19 | 
 20 | function logError(message: string, error?: unknown) {
 21 |   const timestamp = new Date().toISOString();
 22 |   const errorMessage = error instanceof Error ? error.message : String(error);
 23 |   fs.appendFileSync(logFile, `${timestamp} - ERROR: ${message} ${error ? `- ${errorMessage}` : ''}\n`);
 24 | }
 25 | 
 26 | let client: Spot | null = null;
 27 | 
 28 | export async function initializeBinanceClient(): Promise<boolean> {
 29 |   log('Initializing Binance spot client...');
 30 |   const credentials = await getApiKeys();
 31 |   if (!credentials) {
 32 |     log('No credentials available for Binance spot client');
 33 |     return false;
 34 |   }
 35 | 
 36 |   try {
 37 |     log('Creating Binance spot client...');
 38 |     client = new Spot(credentials.apiKey, credentials.apiSecret);
 39 |     
 40 |     // Test the connection
 41 |     log('Testing Binance spot client connection...');
 42 |     await client.account();
 43 |     log('Successfully connected to Binance spot API');
 44 |     return true;
 45 |   } catch (error) {
 46 |     logError('Failed to initialize Binance spot client:', error);
 47 |     client = null;
 48 |     return false;
 49 |   }
 50 | }
 51 | 
 52 | export async function createSpotOrder(order: SpotOrder): Promise<OrderResponse> {
 53 |   if (!client) {
 54 |     throw new BinanceClientError('Binance client not initialized');
 55 |   }
 56 | 
 57 |   try {
 58 |     log(`Creating spot order: ${JSON.stringify(order)}`);
 59 |     const params: any = {
 60 |       symbol: order.symbol,
 61 |       side: order.side,
 62 |       type: order.type,
 63 |     };
 64 | 
 65 |     // 处理标准订单参数
 66 |     if (order.quantity) params.quantity = order.quantity;
 67 |     if (order.price) params.price = order.price;
 68 |     if (order.timeInForce) params.timeInForce = order.timeInForce;
 69 |     
 70 |     // 处理报价资产数量订单参数
 71 |     if (order.quoteOrderQty) {
 72 |       params.quoteOrderQty = order.quoteOrderQty;
 73 |       log(`Using quoteOrderQty: ${order.quoteOrderQty}`);
 74 |     }
 75 | 
 76 |     if (order.type === 'LIMIT' && !order.price) {
 77 |       throw new OrderValidationError('Price is required for LIMIT orders');
 78 |     }
 79 | 
 80 |     // 对于市价单,必须提供quantity或quoteOrderQty其中之一
 81 |     if (order.type === 'MARKET' && !order.quantity && !order.quoteOrderQty) {
 82 |       throw new OrderValidationError('For MARKET orders, either quantity or quoteOrderQty must be provided');
 83 |     }
 84 | 
 85 |     log(`Sending order with params: ${JSON.stringify(params)}`);
 86 |     const response = await client.newOrder(params);
 87 |     log(`Order created successfully: ${JSON.stringify(response.data)}`);
 88 |     return response.data;
 89 |   } catch (error) {
 90 |     if (error instanceof OrderValidationError) {
 91 |       throw error;
 92 |     }
 93 |     if (error instanceof Error) {
 94 |       logError(`Failed to create spot order:`, error);
 95 |       throw new BinanceClientError(`Failed to create spot order: ${error.message}`);
 96 |     }
 97 |     logError('Failed to create spot order: Unknown error', error);
 98 |     throw new BinanceClientError('Failed to create spot order: Unknown error');
 99 |   }
100 | }
101 | 
102 | export async function cancelOrder(symbol: string, orderId: number): Promise<void> {
103 |   if (!client) {
104 |     throw new BinanceClientError('Binance client not initialized');
105 |   }
106 | 
107 |   try {
108 |     await client.cancelOrder(symbol, { orderId });
109 |   } catch (error) {
110 |     if (error instanceof Error) {
111 |       throw new BinanceClientError(`Failed to cancel order: ${error.message}`);
112 |     }
113 |     throw new BinanceClientError('Failed to cancel order: Unknown error');
114 |   }
115 | }
116 | 
117 | export async function getAccountBalances(): Promise<AccountBalance[]> {
118 |   if (!client) {
119 |     throw new BinanceClientError('Binance client not initialized');
120 |   }
121 | 
122 |   try {
123 |     const response = await client.account();
124 |     return response.data.balances;
125 |   } catch (error) {
126 |     if (error instanceof Error) {
127 |       throw new BinanceClientError(`Failed to get account balances: ${error.message}`);
128 |     }
129 |     throw new BinanceClientError('Failed to get account balances: Unknown error');
130 |   }
131 | }
132 | 
133 | export async function getOpenOrders(symbol?: string): Promise<OrderResponse[]> {
134 |   if (!client) {
135 |     throw new BinanceClientError('Binance client not initialized');
136 |   }
137 | 
138 |   try {
139 |     const params = symbol ? { symbol } : {};
140 |     const response = await client.openOrders(params);
141 |     return response.data.map(order => ({
142 |       ...order,
143 |       transactTime: Date.now()
144 |     }));
145 |   } catch (error) {
146 |     if (error instanceof Error) {
147 |       throw new BinanceClientError(`Failed to get open orders: ${error.message}`);
148 |     }
149 |     throw new BinanceClientError('Failed to get open orders: Unknown error');
150 |   }
151 | }
152 | 
153 | // 仅保留可以确认正常工作的API
154 | // 其他功能暂时移除
155 | 
```

--------------------------------------------------------------------------------
/src/services/tools.ts:
--------------------------------------------------------------------------------

```typescript
  1 | export const configureApiKeysTool = {
  2 |   name: "configure_api_keys",
  3 |   description: "Configure Binance API keys for trading",
  4 |   inputSchema: {
  5 |     type: "object",
  6 |     properties: {
  7 |       apiKey: { 
  8 |         type: "string", 
  9 |         description: "Binance API key" 
 10 |       },
 11 |       apiSecret: { 
 12 |         type: "string", 
 13 |         description: "Binance API secret" 
 14 |       }
 15 |     },
 16 |     required: ["apiKey", "apiSecret"],
 17 |   },
 18 | };
 19 | 
 20 | export const createOrderTool = {
 21 |   name: "create_spot_order",
 22 |   description: "Create a new spot order on Binance",
 23 |   inputSchema: {
 24 |     type: "object",
 25 |     properties: {
 26 |       symbol: { 
 27 |         type: "string", 
 28 |         description: "Trading pair symbol (e.g., BTCUSDT)" 
 29 |       },
 30 |       side: { 
 31 |         type: "string", 
 32 |         enum: ["BUY", "SELL"], 
 33 |         description: "Order side" 
 34 |       },
 35 |       type: { 
 36 |         type: "string", 
 37 |         enum: ["LIMIT", "MARKET"], 
 38 |         description: "Order type" 
 39 |       },
 40 |       quantity: { 
 41 |         type: "string", 
 42 |         description: "Order quantity (amount of base asset)" 
 43 |       },
 44 |       quoteOrderQty: {
 45 |         type: "string",
 46 |         description: "Quote order quantity (amount of quote asset to spend or receive, e.g. USDT)"
 47 |       },
 48 |       price: { 
 49 |         type: "string", 
 50 |         description: "Order price (required for LIMIT orders)" 
 51 |       },
 52 |       timeInForce: { 
 53 |         type: "string", 
 54 |         enum: ["GTC", "IOC", "FOK"], 
 55 |         description: "Time in force" 
 56 |       }
 57 |     },
 58 |     required: ["symbol", "side", "type"],
 59 |   },
 60 | };
 61 | 
 62 | export const cancelOrderTool = {
 63 |   name: "cancel_order",
 64 |   description: "Cancel an existing order",
 65 |   inputSchema: {
 66 |     type: "object",
 67 |     properties: {
 68 |       symbol: { 
 69 |         type: "string", 
 70 |         description: "Trading pair symbol (e.g., BTCUSDT)" 
 71 |       },
 72 |       orderId: { 
 73 |         type: "number", 
 74 |         description: "Order ID to cancel" 
 75 |       }
 76 |     },
 77 |     required: ["symbol", "orderId"],
 78 |   },
 79 | };
 80 | 
 81 | export const getBalancesTool = {
 82 |   name: "get_balances",
 83 |   description: "Get account balances",
 84 |   inputSchema: {
 85 |     type: "object",
 86 |     properties: {
 87 |       random_string: {
 88 |         type: "string",
 89 |         description: "Dummy parameter for no-parameter tools"
 90 |       }
 91 |     },
 92 |     required: ["random_string"],
 93 |   },
 94 | };
 95 | 
 96 | export const getOpenOrdersTool = {
 97 |   name: "get_open_orders",
 98 |   description: "Get open orders",
 99 |   inputSchema: {
100 |     type: "object",
101 |     properties: {
102 |       symbol: { 
103 |         type: "string",
104 |         description: "Trading pair symbol (optional)"
105 |       }
106 |     },
107 |     required: [],
108 |   },
109 | };
110 | 
111 | export const createFuturesOrderTool = {
112 |   name: "create_futures_order",
113 |   description: "Create a new futures order on Binance",
114 |   inputSchema: {
115 |     type: "object",
116 |     properties: {
117 |       symbol: { 
118 |         type: "string", 
119 |         description: "Trading pair symbol (e.g., BTCUSDT)" 
120 |       },
121 |       side: { 
122 |         type: "string", 
123 |         enum: ["BUY", "SELL"], 
124 |         description: "Order side" 
125 |       },
126 |       positionSide: {
127 |         type: "string",
128 |         enum: ["BOTH", "LONG", "SHORT"],
129 |         description: "Position side"
130 |       },
131 |       type: { 
132 |         type: "string", 
133 |         enum: ["LIMIT", "MARKET", "STOP", "STOP_MARKET", "TAKE_PROFIT", "TAKE_PROFIT_MARKET", "TRAILING_STOP_MARKET"], 
134 |         description: "Order type" 
135 |       },
136 |       quantity: { 
137 |         type: "string", 
138 |         description: "Order quantity" 
139 |       },
140 |       price: { 
141 |         type: "string", 
142 |         description: "Order price (required for LIMIT orders)" 
143 |       },
144 |       stopPrice: {
145 |         type: "string",
146 |         description: "Stop price (required for STOP/TAKE_PROFIT orders)"
147 |       },
148 |       timeInForce: { 
149 |         type: "string", 
150 |         enum: ["GTC", "IOC", "FOK", "GTX"], 
151 |         description: "Time in force" 
152 |       },
153 |       reduceOnly: {
154 |         type: "boolean",
155 |         description: "Reduce only flag"
156 |       },
157 |       closePosition: {
158 |         type: "boolean",
159 |         description: "Close position flag"
160 |       }
161 |     },
162 |     required: ["symbol", "side", "type", "quantity"],
163 |   },
164 | };
165 | 
166 | export const cancelFuturesOrderTool = {
167 |   name: "cancel_futures_order",
168 |   description: "Cancel an existing futures order",
169 |   inputSchema: {
170 |     type: "object",
171 |     properties: {
172 |       symbol: { 
173 |         type: "string", 
174 |         description: "Trading pair symbol (e.g., BTCUSDT)" 
175 |       },
176 |       orderId: { 
177 |         type: "number", 
178 |         description: "Order ID to cancel" 
179 |       }
180 |     },
181 |     required: ["symbol", "orderId"],
182 |   },
183 | };
184 | 
185 | export const getFuturesPositionsTool = {
186 |   name: "get_futures_positions",
187 |   description: "Get all futures positions",
188 |   inputSchema: {
189 |     type: "object",
190 |     properties: {},
191 |     required: [],
192 |   },
193 | };
194 | 
195 | export const setFuturesLeverageTool = {
196 |   name: "set_futures_leverage",
197 |   description: "Set leverage for a futures symbol",
198 |   inputSchema: {
199 |     type: "object",
200 |     properties: {
201 |       symbol: {
202 |         type: "string",
203 |         description: "Trading pair symbol (e.g., BTCUSDT)"
204 |       },
205 |       leverage: {
206 |         type: "number",
207 |         description: "Leverage value (1-125)"
208 |       }
209 |     },
210 |     required: ["symbol", "leverage"],
211 |   },
212 | };
213 | 
214 | export const getFuturesAccountTool = {
215 |   name: "get_futures_account",
216 |   description: "Get futures account information",
217 |   inputSchema: {
218 |     type: "object",
219 |     properties: {},
220 |     required: [],
221 |   },
222 | };
223 | 
224 | export const getFuturesOpenOrdersTool = {
225 |   name: "get_futures_open_orders",
226 |   description: "Get open futures orders",
227 |   inputSchema: {
228 |     type: "object",
229 |     properties: {
230 |       symbol: { 
231 |         type: "string",
232 |         description: "Trading pair symbol (optional)"
233 |       }
234 |     },
235 |     required: [],
236 |   },
237 | };
238 | 
239 | export const getFundingRateTool = {
240 |   name: "get_funding_rate",
241 |   description: "Get funding rate for a futures symbol",
242 |   inputSchema: {
243 |     type: "object",
244 |     properties: {
245 |       symbol: {
246 |         type: "string",
247 |         description: "Trading pair symbol (e.g., BTCUSDT)"
248 |       }
249 |     },
250 |     required: ["symbol"],
251 |   },
252 | };
253 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | 
  3 | import {
  4 |   CallToolRequestSchema,
  5 |   ListToolsRequestSchema,
  6 | } from "@modelcontextprotocol/sdk/types.js";
  7 | 
  8 | import { SpotOrder } from "./types/binance.js";
  9 | import {
 10 |   storeApiKeys,
 11 |   getApiKeys,
 12 |   deleteApiKeys,
 13 | } from "./services/keystore.js";
 14 | import {
 15 |   createSpotOrder,
 16 |   cancelOrder,
 17 |   getAccountBalances,
 18 |   getOpenOrders,
 19 | } from "./services/binance.js";
 20 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
 21 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
 22 | import dotenv from "dotenv";
 23 | import { initializeBinanceClient } from "./services/binance.js";
 24 | import {
 25 |   configureApiKeysTool,
 26 |   createOrderTool,
 27 |   cancelOrderTool,
 28 |   getBalancesTool,
 29 |   getOpenOrdersTool,
 30 |   createFuturesOrderTool,
 31 |   cancelFuturesOrderTool,
 32 |   getFuturesPositionsTool,
 33 |   setFuturesLeverageTool,
 34 |   getFuturesAccountTool,
 35 |   getFuturesOpenOrdersTool,
 36 |   getFundingRateTool,
 37 | } from "./services/tools.js";
 38 | import {
 39 |   createFuturesOrder,
 40 |   cancelFuturesOrder,
 41 |   getFuturesPositions,
 42 |   setFuturesLeverage,
 43 |   getFuturesAccountInformation as getFuturesAccount,
 44 |   getFuturesOpenOrders,
 45 |   getFundingRate,
 46 |   initializeFuturesClient,
 47 |   changePositionMode,
 48 |   changeMarginType,
 49 |   getFuturesKlines,
 50 | } from "./services/binanceFutures.js";
 51 | import { FuturesOrder, LeverageSettings, TimeInForce, PositionSide, WorkingType, MarginType } from "./types/futures.js";
 52 | import * as fs from 'fs';
 53 | import * as path from 'path';
 54 | import { z } from "zod";
 55 | 
 56 | // Load environment variables first
 57 | dotenv.config();
 58 | 
 59 | const logFile = path.join(process.cwd(), 'logs', 'server.log');
 60 | 
 61 | // 确保日志目录存在
 62 | if (!fs.existsSync(path.dirname(logFile))) {
 63 |   fs.mkdirSync(path.dirname(logFile), { recursive: true });
 64 | }
 65 | 
 66 | function log(message: string) {
 67 |   const timestamp = new Date().toISOString();
 68 |   fs.appendFileSync(logFile, `${timestamp} - ${message}\n`);
 69 | }
 70 | 
 71 | function logError(message: string, error?: unknown) {
 72 |   const timestamp = new Date().toISOString();
 73 |   const errorMessage = error instanceof Error ? error.message : String(error);
 74 |   fs.appendFileSync(logFile, `${timestamp} - ERROR: ${message} ${error ? `- ${errorMessage}` : ''}\n`);
 75 | }
 76 | 
 77 | // 创建高级McpServer实例,而不是低级Server实例
 78 | const server = new McpServer({
 79 |   name: "mcp-server-binance",
 80 |   version: "0.1.0",
 81 | });
 82 | 
 83 | // 注册工具
 84 | server.tool(
 85 |   "configure_api_keys",
 86 |   {
 87 |     apiKey: z.string().describe("Binance API key"),
 88 |     apiSecret: z.string().describe("Binance API secret")
 89 |   },
 90 |   async ({ apiKey, apiSecret }) => {
 91 |     await storeApiKeys(apiKey, apiSecret);
 92 |     const spotInitialized = await initializeBinanceClient();
 93 |     const futuresInitialized = await initializeFuturesClient();
 94 |     return {
 95 |       content: [
 96 |         {
 97 |           type: "text",
 98 |           text: spotInitialized && futuresInitialized
 99 |             ? "API keys configured successfully"
100 |             : "Failed to initialize Binance clients",
101 |         },
102 |       ],
103 |     };
104 |   }
105 | );
106 | 
107 | server.tool(
108 |   "create_spot_order",
109 |   {
110 |     symbol: z.string().describe("Trading pair symbol (e.g., BTCUSDT)"),
111 |     side: z.enum(["BUY", "SELL"]).describe("Order side"),
112 |     type: z.enum(["LIMIT", "MARKET"]).describe("Order type"),
113 |     quantity: z.string().optional().describe("Order quantity (amount of base asset)"),
114 |     quoteOrderQty: z.string().optional().describe("Quote order quantity (amount of quote asset to spend or receive, e.g. USDT)"),
115 |     price: z.string().optional().describe("Order price (required for LIMIT orders)"),
116 |     timeInForce: z.enum(["GTC", "IOC", "FOK"]).optional().describe("Time in force")
117 |   },
118 |   async (args) => {
119 |     const order: SpotOrder = {
120 |       symbol: args.symbol,
121 |       side: args.side,
122 |       type: args.type,
123 |       quantity: args.quantity,
124 |       quoteOrderQty: args.quoteOrderQty,
125 |       price: args.price,
126 |       timeInForce: args.timeInForce,
127 |     };
128 |     const response = await createSpotOrder(order);
129 |     return {
130 |       content: [
131 |         {
132 |           type: "text",
133 |           text: JSON.stringify(response),
134 |         },
135 |       ],
136 |     };
137 |   }
138 | );
139 | 
140 | server.tool(
141 |   "cancel_order",
142 |   {
143 |     symbol: z.string().describe("Trading pair symbol (e.g., BTCUSDT)"),
144 |     orderId: z.number().describe("Order ID to cancel")
145 |   },
146 |   async ({ symbol, orderId }) => {
147 |     await cancelOrder(symbol, orderId);
148 |     return {
149 |       content: [
150 |         {
151 |           type: "text",
152 |           text: "Order cancelled successfully",
153 |         },
154 |       ],
155 |     };
156 |   }
157 | );
158 | 
159 | server.tool(
160 |   "get_balances",
161 |   {},
162 |   async () => {
163 |     const balances = await getAccountBalances();
164 |     return {
165 |       content: [
166 |         {
167 |           type: "text",
168 |           text: JSON.stringify(balances),
169 |         },
170 |       ],
171 |     };
172 |   }
173 | );
174 | 
175 | server.tool(
176 |   "get_open_orders",
177 |   {
178 |     symbol: z.string().optional().describe("Trading pair symbol (optional)")
179 |   },
180 |   async ({ symbol }) => {
181 |     const orders = await getOpenOrders(symbol);
182 |     return {
183 |       content: [
184 |         {
185 |           type: "text",
186 |           text: JSON.stringify(orders),
187 |         },
188 |       ],
189 |     };
190 |   }
191 | );
192 | 
193 | server.tool(
194 |   "create_futures_order",
195 |   {
196 |     symbol: z.string().describe("Trading pair symbol (e.g., BTCUSDT)"),
197 |     side: z.enum(["BUY", "SELL"]).describe("Order side"),
198 |     type: z.enum([
199 |       "LIMIT", "MARKET", "STOP", "STOP_MARKET", 
200 |       "TAKE_PROFIT", "TAKE_PROFIT_MARKET", "TRAILING_STOP_MARKET"
201 |     ]).describe("Order type"),
202 |     quantity: z.string().describe("Order quantity"),
203 |     price: z.string().optional().describe("Order price (required for LIMIT orders)"),
204 |     stopPrice: z.string().optional().describe("Stop price (required for STOP orders)"),
205 |     timeInForce: z.enum(["GTC", "IOC", "FOK", "GTX"]).optional().describe("Time in force"),
206 |     reduceOnly: z.boolean().optional().describe("Reduce only flag"),
207 |     closePosition: z.boolean().optional().describe("Close position flag"),
208 |     positionSide: z.enum(["BOTH", "LONG", "SHORT"]).optional().describe("Position side"),
209 |     workingType: z.enum(["MARK_PRICE", "CONTRACT_PRICE"]).optional().describe("Working type"),
210 |     priceProtect: z.boolean().optional().describe("Price protect flag"),
211 |     activationPrice: z.string().optional().describe("Activation price for TRAILING_STOP_MARKET orders"),
212 |     callbackRate: z.string().optional().describe("Callback rate for TRAILING_STOP_MARKET orders")
213 |   },
214 |   async (args) => {
215 |     const order: FuturesOrder = {
216 |       symbol: args.symbol,
217 |       side: args.side,
218 |       type: args.type,
219 |       quantity: args.quantity,
220 |       price: args.price,
221 |       stopPrice: args.stopPrice,
222 |       timeInForce: args.timeInForce as TimeInForce,
223 |       reduceOnly: args.reduceOnly,
224 |       closePosition: args.closePosition,
225 |       positionSide: args.positionSide as PositionSide,
226 |       workingType: args.workingType as WorkingType,
227 |       priceProtect: args.priceProtect,
228 |       activationPrice: args.activationPrice,
229 |       callbackRate: args.callbackRate,
230 |     };
231 |     const response = await createFuturesOrder(order);
232 |     return {
233 |       content: [
234 |         {
235 |           type: "text",
236 |           text: JSON.stringify(response),
237 |         },
238 |       ],
239 |     };
240 |   }
241 | );
242 | 
243 | server.tool(
244 |   "cancel_futures_order",
245 |   {
246 |     symbol: z.string().describe("Trading pair symbol (e.g., BTCUSDT)"),
247 |     orderId: z.number().describe("Order ID to cancel")
248 |   },
249 |   async ({ symbol, orderId }) => {
250 |     await cancelFuturesOrder(symbol, orderId);
251 |     return {
252 |       content: [
253 |         {
254 |           type: "text",
255 |           text: "Futures order cancelled successfully",
256 |         },
257 |       ],
258 |     };
259 |   }
260 | );
261 | 
262 | server.tool(
263 |   "get_futures_positions",
264 |   {},
265 |   async () => {
266 |     const positions = await getFuturesPositions();
267 |     return {
268 |       content: [
269 |         {
270 |           type: "text",
271 |           text: JSON.stringify(positions),
272 |         },
273 |       ],
274 |     };
275 |   }
276 | );
277 | 
278 | server.tool(
279 |   "set_futures_leverage",
280 |   {
281 |     symbol: z.string().describe("Trading pair symbol (e.g., BTCUSDT)"),
282 |     leverage: z.number().describe("Leverage value (1-125)")
283 |   },
284 |   async ({ symbol, leverage }) => {
285 |     const settings: LeverageSettings = {
286 |       symbol: symbol,
287 |       leverage: leverage,
288 |     };
289 |     await setFuturesLeverage(settings);
290 |     return {
291 |       content: [
292 |         {
293 |           type: "text",
294 |           text: "Leverage set successfully",
295 |         },
296 |       ],
297 |     };
298 |   }
299 | );
300 | 
301 | server.tool(
302 |   "get_futures_account",
303 |   {},
304 |   async () => {
305 |     const account = await getFuturesAccount();
306 |     return {
307 |       content: [
308 |         {
309 |           type: "text",
310 |           text: JSON.stringify(account),
311 |         },
312 |       ],
313 |     };
314 |   }
315 | );
316 | 
317 | server.tool(
318 |   "get_futures_open_orders",
319 |   {
320 |     symbol: z.string().optional().describe("Trading pair symbol (optional)")
321 |   },
322 |   async ({ symbol }) => {
323 |     const orders = await getFuturesOpenOrders(symbol);
324 |     return {
325 |       content: [
326 |         {
327 |           type: "text",
328 |           text: JSON.stringify(orders),
329 |         },
330 |       ],
331 |     };
332 |   }
333 | );
334 | 
335 | server.tool(
336 |   "get_funding_rate",
337 |   {
338 |     symbol: z.string().describe("Trading pair symbol (e.g., BTCUSDT)")
339 |   },
340 |   async ({ symbol }) => {
341 |     const rate = await getFundingRate(symbol);
342 |     return {
343 |       content: [
344 |         {
345 |           type: "text",
346 |           text: JSON.stringify(rate),
347 |         },
348 |       ],
349 |     };
350 |   }
351 | );
352 | 
353 | async function main() {
354 |   try {
355 |     // Initialize Binance clients
356 |     const spotInitialized = await initializeBinanceClient();
357 |     const futuresInitialized = await initializeFuturesClient();
358 |     
359 |     if (!spotInitialized || !futuresInitialized) {
360 |       logError('Binance clients not initialized');
361 |     } else {
362 |       log('Binance clients initialized successfully');
363 |     }
364 | 
365 |     // 使用stdio传输层
366 |     const transport = new StdioServerTransport();
367 |     await server.connect(transport);
368 |     log('Server started successfully with stdio transport');
369 |   } catch (error) {
370 |     logError('Failed to start server:', error);
371 |     process.exit(1);
372 |   }
373 | }
374 | 
375 | main().catch((error) => {
376 |   logError('Unhandled error:', error);
377 |   process.exit(1);
378 | });
379 | 
```

--------------------------------------------------------------------------------
/src/services/binanceFutures.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { Spot } from '@binance/connector';
  2 | import { BinanceClientError, ApiKeyError, OrderValidationError, InsufficientMarginError, InvalidPositionModeError } from '../types/errors.js';
  3 | import { getApiKeys } from './keystore.js';
  4 | import * as fs from 'fs';
  5 | import * as path from 'path';
  6 | import {
  7 |   FuturesOrder,
  8 |   FuturesPosition,
  9 |   FuturesAccountInformation,
 10 |   LeverageSettings,
 11 |   FundingRate,
 12 |   PositionSide,
 13 |   MarginType,
 14 |   WorkingType
 15 | } from '../types/futures.js';
 16 | 
 17 | const logFile = path.join(process.cwd(), 'logs', 'futures.log');
 18 | 
 19 | // 确保日志目录存在
 20 | if (!fs.existsSync(path.dirname(logFile))) {
 21 |   fs.mkdirSync(path.dirname(logFile), { recursive: true });
 22 | }
 23 | 
 24 | function log(message: string) {
 25 |   const timestamp = new Date().toISOString();
 26 |   fs.appendFileSync(logFile, `${timestamp} - ${message}\n`);
 27 | }
 28 | 
 29 | function logError(message: string, error?: unknown) {
 30 |   const timestamp = new Date().toISOString();
 31 |   const errorMessage = error instanceof Error ? error.message : String(error);
 32 |   fs.appendFileSync(logFile, `${timestamp} - ERROR: ${message} ${error ? `- ${errorMessage}` : ''}\n`);
 33 | }
 34 | 
 35 | interface SpotExtended extends Spot {
 36 |   changeLeverage: (params: { symbol: string; leverage: number }) => Promise<any>;
 37 |   premiumIndex: (params: { symbol: string }) => Promise<any>;
 38 |   changePositionMode: (params: { dualSidePosition: boolean }) => Promise<any>;
 39 |   changeMarginType: (params: { symbol: string; marginType: MarginType }) => Promise<any>;
 40 |   klines: (symbol: string, interval: string, options?: any) => Promise<any>;
 41 | }
 42 | 
 43 | let futuresClient: SpotExtended | null = null;
 44 | 
 45 | export async function initializeFuturesClient(): Promise<boolean> {
 46 |   log('Initializing Binance futures client...');
 47 |   try {
 48 |     const keys = await getApiKeys();
 49 |     if (!keys) {
 50 |       logError('No credentials available for Binance futures client');
 51 |       throw new ApiKeyError('Futures API keys not found');
 52 |     }
 53 |     const { apiKey, apiSecret } = keys;
 54 |     
 55 |     log('Creating Binance futures client...');
 56 |     // Initialize client for USDⓈ-M Futures
 57 |     futuresClient = new Spot(apiKey, apiSecret) as SpotExtended;
 58 | 
 59 |     // Test the connection
 60 |     log('Testing Binance futures client connection...');
 61 |     await futuresClient.account();
 62 |     log('Successfully connected to Binance futures API');
 63 |     return true;
 64 |   } catch (error) {
 65 |     logError('Failed to initialize futures client:', error);
 66 |     futuresClient = null;
 67 |     if (error instanceof ApiKeyError) {
 68 |       throw error;
 69 |     }
 70 |     throw new BinanceClientError(`Failed to initialize futures client: ${error instanceof Error ? error.message : 'Unknown error'}`);
 71 |   }
 72 | }
 73 | 
 74 | export async function createFuturesOrder(order: FuturesOrder): Promise<any> {
 75 |   if (!futuresClient) {
 76 |     logError('Attempted to create futures order without initialized client');
 77 |     throw new BinanceClientError('Futures client not initialized');
 78 |   }
 79 | 
 80 |   try {
 81 |     log(`Creating futures order: ${JSON.stringify(order, null, 2)}`);
 82 |     const params = {
 83 |       symbol: order.symbol,
 84 |       side: order.side,
 85 |       type: order.type,
 86 |       quantity: order.quantity,
 87 |       timeInForce: order.timeInForce || 'GTC'
 88 |     } as any;
 89 | 
 90 |     if (order.positionSide) params.positionSide = order.positionSide;
 91 |     if (order.price) params.price = order.price;
 92 |     if (order.stopPrice) params.stopPrice = order.stopPrice;
 93 |     if (order.reduceOnly !== undefined) params.reduceOnly = order.reduceOnly;
 94 |     if (order.workingType) params.workingType = order.workingType;
 95 |     if (order.activationPrice) params.activationPrice = order.activationPrice;
 96 |     if (order.callbackRate) params.callbackRate = order.callbackRate;
 97 |     if (order.closePosition !== undefined) params.closePosition = order.closePosition;
 98 |     if (order.priceProtect !== undefined) params.priceProtect = order.priceProtect;
 99 | 
100 |     // Validate required parameters based on order type
101 |     if (['LIMIT', 'STOP', 'TAKE_PROFIT'].includes(order.type) && !order.price) {
102 |       throw new OrderValidationError(`Price is required for ${order.type} orders`);
103 |     }
104 |     if (['STOP', 'STOP_MARKET', 'TAKE_PROFIT', 'TAKE_PROFIT_MARKET'].includes(order.type) && !order.stopPrice) {
105 |       throw new OrderValidationError(`Stop price is required for ${order.type} orders`);
106 |     }
107 |     if (order.type === 'TRAILING_STOP_MARKET' && !order.callbackRate) {
108 |       throw new OrderValidationError('Callback rate is required for TRAILING_STOP_MARKET orders');
109 |     }
110 | 
111 |     log(`Sending futures order request with params: ${JSON.stringify(params, null, 2)}`);
112 |     const response = await futuresClient.newOrder(params);
113 |     log(`Futures order created successfully: ${JSON.stringify(response, null, 2)}`);
114 |     return response.data;
115 |   } catch (error) {
116 |     logError('Error creating futures order:', error);
117 |     if (error instanceof OrderValidationError) {
118 |       throw error;
119 |     }
120 |     const errorMessage = error instanceof Error ? error.message : 'Unknown error';
121 |     if (errorMessage.includes('insufficient margin')) {
122 |       logError('Insufficient margin for futures order');
123 |       throw new InsufficientMarginError(`Insufficient margin to create futures order: ${errorMessage}`);
124 |     }
125 |     if (errorMessage.includes('invalid position mode')) {
126 |       logError('Invalid position mode for futures order');
127 |       throw new InvalidPositionModeError(`Invalid position mode for futures order: ${errorMessage}`);
128 |     }
129 |     throw new BinanceClientError(`Failed to create futures order: ${errorMessage}`);
130 |   }
131 | }
132 | 
133 | export async function getFuturesAccountInformation(): Promise<FuturesAccountInformation> {
134 |   if (!futuresClient) {
135 |     logError('Attempted to get futures account information without initialized client');
136 |     throw new BinanceClientError('Futures client not initialized');
137 |   }
138 | 
139 |   try {
140 |     log('Fetching futures account information...');
141 |     const response = await futuresClient.account();
142 |     log('Successfully retrieved futures account information');
143 |     const accountInfo = {
144 |       feeTier: 0,
145 |       canTrade: true,
146 |       canDeposit: true,
147 |       canWithdraw: true,
148 |       updateTime: Date.now(),
149 |       totalInitialMargin: '0',
150 |       totalMaintMargin: '0',
151 |       totalWalletBalance: '0',
152 |       totalUnrealizedProfit: '0',
153 |       totalMarginBalance: '0',
154 |       totalPositionInitialMargin: '0',
155 |       totalOpenOrderInitialMargin: '0',
156 |       totalCrossWalletBalance: '0',
157 |       totalCrossUnPnl: '0',
158 |       availableBalance: '0',
159 |       maxWithdrawAmount: '0',
160 |       assets: response.data.balances.map((balance: any) => ({
161 |         asset: balance.asset,
162 |         walletBalance: balance.free,
163 |         unrealizedProfit: '0',
164 |         marginBalance: balance.locked,
165 |         maintMargin: '0',
166 |         initialMargin: '0',
167 |         positionInitialMargin: '0',
168 |         openOrderInitialMargin: '0',
169 |         maxWithdrawAmount: balance.free,
170 |         crossWalletBalance: '0',
171 |         crossUnPnl: '0',
172 |         availableBalance: balance.free
173 |       })),
174 |       positions: []
175 |     };
176 |     return accountInfo;
177 |   } catch (error) {
178 |     logError('Error getting futures account information:', error);
179 |     throw new BinanceClientError(`Failed to get futures account information: ${error instanceof Error ? error.message : 'Unknown error'}`);
180 |   }
181 | }
182 | 
183 | export async function getFuturesPositions(): Promise<FuturesPosition[]> {
184 |   if (!futuresClient) {
185 |     throw new BinanceClientError('Futures client not initialized');
186 |   }
187 | 
188 |   try {
189 |     const response = await futuresClient.account();
190 |     const accountData = response.data as any;
191 |     const positions = accountData.positions || [];
192 |     return positions.map((pos: any) => ({
193 |       symbol: pos.symbol || '',
194 |       positionAmt: pos.positionAmt || '0',
195 |       entryPrice: pos.entryPrice || '0',
196 |       markPrice: pos.markPrice || '0',
197 |       unRealizedProfit: pos.unrealizedProfit || '0',
198 |       liquidationPrice: pos.liquidationPrice || '0',
199 |       leverage: parseInt(pos.leverage || '1'),
200 |       marginType: pos.marginType || MarginType.CROSSED,
201 |       isolatedMargin: pos.isolatedMargin || '0',
202 |       positionSide: pos.positionSide || PositionSide.BOTH,
203 |       updateTime: pos.updateTime || Date.now()
204 |     }));
205 |   } catch (error) {
206 |     throw new BinanceClientError(`Failed to get futures positions: ${error instanceof Error ? error.message : 'Unknown error'}`);
207 |   }
208 | }
209 | 
210 | export async function setFuturesLeverage(settings: LeverageSettings): Promise<boolean> {
211 |   if (!futuresClient) {
212 |     throw new BinanceClientError('Futures client not initialized');
213 |   }
214 | 
215 |   try {
216 |     await futuresClient.changeLeverage({
217 |       symbol: settings.symbol,
218 |       leverage: settings.leverage
219 |     });
220 |     return true;
221 |   } catch (error) {
222 |     const errorMessage = error instanceof Error ? error.message : 'Unknown error';
223 |     if (errorMessage.includes('insufficient margin')) {
224 |       throw new InsufficientMarginError(`Insufficient margin to change leverage: ${errorMessage}`);
225 |     }
226 |     if (errorMessage.includes('invalid position mode')) {
227 |       throw new InvalidPositionModeError(`Invalid position mode when changing leverage: ${errorMessage}`);
228 |     }
229 |     throw new BinanceClientError(`Failed to set futures leverage: ${errorMessage}`);
230 |   }
231 | }
232 | 
233 | export async function getFundingRate(symbol: string): Promise<FundingRate> {
234 |   if (!futuresClient) {
235 |     throw new BinanceClientError('Futures client not initialized');
236 |   }
237 | 
238 |   try {
239 |     const response = await futuresClient.premiumIndex({ symbol });
240 |     const data = response.data[0] || {};
241 |     return {
242 |       symbol: data.symbol || symbol,
243 |       fundingRate: data.lastFundingRate || '0',
244 |       fundingTime: data.nextFundingTime || Date.now(),
245 |       nextFundingTime: data.nextFundingTime || Date.now()
246 |     };
247 |   } catch (error) {
248 |     throw new BinanceClientError(`Failed to get funding rate: ${error instanceof Error ? error.message : 'Unknown error'}`);
249 |   }
250 | }
251 | 
252 | export async function cancelFuturesOrder(symbol: string, orderId: number): Promise<void> {
253 |   if (!futuresClient) {
254 |     throw new BinanceClientError('Futures client not initialized');
255 |   }
256 | 
257 |   try {
258 |     await futuresClient.cancelOrder(symbol, { orderId });
259 |   } catch (error) {
260 |     const errorMessage = error instanceof Error ? error.message : 'Unknown error';
261 |     if (errorMessage.includes('invalid position mode')) {
262 |       throw new InvalidPositionModeError(`Invalid position mode when canceling futures order: ${errorMessage}`);
263 |     }
264 |     throw new BinanceClientError(`Failed to cancel futures order: ${errorMessage}`);
265 |   }
266 | }
267 | 
268 | export async function getFuturesOpenOrders(symbol?: string): Promise<FuturesOrder[]> {
269 |   if (!futuresClient) {
270 |     throw new BinanceClientError('Futures client not initialized');
271 |   }
272 | 
273 |   try {
274 |     const params = symbol ? { symbol } : {};
275 |     const response = await futuresClient.openOrders(params);
276 |     return response.data.map((order: any) => ({
277 |       symbol: order.symbol,
278 |       side: order.side,
279 |       type: order.type,
280 |       quantity: order.origQty,
281 |       price: order.price,
282 |       timeInForce: order.timeInForce,
283 |       positionSide: order.positionSide,
284 |       stopPrice: order.stopPrice,
285 |       workingType: order.workingType,
286 |       closePosition: order.closePosition,
287 |       activationPrice: order.activationPrice,
288 |       callbackRate: order.callbackRate,
289 |       priceProtect: order.priceProtect,
290 |       reduceOnly: order.reduceOnly
291 |     }));
292 |   } catch (error) {
293 |     throw new BinanceClientError(`Failed to get open futures orders: ${error instanceof Error ? error.message : 'Unknown error'}`);
294 |   }
295 | }
296 | 
297 | export async function changePositionMode(dualSidePosition: boolean): Promise<boolean> {
298 |   if (!futuresClient) {
299 |     throw new BinanceClientError('Futures client not initialized');
300 |   }
301 | 
302 |   try {
303 |     log(`Changing position mode to ${dualSidePosition ? 'dual-side' : 'one-way'}`);
304 |     await futuresClient.changePositionMode({
305 |       dualSidePosition: dualSidePosition
306 |     });
307 |     log('Position mode changed successfully');
308 |     return true;
309 |   } catch (error) {
310 |     const errorMessage = error instanceof Error ? error.message : 'Unknown error';
311 |     logError(`Failed to change position mode:`, error);
312 |     throw new BinanceClientError(`Failed to change position mode: ${errorMessage}`);
313 |   }
314 | }
315 | 
316 | export async function changeMarginType(symbol: string, marginType: MarginType): Promise<boolean> {
317 |   if (!futuresClient) {
318 |     throw new BinanceClientError('Futures client not initialized');
319 |   }
320 | 
321 |   try {
322 |     log(`Changing margin type for ${symbol} to ${marginType}`);
323 |     await futuresClient.changeMarginType({
324 |       symbol: symbol,
325 |       marginType: marginType
326 |     });
327 |     log('Margin type changed successfully');
328 |     return true;
329 |   } catch (error) {
330 |     const errorMessage = error instanceof Error ? error.message : 'Unknown error';
331 |     logError(`Failed to change margin type:`, error);
332 |     if (errorMessage.includes('isolated balance insufficient')) {
333 |       throw new InsufficientMarginError(`Insufficient margin to change margin type: ${errorMessage}`);
334 |     }
335 |     throw new BinanceClientError(`Failed to change margin type: ${errorMessage}`);
336 |   }
337 | }
338 | 
339 | export async function getFuturesKlines(symbol: string, interval: string, limit?: number): Promise<any[]> {
340 |   if (!futuresClient) {
341 |     throw new BinanceClientError('Futures client not initialized');
342 |   }
343 | 
344 |   try {
345 |     const params: any = {};
346 |     if (limit) params.limit = limit;
347 | 
348 |     log(`Querying futures klines for ${symbol}, interval ${interval}`);
349 |     const response = await futuresClient.klines(symbol, interval, params);
350 |     log('Futures klines retrieved successfully');
351 |     
352 |     // 转换返回数据为更易于使用的格式
353 |     return response.data.map((kline: any[]) => ({
354 |       openTime: kline[0],
355 |       open: kline[1],
356 |       high: kline[2],
357 |       low: kline[3],
358 |       close: kline[4],
359 |       volume: kline[5],
360 |       closeTime: kline[6],
361 |       quoteAssetVolume: kline[7],
362 |       trades: kline[8],
363 |       takerBuyBaseAssetVolume: kline[9],
364 |       takerBuyQuoteAssetVolume: kline[10]
365 |     }));
366 |   } catch (error) {
367 |     const errorMessage = error instanceof Error ? error.message : 'Unknown error';
368 |     logError(`Failed to get futures klines:`, error);
369 |     throw new BinanceClientError(`Failed to get futures klines: ${errorMessage}`);
370 |   }
371 | }
372 | 
```