A comprehensive Model Context Protocol server for Zerodha trading platform integration, providing tools for holdings, positions, orders, GTT triggers, margins, and mutual funds management
Output schemas not formally documented. Tools return JSON responses (inferred from code), but the MCP server does not provide explicit output schema definitions. Agents cannot see what fields to expect without calling the tool first, preventing proper planning and field extraction.
Many read-only tools return unbounded or very large result sets without pagination. zerodha_get_holdings, zerodha_get_positions, zerodha_get_gtts, zerodha_get_mf_holdings return all results in one call. No limit param, no offset/cursor. A user with 500+ holdings or GTTs will bloat the response and context window.
Document output schemas for all tools. Use JSON Schema to declare response fields, types, and required properties. Example: zerodha_get_holdings should document { summary: { total_holdings: int, total_invested: float, ... }, holdings: [ { symbol: string, quantity: int, ... } ] }. This enables agents to plan field extraction before calling.
Add pagination support to list/get tools that return multiple results. Add 'limit' (default 20, max 100) and 'offset' or 'cursor' parameters to zerodha_get_holdings, zerodha_get_positions, zerodha_get_gtts, zerodha_get_mf_holdings, zerodha_get_mf_orders, zerodha_get_sips. Document total_count and next_cursor in responses.
Implement error classification and recovery guidance. Instead of raw exceptions, return structured errors: { error_type: 'retryable'|'user_fixable'|'fatal', message: '...', suggestion: '...' }. Example: 'Insufficient funds: available cash INR 50000, required INR 75000. Call zerodha_get_margins() to check balance.' This guides LLM retry logic.
Add confirmation/dry-run support for destructive operations. Introduce a 'dry_run' param (default false) for zerodha_place_order, zerodha_cancel_order, zerodha_delete_gtt, and SIP/MF operations. When dry_run=true, return simulated result without executing. This prevents accidental live trades.
Define JSON Schema enums for constrained string parameters. Add enum constraints to transaction_type (BUY, SELL), order_type (MARKET, LIMIT, STOP, STOP_LIMIT), product (MIS, CNC, CO, BO), validity (DAY, IOC, GTD, GTC), gtt_type (single, oco), frequency (monthly, quarterly, half_yearly, yearly). LLMs will validate input against enums.
Error handling is generic and non-actionable. _handle_api_error() catches exceptions but does not categorize errors as retryable, user-fixable, or fatal. LLMs receive raw errors with no guidance on recovery (e.g., 'Connection timeout' vs 'Invalid order parameters'). No error classification or remediation hints.
Destructive operations (place_order, cancel_order, delete_gtt, cancel_mf_order, cancel_sip) have no dry-run or confirmation mechanism. Agents can execute real trades on live accounts with no safety gate. zerodha_place_order annotation warns ⚠️ but there is no confirmation-request pattern implementation.
Parameter descriptions are sparse or missing for complex input objects. zerodha_create_gtt and zerodha_create_sip accept 'orders' as an array of objects, but the description does not explain the structure of each order object (required fields, constraints, dependencies). LLMs must guess the correct payload shape.
Enums for constrained parameters are not defined in schemas. Fields like 'transaction_type' (BUY|SELL), 'order_type' (MARKET|LIMIT), 'product' (MIS|CNC), 'validity' (DAY|IOC), 'gtt_type' (single|oco) are free-form strings with no enum constraint. LLMs can hallucinate invalid values ('MARKET_LIMIT', 'immediate', 'perpetual'). No schema validation prevents misuse.
Login flow complexity and OAuth callback server initialization (start_callback_server(5000)) may fail silently or conflict if port 5000 is in use. zerodha_get_login_url and zerodha_complete_login do not document the OAuth flow or prerequisites. A user/agent must understand callback mechanics and manual request_token handling.
Field naming inconsistencies between related tools. zerodha_get_orders returns 'symbol' and 'exchange', but zerodha_place_order accepts 'tradingsymbol' and 'exchange'. Agents must map between different field names. zerodha_get_margins returns 'available_margin' but zerodha_calculate_margin takes 'price' and 'quantity', unclear field correspondence.
No audit logging or permission checks visible in code. Tools accept API requests and execute trades without verifying the user identity or permissions. No logging of who called what tool, with which parameters, at what time. Compliance and incident response will be difficult.
Document the structure of nested objects (e.g., 'orders' array in zerodha_create_gtt, 'orders' array in zerodha_calculate_basket_margin). Provide example payloads or JSON Schema sub-schemas. Example: orders is an array of { exchange, tradingsymbol, transaction_type, variety, product, order_type, quantity, price, trigger_price }.
Normalize parameter names across related tools. Use 'tradingsymbol' consistently in all tools (not 'symbol' in get_orders response). Return 'tradingsymbol' and 'exchange' from list tools so agents can chain directly to place_order without field mapping.
Add audit logging: log tool invocations with timestamp, caller ID, tool name, parameters (excluding secrets), result/error, and execution time. Store logs in a secure, queryable store (e.g., database, syslog). This enables compliance, debugging, and incident post-mortems.
Document OAuth prerequisites and callback server behavior in zerodha_get_login_url and zerodha_complete_login. Explain that port 5000 must be available, provide the callback URL, and describe the manual request_token flow if auto-callback fails. This prevents setup confusion.
Add rate limiting to prevent agent runaway loops. Implement per-user request quotas (e.g., max 10 place_order calls per minute) and return clear rate-limit-exceeded errors with retry guidance. Protect against accidental high-frequency trading.
Remove or redact sensitive fields from responses. Ensure API tokens, session IDs, or internal trade IDs do not appear in tool outputs. Every field in responses enters the LLM context and could be logged or echoed.
Add parameter validation with actionable error messages. Instead of a 500 error, validate quantity > 0, price > 0, transaction_type in (BUY, SELL), etc. Return 'Invalid quantity: must be >= 1, got 0' so LLMs can self-correct immediately.