Skip to main content
Glama

MCP Binance

by shukehi
server.js•9.74 kB
import express from 'express'; import cors from 'cors'; const app = express(); const PORT = process.env.PORT || 8080; // Configuration const PROTOCOL_VERSION = "2025-06-18"; const SERVER_NAME = "mcp-demo"; const SERVER_VERSION = "1.0.0"; // Middleware const ALLOWED_ORIGINS = [ 'https://chatgpt.com', 'https://chat.openai.com', 'https://platform.openai.com' ]; const DEFAULT_ALLOWED_HEADERS = [ 'Content-Type', 'Authorization', 'MCP-Protocol-Version', 'MCP-Client-ID', 'MCP-Connection-ID', 'MCP-Sequence-ID', 'MCP-Session-ID', 'MCP-Tenant-ID', 'OpenAI-Beta' ]; const ALLOWED_METHODS = ['GET', 'POST', 'OPTIONS']; app.use((req, res, next) => { if (req.method !== 'OPTIONS') { return next(); } const origin = req.headers.origin; if (!origin || !ALLOWED_ORIGINS.includes(origin)) { return res.sendStatus(403); } const requestHeaders = req.headers['access-control-request-headers']; res.header('Access-Control-Allow-Origin', origin); res.header('Access-Control-Allow-Credentials', 'true'); res.header('Access-Control-Allow-Methods', ALLOWED_METHODS.join(',')); res.header( 'Access-Control-Allow-Headers', requestHeaders || DEFAULT_ALLOWED_HEADERS.join(',') ); res.header('Vary', 'Origin'); res.sendStatus(204); }); app.use(cors({ origin: ALLOWED_ORIGINS, credentials: true, // Allow ChatGPT MCP browser clients to send their custom headers allowedHeaders: DEFAULT_ALLOWED_HEADERS, methods: ALLOWED_METHODS, optionsSuccessStatus: 204 })); app.use(express.json()); // MCP Protocol Handler app.post('/', async (req, res) => { const { jsonrpc, method, params = {}, id } = req.body; switch (method) { case 'initialize': res.json({ jsonrpc: '2.0', id, result: { protocolVersion: PROTOCOL_VERSION, capabilities: { logging: {}, prompts: { listChanged: false }, resources: { listChanged: false }, tools: { listChanged: false } }, serverInfo: { name: SERVER_NAME, title: 'MCP Demo Server', version: SERVER_VERSION } } }); break; case 'initialized': res.status(200).end(); break; case 'tools/list': res.json({ jsonrpc: '2.0', id, result: { tools: [ { name: 'search', title: 'Search', description: 'Search for information', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query' } }, required: ['query'], additionalProperties: false } }, { name: 'fetch', title: 'Fetch Data', description: 'Fetch data by ID', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Resource ID' } }, required: ['id'], additionalProperties: false } }, { name: 'calculate', title: 'Calculate', description: 'Perform calculations', inputSchema: { type: 'object', properties: { expression: { type: 'string', description: 'Math expression' } }, required: ['expression'], additionalProperties: false } }, { name: 'binance_klines', title: 'Binance K-Line Data', description: 'Fetch candlestick data from Binance public API', inputSchema: { type: 'object', properties: { symbol: { type: 'string', description: 'Trading pair symbol, e.g., BTCUSDT' }, interval: { type: 'string', description: 'K-line interval per Binance spec', default: '1h' }, limit: { type: 'integer', minimum: 1, maximum: 1000, description: 'Number of candles to return (max 1000)', default: 100 } }, required: ['symbol'], additionalProperties: false } } ] } }); break; case 'tools/call': const { name, arguments: args = {} } = params; let content; switch (name) { case 'search': // Mock search results content = [{ type: 'text', text: JSON.stringify([ { id: '1', title: 'Result 1', content: `Found: ${args.query}` }, { id: '2', title: 'Result 2', content: 'Additional result' } ]) }]; break; case 'fetch': // Mock fetch result content = [{ type: 'text', text: JSON.stringify({ id: args.id, title: `Resource ${args.id}`, content: `Data for ${args.id}`, timestamp: new Date().toISOString() }) }]; break; case 'calculate': // Simple calculator try { // WARNING: eval is dangerous! Use a proper math library in production const result = eval(args.expression.replace(/[^0-9+\-*/().\s]/g, '')); content = [{ type: 'text', text: `${args.expression} = ${result}` }]; } catch (error) { content = [{ type: 'text', text: `Error: Invalid expression` }]; } break; case 'binance_klines': { const symbol = String(args.symbol || '').toUpperCase().replace(/[^A-Z0-9]/g, ''); const interval = String(args.interval || '1h'); const limit = Math.min(Math.max(parseInt(args.limit ?? 100, 10) || 100, 1), 1000); const allowedIntervals = new Set([ '1m','3m','5m','15m','30m', '1h','2h','4h','6h','8h','12h', '1d','3d','1w','1M' ]); if (!symbol) { content = [{ type: 'text', text: 'Error: symbol is required' }]; break; } if (!allowedIntervals.has(interval)) { content = [{ type: 'text', text: `Error: interval must be one of ${Array.from(allowedIntervals).join(', ')}` }]; break; } try { const url = new URL('https://api.binance.com/api/v3/klines'); url.searchParams.set('symbol', symbol); url.searchParams.set('interval', interval); url.searchParams.set('limit', String(limit)); const response = await fetch(url, { headers: { 'Accept': 'application/json', 'User-Agent': 'crypto-mcp-demo' } }); if (!response.ok) { content = [{ type: 'text', text: `Error: Binance API responded with ${response.status}` }]; break; } const data = await response.json(); content = [{ type: 'text', text: JSON.stringify({ symbol, interval, limit, candles: data.map(([openTime, open, high, low, close, volume, closeTime]) => ({ openTime, open, high, low, close, volume, closeTime })) }) }]; } catch (error) { content = [{ type: 'text', text: `Error: Failed to fetch Binance data (${error.message})` }]; } } break; default: return res.json({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name}` } }); } res.json({ jsonrpc: '2.0', id, result: { content, isError: false } }); break; case 'resources/list': res.json({ jsonrpc: '2.0', id, result: { resources: [], nextCursor: null } }); break; case 'prompts/list': res.json({ jsonrpc: '2.0', id, result: { prompts: [ { name: 'analyze_code', description: 'Analyze code quality', arguments: [ { name: 'code', description: 'Code to analyze', required: true } ] } ] } }); break; default: res.json({ jsonrpc: '2.0', id, error: { code: -32601, message: 'Method not found' } }); } }); // Health check endpoint app.get('/', (req, res) => { res.json({ name: SERVER_NAME, version: SERVER_VERSION, protocol: PROTOCOL_VERSION, status: 'running' }); }); app.listen(PORT, () => { console.log(`🚀 MCP Server running on port ${PORT}`); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shukehi/crypto-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server