ML Engine Updates: - Updated BTCUSD with Polygon API data (2024-2025): 215,699 new records - Re-trained all ML models: Attention (R²: 0.223), Base, Metamodel (87.3% confidence) - Backtest results: +176.71R profit with aggressive_filter strategy Documentation Consolidation: - Created docs/99-analisis/_MAP.md index with 13 new analysis documents - Consolidated inventories: removed duplicates from orchestration/inventarios/ - Updated ML_INVENTORY.yml with BTCUSD metrics and training results - Added execution reports: FASE11-BTCUSD, correction issues, alignment validation Architecture & Integration: - Updated all module documentation with NEXUS v3.4 frontmatter - Fixed _MAP.md indexes across all folders - Updated orchestration plans and traces Files: 229 changed, 5064 insertions(+), 1872 deletions(-) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
32 KiB
32 KiB
| id | title | type | project | version | created_date | updated_date | author |
|---|---|---|---|---|---|---|---|
| MCP-BINANCE-CONNECTOR-SPEC | Especificacion MCP Binance Connector | Technical Specification | trading-platform | 1.0.0 | 2026-01-04 | 2026-01-04 | 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
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
{
"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)
// 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)
// 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)
// 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)
// 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
// 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
// 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
// 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
# .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
// 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
// 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
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
// 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
// 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