---
id: "MCP-BINANCE-CONNECTOR-SPEC"
title: "Especificacion MCP Binance Connector"
type: "Technical Specification"
project: "trading-platform"
version: "1.0.0"
created_date: "2026-01-04"
updated_date: "2026-01-04"
author: "Orquestador Agent - Trading Platform"
---

# MCP Binance Connector - Especificacion Tecnica

**Version:** 1.0.0
**Fecha:** 2026-01-04
**Modulo:** OQI-010-llm-trading-integration
**Puerto:** 3606

---

## Tabla de Contenidos

1. [Vision General](#vision-general)
2. [Arquitectura](#arquitectura)
3. [MCP Tools Specification](#mcp-tools-specification)
4. [Seguridad](#seguridad)
5. [Configuracion](#configuracion)
6. [Implementacion](#implementacion)
7. [Testing](#testing)

---

## Vision General

### Proposito

El MCP Binance Connector expone las funcionalidades de Binance como herramientas MCP (Model Context Protocol), permitiendo que los agentes LLM interactuen con el exchange de forma segura y controlada.

### Capacidades

| Categoria | Funcionalidades |
|-----------|-----------------|
| **Market Data** | Precios, order book, velas, 24h stats |
| **Account** | Balance, posiciones, historial |
| **Trading** | Ordenes market/limit, cancelacion |
| **Futures** | Posiciones, leverage, funding |

### Integracion con LLM Agent

```
┌─────────────────────────────────────────────────────────────────┐
│                      LLM TRADING AGENT                           │
│                                                                  │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │                   MCP ORCHESTRATOR                         │ │
│  │                                                            │ │
│  │   ┌──────────────────┐      ┌──────────────────┐          │ │
│  │   │  MCP MT4         │      │  MCP BINANCE     │          │ │
│  │   │  Connector       │      │  Connector       │          │ │
│  │   │  :3605           │      │  :3606           │          │ │
│  │   └────────┬─────────┘      └────────┬─────────┘          │ │
│  └────────────┼─────────────────────────┼────────────────────┘ │
│               │                         │                       │
└───────────────┼─────────────────────────┼───────────────────────┘
                │                         │
                ▼                         ▼
        ┌───────────────┐         ┌───────────────┐
        │   MetaAPI     │         │   Binance     │
        │   (MT4/MT5)   │         │   Exchange    │
        └───────────────┘         └───────────────┘
```

---

## Arquitectura

### Estructura del Proyecto

```
apps/mcp-binance-connector/
├── src/
│   ├── index.ts                 # Entry point & MCP server
│   ├── config.ts                # Configuration management
│   │
│   ├── services/
│   │   ├── binance-client.ts    # CCXT wrapper for Binance
│   │   ├── rate-limiter.ts      # Rate limiting service
│   │   └── websocket-manager.ts # WebSocket connections
│   │
│   ├── tools/
│   │   ├── index.ts             # Tool registry
│   │   ├── market.ts            # Market data tools
│   │   ├── account.ts           # Account info tools
│   │   ├── orders.ts            # Order management tools
│   │   ├── positions.ts         # Position management (futures)
│   │   └── utils.ts             # Utility tools
│   │
│   ├── middleware/
│   │   ├── auth.ts              # API key validation
│   │   ├── risk-check.ts        # Pre-trade risk validation
│   │   └── logging.ts           # Request/response logging
│   │
│   └── types/
│       ├── binance.ts           # Binance-specific types
│       └── mcp.ts               # MCP protocol types
│
├── tests/
│   ├── unit/
│   │   ├── market.test.ts
│   │   └── orders.test.ts
│   └── integration/
│       └── binance-api.test.ts
│
├── docs/
│   ├── ARCHITECTURE.md
│   └── MCP-TOOLS-SPEC.md
│
├── Dockerfile
├── package.json
├── tsconfig.json
├── .env.example
└── README.md
```

### Dependencias Principales

```json
{
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.6.0",
    "ccxt": "^4.0.0",
    "express": "^4.18.2",
    "zod": "^3.22.0",
    "redis": "^4.6.0",
    "winston": "^3.11.0",
    "axios": "^1.6.0"
  },
  "devDependencies": {
    "typescript": "^5.3.0",
    "ts-node-dev": "^2.0.0",
    "jest": "^29.7.0",
    "@types/node": "^20.10.0"
  }
}
```

---

## MCP Tools Specification

### Tool Categories

#### 1. Market Data Tools (Read-Only, Low Risk)

```typescript
// tools/market.ts

/**
 * Tool: binance_get_ticker
 * Obtiene precio actual y estadisticas 24h de un simbolo
 */
export const getTickerTool: MCPTool = {
  name: "binance_get_ticker",
  description: "Obtiene el precio actual y estadisticas de 24h para un simbolo de trading",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de trading (ej: BTCUSDT, ETHUSDT)",
        pattern: "^[A-Z]{2,10}$"
      }
    },
    required: ["symbol"]
  },
  handler: async ({ symbol }) => {
    const ticker = await binanceClient.fetchTicker(symbol);
    return {
      symbol: ticker.symbol,
      price: ticker.last,
      bid: ticker.bid,
      ask: ticker.ask,
      high24h: ticker.high,
      low24h: ticker.low,
      volume24h: ticker.baseVolume,
      change24h: ticker.percentage,
      timestamp: ticker.timestamp
    };
  }
};

/**
 * Tool: binance_get_orderbook
 * Obtiene el order book con profundidad especificada
 */
export const getOrderbookTool: MCPTool = {
  name: "binance_get_orderbook",
  description: "Obtiene el order book (bids y asks) con la profundidad especificada",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de trading"
      },
      limit: {
        type: "number",
        description: "Profundidad del orderbook (5, 10, 20, 50, 100)",
        enum: [5, 10, 20, 50, 100],
        default: 20
      }
    },
    required: ["symbol"]
  },
  handler: async ({ symbol, limit = 20 }) => {
    const orderbook = await binanceClient.fetchOrderBook(symbol, limit);
    return {
      symbol,
      bids: orderbook.bids.slice(0, 10),
      asks: orderbook.asks.slice(0, 10),
      spread: orderbook.asks[0][0] - orderbook.bids[0][0],
      spreadPercentage: ((orderbook.asks[0][0] - orderbook.bids[0][0]) / orderbook.bids[0][0]) * 100,
      timestamp: orderbook.timestamp
    };
  }
};

/**
 * Tool: binance_get_klines
 * Obtiene velas historicas (OHLCV)
 */
export const getKlinesTool: MCPTool = {
  name: "binance_get_klines",
  description: "Obtiene velas historicas (OHLCV) para analisis tecnico",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de trading"
      },
      interval: {
        type: "string",
        description: "Intervalo temporal",
        enum: ["1m", "5m", "15m", "30m", "1h", "4h", "1d", "1w"],
        default: "5m"
      },
      limit: {
        type: "number",
        description: "Numero de velas (max 500)",
        default: 100,
        maximum: 500
      }
    },
    required: ["symbol"]
  },
  handler: async ({ symbol, interval = "5m", limit = 100 }) => {
    const ohlcv = await binanceClient.fetchOHLCV(symbol, interval, undefined, limit);
    return {
      symbol,
      interval,
      candles: ohlcv.map(c => ({
        timestamp: c[0],
        open: c[1],
        high: c[2],
        low: c[3],
        close: c[4],
        volume: c[5]
      })),
      count: ohlcv.length
    };
  }
};

/**
 * Tool: binance_get_trades
 * Obtiene trades recientes
 */
export const getRecentTradesTool: MCPTool = {
  name: "binance_get_trades",
  description: "Obtiene los trades mas recientes del mercado",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de trading"
      },
      limit: {
        type: "number",
        description: "Numero de trades (max 100)",
        default: 50,
        maximum: 100
      }
    },
    required: ["symbol"]
  },
  handler: async ({ symbol, limit = 50 }) => {
    const trades = await binanceClient.fetchTrades(symbol, undefined, limit);
    return {
      symbol,
      trades: trades.map(t => ({
        id: t.id,
        price: t.price,
        amount: t.amount,
        side: t.side,
        timestamp: t.timestamp
      })),
      count: trades.length
    };
  }
};
```

#### 2. Account Tools (Read-Only, Medium Risk)

```typescript
// tools/account.ts

/**
 * Tool: binance_get_account
 * Obtiene balance y estado de la cuenta
 */
export const getAccountTool: MCPTool = {
  name: "binance_get_account",
  description: "Obtiene el balance y estado de la cuenta de trading",
  inputSchema: {
    type: "object",
    properties: {},
    required: []
  },
  handler: async () => {
    const balance = await binanceClient.fetchBalance();

    // Filtrar solo activos con balance > 0
    const nonZeroBalances = Object.entries(balance.total)
      .filter(([_, amount]) => amount > 0)
      .map(([asset, total]) => ({
        asset,
        free: balance.free[asset],
        locked: balance.used[asset],
        total
      }));

    return {
      accountType: "SPOT",
      balances: nonZeroBalances,
      totalUSDT: await calculateTotalUSDT(nonZeroBalances),
      canTrade: true,
      canWithdraw: true,
      updateTime: Date.now()
    };
  }
};

/**
 * Tool: binance_get_open_orders
 * Obtiene ordenes abiertas
 */
export const getOpenOrdersTool: MCPTool = {
  name: "binance_get_open_orders",
  description: "Obtiene todas las ordenes abiertas (pendientes de ejecucion)",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo especifico (opcional, si no se especifica retorna todos)"
      }
    },
    required: []
  },
  handler: async ({ symbol }) => {
    const orders = await binanceClient.fetchOpenOrders(symbol);
    return {
      orders: orders.map(o => ({
        id: o.id,
        symbol: o.symbol,
        side: o.side,
        type: o.type,
        price: o.price,
        amount: o.amount,
        filled: o.filled,
        remaining: o.remaining,
        status: o.status,
        createdAt: o.timestamp
      })),
      count: orders.length
    };
  }
};

/**
 * Tool: binance_get_trade_history
 * Obtiene historial de trades ejecutados
 */
export const getTradeHistoryTool: MCPTool = {
  name: "binance_get_trade_history",
  description: "Obtiene el historial de trades ejecutados por el usuario",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de trading"
      },
      limit: {
        type: "number",
        description: "Numero de trades (max 100)",
        default: 50,
        maximum: 100
      }
    },
    required: ["symbol"]
  },
  handler: async ({ symbol, limit = 50 }) => {
    const trades = await binanceClient.fetchMyTrades(symbol, undefined, limit);
    return {
      symbol,
      trades: trades.map(t => ({
        id: t.id,
        orderId: t.order,
        side: t.side,
        price: t.price,
        amount: t.amount,
        cost: t.cost,
        fee: t.fee,
        timestamp: t.timestamp
      })),
      totalPnL: calculatePnL(trades),
      count: trades.length
    };
  }
};
```

#### 3. Order Management Tools (High Risk, Requires Confirmation)

```typescript
// tools/orders.ts

/**
 * Tool: binance_create_order
 * Crea una orden de trading
 * ALTO RIESGO - Requiere confirmacion explicita
 */
export const createOrderTool: MCPTool = {
  name: "binance_create_order",
  description: "Crea una orden de compra o venta. ALTO RIESGO - Asegurate de validar con el usuario antes de ejecutar.",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de trading (ej: BTCUSDT)"
      },
      side: {
        type: "string",
        description: "Direccion de la orden",
        enum: ["buy", "sell"]
      },
      type: {
        type: "string",
        description: "Tipo de orden",
        enum: ["market", "limit", "stop_loss", "take_profit"],
        default: "market"
      },
      amount: {
        type: "number",
        description: "Cantidad a comprar/vender"
      },
      price: {
        type: "number",
        description: "Precio limite (requerido para ordenes limit)"
      },
      stopPrice: {
        type: "number",
        description: "Precio de activacion para stop orders"
      }
    },
    required: ["symbol", "side", "amount"]
  },
  riskLevel: "HIGH",
  requiresConfirmation: true,
  handler: async ({ symbol, side, type = "market", amount, price, stopPrice }) => {
    // Pre-trade risk check
    const riskCheck = await performRiskCheck({ symbol, side, amount, price });
    if (!riskCheck.allowed) {
      return {
        success: false,
        error: "RISK_CHECK_FAILED",
        details: riskCheck.reason
      };
    }

    try {
      let order;
      if (type === "market") {
        order = await binanceClient.createMarketOrder(symbol, side, amount);
      } else if (type === "limit" && price) {
        order = await binanceClient.createLimitOrder(symbol, side, amount, price);
      } else if (type === "stop_loss" && stopPrice) {
        order = await binanceClient.createOrder(symbol, "stop_loss", side, amount, undefined, {
          stopPrice
        });
      }

      return {
        success: true,
        order: {
          id: order.id,
          symbol: order.symbol,
          side: order.side,
          type: order.type,
          price: order.price || order.average,
          amount: order.amount,
          filled: order.filled,
          status: order.status,
          timestamp: order.timestamp
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
};

/**
 * Tool: binance_cancel_order
 * Cancela una orden pendiente
 */
export const cancelOrderTool: MCPTool = {
  name: "binance_cancel_order",
  description: "Cancela una orden pendiente",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de trading"
      },
      orderId: {
        type: "string",
        description: "ID de la orden a cancelar"
      }
    },
    required: ["symbol", "orderId"]
  },
  riskLevel: "MEDIUM",
  handler: async ({ symbol, orderId }) => {
    try {
      const result = await binanceClient.cancelOrder(orderId, symbol);
      return {
        success: true,
        cancelledOrder: {
          id: result.id,
          symbol: result.symbol,
          status: "CANCELLED"
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
};

/**
 * Tool: binance_cancel_all_orders
 * Cancela todas las ordenes de un simbolo
 */
export const cancelAllOrdersTool: MCPTool = {
  name: "binance_cancel_all_orders",
  description: "Cancela todas las ordenes pendientes de un simbolo",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de trading"
      }
    },
    required: ["symbol"]
  },
  riskLevel: "MEDIUM",
  handler: async ({ symbol }) => {
    try {
      const result = await binanceClient.cancelAllOrders(symbol);
      return {
        success: true,
        cancelledCount: result.length
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
};
```

#### 4. Futures Tools (High Risk)

```typescript
// tools/positions.ts

/**
 * Tool: binance_get_futures_positions
 * Obtiene posiciones abiertas en futuros
 */
export const getFuturesPositionsTool: MCPTool = {
  name: "binance_get_futures_positions",
  description: "Obtiene posiciones abiertas en Binance Futures",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo especifico (opcional)"
      }
    },
    required: []
  },
  handler: async ({ symbol }) => {
    // Cambiar a cliente de futuros
    const positions = await binanceFuturesClient.fetchPositions(symbol);

    const activePositions = positions.filter(p =>
      parseFloat(p.contracts) !== 0
    );

    return {
      positions: activePositions.map(p => ({
        symbol: p.symbol,
        side: parseFloat(p.contracts) > 0 ? 'LONG' : 'SHORT',
        size: Math.abs(parseFloat(p.contracts)),
        entryPrice: parseFloat(p.entryPrice),
        markPrice: parseFloat(p.markPrice),
        unrealizedPnL: parseFloat(p.unrealizedPnl),
        leverage: p.leverage,
        liquidationPrice: parseFloat(p.liquidationPrice),
        marginType: p.marginType
      })),
      count: activePositions.length
    };
  }
};

/**
 * Tool: binance_set_leverage
 * Configura el leverage para un simbolo
 */
export const setLeverageTool: MCPTool = {
  name: "binance_set_leverage",
  description: "Configura el nivel de leverage para un simbolo en Futures",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de trading"
      },
      leverage: {
        type: "number",
        description: "Nivel de leverage (1-125)",
        minimum: 1,
        maximum: 125
      }
    },
    required: ["symbol", "leverage"]
  },
  riskLevel: "HIGH",
  handler: async ({ symbol, leverage }) => {
    // Validar leverage maximo
    if (leverage > 20) {
      return {
        success: false,
        error: "LEVERAGE_TOO_HIGH",
        message: "Leverage mayor a 20x no recomendado por politica de riesgo"
      };
    }

    try {
      await binanceFuturesClient.setLeverage(leverage, symbol);
      return {
        success: true,
        symbol,
        leverage,
        message: `Leverage configurado a ${leverage}x`
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
};

/**
 * Tool: binance_close_position
 * Cierra una posicion de futuros
 */
export const closePositionTool: MCPTool = {
  name: "binance_close_position",
  description: "Cierra completamente una posicion de futuros. ALTO RIESGO.",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de la posicion a cerrar"
      }
    },
    required: ["symbol"]
  },
  riskLevel: "HIGH",
  requiresConfirmation: true,
  handler: async ({ symbol }) => {
    try {
      // Obtener posicion actual
      const positions = await binanceFuturesClient.fetchPositions(symbol);
      const position = positions.find(p =>
        p.symbol === symbol && parseFloat(p.contracts) !== 0
      );

      if (!position) {
        return {
          success: false,
          error: "NO_POSITION",
          message: `No hay posicion abierta para ${symbol}`
        };
      }

      const size = Math.abs(parseFloat(position.contracts));
      const side = parseFloat(position.contracts) > 0 ? 'sell' : 'buy';

      // Crear orden de cierre
      const order = await binanceFuturesClient.createMarketOrder(
        symbol,
        side,
        size,
        undefined,
        { reduceOnly: true }
      );

      return {
        success: true,
        closedPosition: {
          symbol,
          closedSize: size,
          closedSide: side === 'sell' ? 'LONG' : 'SHORT',
          realizedPnL: parseFloat(position.unrealizedPnl),
          orderId: order.id
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }
};
```

#### 5. Utility Tools

```typescript
// tools/utils.ts

/**
 * Tool: binance_get_exchange_info
 * Obtiene informacion del exchange
 */
export const getExchangeInfoTool: MCPTool = {
  name: "binance_get_exchange_info",
  description: "Obtiene informacion del exchange: simbolos disponibles, limites, etc.",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo especifico (opcional)"
      }
    },
    required: []
  },
  handler: async ({ symbol }) => {
    const markets = await binanceClient.loadMarkets();

    if (symbol) {
      const market = markets[symbol];
      if (!market) {
        return { error: `Symbol ${symbol} not found` };
      }
      return {
        symbol: market.symbol,
        base: market.base,
        quote: market.quote,
        precision: market.precision,
        limits: market.limits,
        active: market.active
      };
    }

    // Retornar resumen general
    const activeMarkets = Object.values(markets).filter(m => m.active);
    return {
      totalMarkets: activeMarkets.length,
      topMarkets: activeMarkets
        .filter(m => m.quote === 'USDT')
        .slice(0, 20)
        .map(m => m.symbol)
    };
  }
};

/**
 * Tool: binance_get_funding_rate
 * Obtiene funding rate actual (futures)
 */
export const getFundingRateTool: MCPTool = {
  name: "binance_get_funding_rate",
  description: "Obtiene el funding rate actual para un simbolo de futuros",
  inputSchema: {
    type: "object",
    properties: {
      symbol: {
        type: "string",
        description: "Simbolo de futuros (ej: BTCUSDT)"
      }
    },
    required: ["symbol"]
  },
  handler: async ({ symbol }) => {
    const funding = await binanceFuturesClient.fetchFundingRate(symbol);
    return {
      symbol,
      fundingRate: funding.fundingRate,
      fundingTimestamp: funding.fundingTimestamp,
      nextFundingTime: funding.nextFundingTimestamp,
      annualized: funding.fundingRate * 3 * 365 * 100 // Aproximado anualizado
    };
  }
};
```

---

## Seguridad

### Niveles de Riesgo

| Nivel | Herramientas | Requiere Confirmacion |
|-------|--------------|----------------------|
| **LOW** | get_ticker, get_klines, get_orderbook | No |
| **MEDIUM** | get_account, cancel_order | No |
| **HIGH** | create_order, close_position, set_leverage | SI |

### Middleware de Autorizacion

```typescript
// middleware/auth.ts

import { Request, Response, NextFunction } from 'express';

export const authMiddleware = async (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  // 1. Verificar API key del MCP client
  const mcpKey = req.headers['x-mcp-api-key'];
  if (!mcpKey || mcpKey !== process.env.MCP_API_KEY) {
    return res.status(401).json({ error: 'Invalid MCP API key' });
  }

  // 2. Verificar que Binance API keys estan configuradas
  if (!process.env.BINANCE_API_KEY || !process.env.BINANCE_API_SECRET) {
    return res.status(500).json({ error: 'Binance API not configured' });
  }

  next();
};
```

### Pre-Trade Risk Check

```typescript
// middleware/risk-check.ts

interface RiskCheckParams {
  symbol: string;
  side: 'buy' | 'sell';
  amount: number;
  price?: number;
}

export const performRiskCheck = async (params: RiskCheckParams) => {
  const { symbol, side, amount, price } = params;

  // 1. Verificar balance suficiente
  const balance = await binanceClient.fetchBalance();
  const quoteAsset = symbol.replace(/.*?(USDT|BUSD|USDC)$/, '$1');
  const available = balance.free[quoteAsset] || 0;

  const orderValue = price ? amount * price : amount * (await getCurrentPrice(symbol));

  if (side === 'buy' && available < orderValue) {
    return {
      allowed: false,
      reason: `Insufficient balance. Required: ${orderValue}, Available: ${available}`
    };
  }

  // 2. Verificar tamano maximo de orden
  const maxOrderValue = parseFloat(process.env.MAX_ORDER_VALUE_USDT || '1000');
  if (orderValue > maxOrderValue) {
    return {
      allowed: false,
      reason: `Order value ${orderValue} exceeds maximum ${maxOrderValue} USDT`
    };
  }

  // 3. Verificar limites diarios
  const dailyVolume = await getDailyTradingVolume();
  const maxDailyVolume = parseFloat(process.env.MAX_DAILY_VOLUME_USDT || '10000');
  if (dailyVolume + orderValue > maxDailyVolume) {
    return {
      allowed: false,
      reason: `Daily volume limit reached. Current: ${dailyVolume}, Limit: ${maxDailyVolume}`
    };
  }

  return { allowed: true };
};
```

---

## Configuracion

### Variables de Entorno

```bash
# .env.example

# === MCP Server ===
PORT=3606
MCP_API_KEY=your_mcp_api_key_here

# === Binance API ===
BINANCE_API_KEY=your_binance_api_key
BINANCE_API_SECRET=your_binance_api_secret

# === Network ===
BINANCE_TESTNET=true  # Usar testnet por defecto
BINANCE_FUTURES_TESTNET=true

# === Risk Limits ===
MAX_ORDER_VALUE_USDT=1000
MAX_DAILY_VOLUME_USDT=10000
MAX_LEVERAGE=20
MAX_POSITION_SIZE_PCT=5

# === Logging ===
LOG_LEVEL=info
LOG_FILE=logs/mcp-binance.log

# === Redis (para rate limiting) ===
REDIS_URL=redis://localhost:6379
```

### Configuracion de CCXT

```typescript
// config.ts

import ccxt from 'ccxt';

export const createBinanceClient = () => {
  const isTestnet = process.env.BINANCE_TESTNET === 'true';

  return new ccxt.binance({
    apiKey: process.env.BINANCE_API_KEY,
    secret: process.env.BINANCE_API_SECRET,
    sandbox: isTestnet,
    options: {
      defaultType: 'spot',
      adjustForTimeDifference: true,
    },
    enableRateLimit: true,
    rateLimit: 100
  });
};

export const createBinanceFuturesClient = () => {
  const isTestnet = process.env.BINANCE_FUTURES_TESTNET === 'true';

  return new ccxt.binance({
    apiKey: process.env.BINANCE_API_KEY,
    secret: process.env.BINANCE_API_SECRET,
    sandbox: isTestnet,
    options: {
      defaultType: 'future',
      adjustForTimeDifference: true,
    },
    enableRateLimit: true,
    rateLimit: 100
  });
};
```

---

## Implementacion

### Entry Point

```typescript
// src/index.ts

import express from 'express';
import { Server } from '@modelcontextprotocol/sdk/server';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio';
import { createBinanceClient, createBinanceFuturesClient } from './config';
import { registerTools } from './tools';
import { authMiddleware } from './middleware/auth';
import { loggingMiddleware } from './middleware/logging';
import logger from './utils/logger';

const app = express();
const PORT = process.env.PORT || 3606;

// Middleware
app.use(express.json());
app.use(loggingMiddleware);

// Health check
app.get('/health', (req, res) => {
  res.json({
    status: 'healthy',
    service: 'mcp-binance-connector',
    version: '1.0.0',
    testnet: process.env.BINANCE_TESTNET === 'true',
    timestamp: new Date().toISOString()
  });
});

// MCP Server setup
const server = new Server({
  name: 'trading-binance-mcp',
  version: '1.0.0'
}, {
  capabilities: {
    tools: {}
  }
});

// Initialize clients
const binanceClient = createBinanceClient();
const binanceFuturesClient = createBinanceFuturesClient();

// Register all tools
registerTools(server, binanceClient, binanceFuturesClient);

// Tool execution endpoint (HTTP fallback)
app.post('/tools/:toolName', authMiddleware, async (req, res) => {
  const { toolName } = req.params;
  const params = req.body;

  try {
    const result = await executeToolByName(toolName, params);
    res.json(result);
  } catch (error) {
    logger.error(`Tool execution failed: ${toolName}`, error);
    res.status(500).json({ error: error.message });
  }
});

// List available tools
app.get('/tools', (req, res) => {
  res.json({
    tools: getAllToolDefinitions()
  });
});

// Start HTTP server
app.listen(PORT, () => {
  logger.info(`MCP Binance Connector running on port ${PORT}`);
  logger.info(`Testnet mode: ${process.env.BINANCE_TESTNET === 'true'}`);
});

// Start MCP stdio transport
const transport = new StdioServerTransport();
server.connect(transport).catch((error) => {
  logger.error('MCP transport connection failed', error);
});

export default app;
```

### Dockerfile

```dockerfile
# Dockerfile

FROM node:20-alpine

WORKDIR /app

# Install dependencies
COPY package*.json ./
RUN npm ci --only=production

# Copy source
COPY . .

# Build TypeScript
RUN npm run build

# Environment
ENV NODE_ENV=production
ENV PORT=3606

EXPOSE 3606

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3606/health || exit 1

CMD ["node", "dist/index.js"]
```

---

## Testing

### Unit Tests

```typescript
// tests/unit/market.test.ts

import { getTickerTool, getKlinesTool } from '../../src/tools/market';

describe('Market Tools', () => {
  describe('getTickerTool', () => {
    it('should return ticker data for valid symbol', async () => {
      const result = await getTickerTool.handler({ symbol: 'BTCUSDT' });

      expect(result).toHaveProperty('symbol', 'BTCUSDT');
      expect(result).toHaveProperty('price');
      expect(result.price).toBeGreaterThan(0);
    });

    it('should handle invalid symbol', async () => {
      const result = await getTickerTool.handler({ symbol: 'INVALID' });

      expect(result).toHaveProperty('error');
    });
  });

  describe('getKlinesTool', () => {
    it('should return OHLCV data', async () => {
      const result = await getKlinesTool.handler({
        symbol: 'BTCUSDT',
        interval: '5m',
        limit: 10
      });

      expect(result.candles).toHaveLength(10);
      expect(result.candles[0]).toHaveProperty('open');
      expect(result.candles[0]).toHaveProperty('high');
      expect(result.candles[0]).toHaveProperty('low');
      expect(result.candles[0]).toHaveProperty('close');
      expect(result.candles[0]).toHaveProperty('volume');
    });
  });
});
```

### Integration Tests

```typescript
// tests/integration/binance-api.test.ts

import request from 'supertest';
import app from '../../src/index';

describe('MCP Binance Connector API', () => {
  const API_KEY = process.env.MCP_API_KEY;

  describe('GET /health', () => {
    it('should return healthy status', async () => {
      const res = await request(app).get('/health');

      expect(res.status).toBe(200);
      expect(res.body.status).toBe('healthy');
    });
  });

  describe('POST /tools/binance_get_ticker', () => {
    it('should return ticker data', async () => {
      const res = await request(app)
        .post('/tools/binance_get_ticker')
        .set('x-mcp-api-key', API_KEY)
        .send({ symbol: 'BTCUSDT' });

      expect(res.status).toBe(200);
      expect(res.body).toHaveProperty('symbol', 'BTCUSDT');
      expect(res.body).toHaveProperty('price');
    });
  });

  describe('POST /tools/binance_create_order', () => {
    it('should reject without confirmation', async () => {
      const res = await request(app)
        .post('/tools/binance_create_order')
        .set('x-mcp-api-key', API_KEY)
        .send({
          symbol: 'BTCUSDT',
          side: 'buy',
          amount: 0.001
        });

      // En testnet deberia funcionar, pero verificar risk check
      expect(res.status).toBe(200);
    });
  });
});
```

---

## Metricas y Monitoring

| Metrica | Target | Alerta |
|---------|--------|--------|
| Latency | <200ms | >500ms |
| Error Rate | <1% | >5% |
| Uptime | 99.9% | <99% |
| Rate Limit Usage | <80% | >90% |

---

**Documento Generado:** 2026-01-04
**Autor:** Orquestador Agent - Trading Platform
**Version:** 1.0.0
