binance-futures-mcp 1.0.7__py3-none-any.whl → 1.0.8__py3-none-any.whl

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.
@@ -1,12 +1,14 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: binance-futures-mcp
3
- Version: 1.0.7
4
- Summary: A Model Context Protocol server for Binance Futures API
3
+ Version: 1.0.8
4
+ Summary: A Model Context Protocol server for Binance Futures API with comprehensive trading tools
5
5
  Home-page: https://github.com/alexcandrabersiva/bin-mcp
6
6
  Author: Binance MCP Server
7
- Project-URL: Bug Tracker, https://github.com/alexcandrabersiva/bin-mcp/issues
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/alexcandrabersiva/bin-mcp
8
9
  Project-URL: Repository, https://github.com/alexcandrabersiva/bin-mcp.git
9
- Keywords: mcp binance trading futures api model-context-protocol
10
+ Project-URL: Issues, https://github.com/alexcandrabersiva/bin-mcp/issues
11
+ Keywords: mcp,binance,trading,futures,api,model-context-protocol
10
12
  Classifier: Development Status :: 4 - Beta
11
13
  Classifier: Intended Audience :: Developers
12
14
  Classifier: Programming Language :: Python :: 3
@@ -20,9 +22,18 @@ Classifier: Topic :: Office/Business :: Financial :: Investment
20
22
  Requires-Python: >=3.8
21
23
  Description-Content-Type: text/markdown
22
24
  License-File: LICENSE
23
- Requires-Dist: mcp (>=1.0.0)
24
- Requires-Dist: aiohttp (>=3.8.0)
25
- Requires-Dist: pydantic (>=2.0.0)
25
+ Requires-Dist: mcp>=1.0.0
26
+ Requires-Dist: aiohttp>=3.8.0
27
+ Requires-Dist: pydantic>=2.0.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
30
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
31
+ Requires-Dist: black>=23.0.0; extra == "dev"
32
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
33
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
34
+ Dynamic: home-page
35
+ Dynamic: license-file
36
+ Dynamic: requires-python
26
37
 
27
38
  # Binance MCP Server
28
39
 
@@ -0,0 +1,9 @@
1
+ binance_futures_mcp-1.0.8.dist-info/licenses/LICENSE,sha256=zqfwopvOi7kOx5YVOnehgmRFR-IU3x1n9JEShr3QOYg,1075
2
+ binance_mcp/__init__.py,sha256=ExUxc1kp3GoSwmEtC7eGgFMZlvSQ4IdW1T5xhw-NT98,106
3
+ binance_mcp/__main__.py,sha256=_9DBrtv0PAvjLjCqKk_cMfGtkqSUOcmU6HeQKFjuFMQ,214
4
+ binance_mcp/server.py,sha256=RNLNWe_lF24HKti32MBPFo3rsACBWZ6yF02C3owtDB4,48057
5
+ binance_futures_mcp-1.0.8.dist-info/METADATA,sha256=32MQTpog3BDvt0acBdZpD6dJyURTEGG54nYqVHa9qNA,11845
6
+ binance_futures_mcp-1.0.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ binance_futures_mcp-1.0.8.dist-info/entry_points.txt,sha256=-1iVs9AF7JQBS-xMichP9hQhbCY7YfLFRJVaNKwuN34,69
8
+ binance_futures_mcp-1.0.8.dist-info/top_level.txt,sha256=RqGhe1caZUvBF_ezvTiLZD8kVS25eiWVkfJfmoND9m8,12
9
+ binance_futures_mcp-1.0.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.40.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
binance_mcp/server.py CHANGED
@@ -1,9 +1,11 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
3
  import asyncio
4
+ import argparse
4
5
  import hashlib
5
6
  import hmac
6
7
  import json
8
+ import os
7
9
  import time
8
10
  from datetime import datetime
9
11
  from typing import Any, Dict, List, Optional, Union
@@ -48,7 +50,7 @@ class BinanceClient:
48
50
  timeout=timeout,
49
51
  connector=connector,
50
52
  headers={
51
- 'User-Agent': 'binance-mcp-server/1.0.7',
53
+ 'User-Agent': 'binance-mcp-server/1.0.8',
52
54
  'Content-Type': 'application/x-www-form-urlencoded'
53
55
  }
54
56
  )
@@ -96,15 +98,21 @@ class BinanceClient:
96
98
  try:
97
99
  if method == "GET":
98
100
  async with self.session.get(url, params=params, headers=headers, ssl=False) as response:
99
- response.raise_for_status()
101
+ if response.status != 200:
102
+ error_text = await response.text()
103
+ raise Exception(f"HTTP {response.status}: {error_text}")
100
104
  return await response.json()
101
105
  elif method == "POST":
102
106
  async with self.session.post(url, data=params, headers=headers, ssl=False) as response:
103
- response.raise_for_status()
107
+ if response.status != 200:
108
+ error_text = await response.text()
109
+ raise Exception(f"HTTP {response.status}: {error_text}")
104
110
  return await response.json()
105
111
  elif method == "DELETE":
106
112
  async with self.session.delete(url, data=params, headers=headers, ssl=False) as response:
107
- response.raise_for_status()
113
+ if response.status != 200:
114
+ error_text = await response.text()
115
+ raise Exception(f"HTTP {response.status}: {error_text}")
108
116
  return await response.json()
109
117
  else:
110
118
  raise ValueError(f"Unsupported HTTP method: {method}")
@@ -244,26 +252,26 @@ class BinanceMCPServer:
244
252
  "properties": {
245
253
  "symbol": {"type": "string", "description": "Trading pair symbol"},
246
254
  "side": {"type": "string", "description": "Order side ('BUY' or 'SELL')"},
247
- "order_type": {"type": "string", "description": "Order type ('MARKET', 'LIMIT', 'STOP', 'STOP_MARKET', 'TRAILING_STOP_MARKET', etc)"},
255
+ "type": {"type": "string", "description": "Order type ('MARKET', 'LIMIT', 'STOP', 'STOP_MARKET', 'TRAILING_STOP_MARKET', etc)"},
248
256
  "quantity": {"type": "number", "description": "Order quantity"},
249
257
  "price": {"type": "number", "description": "Order price (for LIMIT orders)"},
250
- "stop_price": {"type": "number", "description": "Stop price (for STOP orders)"},
251
- "time_in_force": {"type": "string", "description": "Time in force (GTC, IOC, FOK)"},
252
- "position_side": {"type": "string", "description": "Position side ('BOTH', 'LONG', 'SHORT')"},
253
- "reduce_only": {"type": "string", "description": "Reduce only flag"},
254
- "new_client_order_id": {"type": "string", "description": "Custom order ID"},
255
- "close_position": {"type": "string", "description": "Close position flag"},
256
- "activation_price": {"type": "number", "description": "Activation price (for TRAILING_STOP_MARKET)"},
257
- "callback_rate": {"type": "number", "description": "Callback rate (for TRAILING_STOP_MARKET)"},
258
- "working_type": {"type": "string", "description": "Working type (MARK_PRICE, CONTRACT_PRICE)"},
259
- "price_protect": {"type": "string", "description": "Price protection flag"},
260
- "new_order_resp_type": {"type": "string", "description": "Response type"},
261
- "recv_window": {"type": "integer", "description": "Receive window"},
258
+ "stopPrice": {"type": "number", "description": "Stop price (for STOP orders)"},
259
+ "timeInForce": {"type": "string", "description": "Time in force (GTC, IOC, FOK)"},
260
+ "positionSide": {"type": "string", "description": "Position side ('BOTH', 'LONG', 'SHORT')"},
261
+ "reduceOnly": {"type": "string", "description": "Reduce only flag ('true' or 'false')"},
262
+ "newClientOrderId": {"type": "string", "description": "Custom order ID"},
263
+ "closePosition": {"type": "string", "description": "Close position flag ('true' or 'false')"},
264
+ "activationPrice": {"type": "number", "description": "Activation price (for TRAILING_STOP_MARKET)"},
265
+ "callbackRate": {"type": "number", "description": "Callback rate (for TRAILING_STOP_MARKET)"},
266
+ "workingType": {"type": "string", "description": "Working type (MARK_PRICE, CONTRACT_PRICE)"},
267
+ "priceProtect": {"type": "string", "description": "Price protection flag ('TRUE' or 'FALSE')"},
268
+ "newOrderRespType": {"type": "string", "description": "Response type ('ACK', 'RESULT')"},
269
+ "recvWindow": {"type": "integer", "description": "Receive window"},
262
270
  "timestamp": {"type": "integer", "description": "Timestamp"},
263
271
  "quantity_precision": {"type": "integer", "description": "Quantity precision for validation"},
264
272
  "price_precision": {"type": "integer", "description": "Price precision for validation"}
265
273
  },
266
- "required": ["symbol", "side", "order_type"]
274
+ "required": ["symbol", "side", "type"]
267
275
  }
268
276
  ),
269
277
  Tool(
@@ -386,6 +394,20 @@ class BinanceMCPServer:
386
394
  "required": ["symbol", "order_id"]
387
395
  }
388
396
  ),
397
+ Tool(
398
+ name="close_position",
399
+ description="Close current position for a symbol (market order to close all or part of position)",
400
+ inputSchema={
401
+ "type": "object",
402
+ "properties": {
403
+ "symbol": {"type": "string", "description": "Trading pair symbol"},
404
+ "position_side": {"type": "string", "description": "Position side to close ('BOTH', 'LONG', 'SHORT'). Default 'BOTH' for One-way mode"},
405
+ "quantity": {"type": "number", "description": "Quantity to close (optional, if not provided will close entire position)"},
406
+ "close_all": {"type": "boolean", "description": "If true, closes entire position using closePosition=true parameter"}
407
+ },
408
+ "required": ["symbol"]
409
+ }
410
+ ),
389
411
 
390
412
  # Trading Configuration Tools
391
413
  Tool(
@@ -656,10 +678,31 @@ class BinanceMCPServer:
656
678
 
657
679
  # Order Management Tools
658
680
  elif name == "place_order":
681
+ # Filter out precision parameters and pass through all other parameters directly
659
682
  params = {k: v for k, v in arguments.items() if v is not None and k not in ["quantity_precision", "price_precision"]}
660
- # Convert order_type to type for API
661
- if "order_type" in params:
662
- params["type"] = params.pop("order_type")
683
+
684
+ # Validate mandatory parameters based on order type
685
+ order_type = params.get("type")
686
+ if order_type == "LIMIT":
687
+ required_params = ["timeInForce", "quantity", "price"]
688
+ missing = [p for p in required_params if p not in params]
689
+ if missing:
690
+ raise ValueError(f"LIMIT order missing required parameters: {missing}")
691
+ elif order_type == "MARKET":
692
+ if "quantity" not in params:
693
+ raise ValueError("MARKET order missing required parameter: quantity")
694
+ elif order_type in ["STOP", "TAKE_PROFIT"]:
695
+ required_params = ["quantity", "price", "stopPrice"]
696
+ missing = [p for p in required_params if p not in params]
697
+ if missing:
698
+ raise ValueError(f"{order_type} order missing required parameters: {missing}")
699
+ elif order_type in ["STOP_MARKET", "TAKE_PROFIT_MARKET"]:
700
+ if "stopPrice" not in params:
701
+ raise ValueError(f"{order_type} order missing required parameter: stopPrice")
702
+ elif order_type == "TRAILING_STOP_MARKET":
703
+ if "callbackRate" not in params:
704
+ raise ValueError("TRAILING_STOP_MARKET order missing required parameter: callbackRate")
705
+
663
706
  result = await client._make_request("POST", "/fapi/v1/order", params, "TRADE")
664
707
  elif name == "place_multiple_orders":
665
708
  # This requires special handling for batch orders
@@ -697,6 +740,63 @@ class BinanceMCPServer:
697
740
  elif name == "query_order":
698
741
  params = {"symbol": arguments["symbol"], "orderId": arguments["order_id"]}
699
742
  result = await client._make_request("GET", "/fapi/v1/order", params, "USER_DATA")
743
+ elif name == "close_position":
744
+ # Handle position closing
745
+ symbol = arguments["symbol"]
746
+ position_side = arguments.get("position_side", "BOTH")
747
+ quantity = arguments.get("quantity")
748
+ close_all = arguments.get("close_all", False)
749
+
750
+ # First, get current position to determine the side and quantity to close
751
+ position_params = {"symbol": symbol}
752
+ positions = await client._make_request("GET", "/fapi/v2/positionRisk", position_params, "USER_DATA")
753
+
754
+ # Find the position to close
755
+ position_to_close = None
756
+ for pos in positions:
757
+ if pos["symbol"] == symbol and float(pos["positionAmt"]) != 0:
758
+ if position_side == "BOTH" or pos["positionSide"] == position_side:
759
+ position_to_close = pos
760
+ break
761
+
762
+ if not position_to_close:
763
+ raise ValueError(f"No open position found for {symbol} with position side {position_side}")
764
+
765
+ position_amt = float(position_to_close["positionAmt"])
766
+ current_position_side = position_to_close["positionSide"]
767
+
768
+ # Determine order side (opposite of position)
769
+ if position_amt > 0: # Long position
770
+ order_side = "SELL"
771
+ else: # Short position
772
+ order_side = "BUY"
773
+ position_amt = abs(position_amt) # Make positive for order quantity
774
+
775
+ # Determine quantity to close
776
+ if close_all:
777
+ # Use closePosition parameter to close entire position
778
+ order_params = {
779
+ "symbol": symbol,
780
+ "side": order_side,
781
+ "type": "MARKET",
782
+ "closePosition": "true"
783
+ }
784
+ if current_position_side != "BOTH":
785
+ order_params["positionSide"] = current_position_side
786
+ else:
787
+ # Close specific quantity or entire position
788
+ close_quantity = quantity if quantity else position_amt
789
+ order_params = {
790
+ "symbol": symbol,
791
+ "side": order_side,
792
+ "type": "MARKET",
793
+ "quantity": close_quantity,
794
+ "reduceOnly": "true"
795
+ }
796
+ if current_position_side != "BOTH":
797
+ order_params["positionSide"] = current_position_side
798
+
799
+ result = await client._make_request("POST", "/fapi/v1/order", order_params, "TRADE")
700
800
 
701
801
  # Trading Configuration Tools
702
802
  elif name == "change_leverage":
@@ -816,7 +916,7 @@ async def main():
816
916
  write_stream,
817
917
  InitializationOptions(
818
918
  server_name="binance-futures-mcp-server",
819
- server_version="1.0.7",
919
+ server_version="1.0.8",
820
920
  capabilities={
821
921
  "tools": {}
822
922
  }
@@ -1,9 +0,0 @@
1
- binance_mcp/__init__.py,sha256=ExUxc1kp3GoSwmEtC7eGgFMZlvSQ4IdW1T5xhw-NT98,106
2
- binance_mcp/__main__.py,sha256=_9DBrtv0PAvjLjCqKk_cMfGtkqSUOcmU6HeQKFjuFMQ,214
3
- binance_mcp/server.py,sha256=mBuB1HX6xf5GSviYV5oIPqKz2werdBiibyxTUA-qnpY,41669
4
- binance_futures_mcp-1.0.7.dist-info/LICENSE,sha256=zqfwopvOi7kOx5YVOnehgmRFR-IU3x1n9JEShr3QOYg,1075
5
- binance_futures_mcp-1.0.7.dist-info/METADATA,sha256=GgB3I-rPgq5YKmV9Usi-RYvAtpQ9rk7LowADz1-Q5j8,11418
6
- binance_futures_mcp-1.0.7.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
7
- binance_futures_mcp-1.0.7.dist-info/entry_points.txt,sha256=-1iVs9AF7JQBS-xMichP9hQhbCY7YfLFRJVaNKwuN34,69
8
- binance_futures_mcp-1.0.7.dist-info/top_level.txt,sha256=RqGhe1caZUvBF_ezvTiLZD8kVS25eiWVkfJfmoND9m8,12
9
- binance_futures_mcp-1.0.7.dist-info/RECORD,,