Skip to main content
Glama
ssonthal

Zerodha Trading Bot - MCP Server

by ssonthal
mcp-server.js9.71 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { ZerodhaClient } from './zerodha-client.js'; import dotenv from 'dotenv'; dotenv.config(); class ZerodhaMCPServer { constructor() { this.zerodhaClient = new ZerodhaClient( process.env.ZERODHA_API_KEY, process.env.ZERODHA_API_SECRET, process.env.ZERODHA_REDIRECT_URI ); this.server = new Server( { name: 'zerodha-trading-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); this.setupToolHandlers(); } setupToolHandlers() { // Tool: Get login URL this.server.setRequestHandler('tools/call', async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'get_login_url': return { content: [ { type: 'text', text: this.zerodhaClient.getLoginURL() } ] }; case 'authenticate': const { requestToken } = args; const tokens = await this.zerodhaClient.getAccessToken(requestToken); return { content: [ { type: 'text', text: JSON.stringify(tokens, null, 2) } ] }; case 'get_user_profile': const profile = await this.zerodhaClient.getUserProfile(); return { content: [ { type: 'text', text: JSON.stringify(profile, null, 2) } ] }; case 'get_holdings': const holdings = await this.zerodhaClient.getHoldings(); return { content: [ { type: 'text', text: JSON.stringify(holdings, null, 2) } ] }; case 'get_positions': const positions = await this.zerodhaClient.getPositions(); return { content: [ { type: 'text', text: JSON.stringify(positions, null, 2) } ] }; case 'get_quote': const { symbols } = args; const quote = await this.zerodhaClient.getQuote(symbols); return { content: [ { type: 'text', text: JSON.stringify(quote, null, 2) } ] }; case 'place_order': const orderResult = await this.zerodhaClient.placeOrder(args); return { content: [ { type: 'text', text: JSON.stringify(orderResult, null, 2) } ] }; case 'get_order_history': const orders = await this.zerodhaClient.getOrderHistory(); return { content: [ { type: 'text', text: JSON.stringify(orders, null, 2) } ] }; case 'cancel_order': const { orderId } = args; const cancelResult = await this.zerodhaClient.cancelOrder(orderId); return { content: [ { type: 'text', text: JSON.stringify(cancelResult, null, 2) } ] }; case 'get_margins': const margins = await this.zerodhaClient.getMargins(); return { content: [ { type: 'text', text: JSON.stringify(margins, null, 2) } ] }; case 'validate_token': const isValid = await this.zerodhaClient.validateToken(); return { content: [ { type: 'text', text: JSON.stringify({ isValid }, null, 2) } ] }; default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Error: ${error.message}` } ] }; } }); // Tool definitions this.server.setRequestHandler('tools/list', async () => { return { tools: [ { name: 'get_login_url', description: 'Get the login URL for Zerodha OAuth authentication', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'authenticate', description: 'Authenticate with Zerodha using request token', inputSchema: { type: 'object', properties: { requestToken: { type: 'string', description: 'Request token received from Zerodha OAuth' } }, required: ['requestToken'] } }, { name: 'get_user_profile', description: 'Get the current user profile from Zerodha', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'get_holdings', description: 'Get current holdings from Zerodha', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'get_positions', description: 'Get current positions from Zerodha', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'get_quote', description: 'Get live quotes for symbols', inputSchema: { type: 'object', properties: { symbols: { type: 'string', description: 'Comma-separated list of symbols (e.g., "NSE:RELIANCE,NSE:TCS")' } }, required: ['symbols'] } }, { name: 'place_order', description: 'Place a trading order on Zerodha', inputSchema: { type: 'object', properties: { tradingsymbol: { type: 'string', description: 'Trading symbol (e.g., "RELIANCE")' }, exchange: { type: 'string', description: 'Exchange (NSE, BSE)', default: 'NSE' }, transaction_type: { type: 'string', description: 'BUY or SELL', enum: ['BUY', 'SELL'] }, quantity: { type: 'integer', description: 'Quantity to trade' }, product: { type: 'string', description: 'Product type (CNC, MIS, NRML)', default: 'MIS' }, order_type: { type: 'string', description: 'Order type (MARKET, LIMIT, SL, SL-M)', default: 'MARKET' }, price: { type: 'number', description: 'Price for limit orders' }, trigger_price: { type: 'number', description: 'Trigger price for stop loss orders' } }, required: ['tradingsymbol', 'transaction_type', 'quantity'] } }, { name: 'get_order_history', description: 'Get order history from Zerodha', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'cancel_order', description: 'Cancel an existing order', inputSchema: { type: 'object', properties: { orderId: { type: 'string', description: 'Order ID to cancel' } }, required: ['orderId'] } }, { name: 'get_margins', description: 'Get margin information from Zerodha', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'validate_token', description: 'Validate if the current access token is still valid', inputSchema: { type: 'object', properties: {}, required: [] } } ] }; }); } async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.log('Zerodha MCP Server started'); } } // Start the server const server = new ZerodhaMCPServer(); server.start().catch(console.error);

Latest Blog Posts

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/ssonthal/ZerodhaTradingBot-MCPServer'

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