MCP server for managing Zerodha trading accounts, orders, portfolio, and positions
This server has 12 tools with partial schema and description coverage. Most tools have clear action-verb naming (get_, place_, modify_, cancel_) which is good. However, critical issues emerge: (1) ALL tools return plain strings (str()) instead of structured JSON objects, violating the response-shaper pattern. (2) Most parameter schemas lack proper type constraints and enums, e.g., place_order's 'exchange', 'product', 'order_type', 'transaction_type', and 'validity' parameters accept free-form strings with no enums despite known valid values. (3) No output schemas are documented, callers don't know what fields to expect from returned data. (4) Error handling is absent, no guidance for LLMs on recovery actions. (5) Parameter descriptions lack constraint details (e.g., 'segment' says 'equity' or 'commodity' but these aren't enforced as enums). The descriptions themselves are moderately detailed but buried in docstrings rather than parameter-level metadata. Tool naming is strong, but the schemas and output structure are weak.
Cancel an existing order.
Get the access token for the user.
Get the user's portfolio holdings from Zerodha. Retrieves detailed information about all securities currently held in the portfolio, including: Trading symbol, Exchange, ISIN code, Product (CNC, MIS, etc.), Average price, Last price, Quantity, PnL (Profit and Loss), Close price, Value
Get the login URL for the user. Use this to get the login URL for the user and then redirect the user to the login URL to get the request token.
Get the user's available margins and fund details from Zerodha. Retrieves information including: Available cash balance, Used margin, Available margin, Opening balance, Margin utilized for various segments (equity, commodity, etc), Collateral value, Margin categories (SPAN, exposure, etc)
All tools return str(dict) instead of structured JSON. Returns like 'return str(orders)' convert data to string representation, forcing LLMs to parse text rather than working with typed fields. This violates response-shaper and adds parsing overhead.
Missing output schemas for all tools. Callers (LLMs) have no documentation of what fields to expect. E.g., get_user_profile says it returns 'user profile information' but never lists which fields (user_id, username, email, etc.) are present. This forces agents to infer structure from stringified output.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 53 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 41 | - | v1 |
Get history of an order. Retrieves detailed information about all states an order has gone through, including: Order ID, Exchange order ID, Status of the order at each state (OPEN, COMPLETE, REJECTED, CANCELLED, etc), Filled quantity at each state, Pending quantity at each state, Average price at each state, Exchange update timestamps
Get trades generated by an order. An order can be executed in multiple trades. Use this to get all trades linked to an order.
Get all orders placed for the day. Retrieves detailed information about all orders placed during the current day, including: Order ID, Exchange order ID, Parent order ID (for bracket orders), Status of the order (COMPLETE, REJECTED, CANCELLED, etc), Exchange, Trading symbol, Order type (MARKET, LIMIT, etc), Transaction type (BUY or SELL), Product code (CNC, MIS, etc), Quantity, Price, Trigger price (for SL and SL-M orders), Average price, Filled quantity, Pending quantity, Order timestamp, Exchange timestamp, Order variety (regular, amo, bo, co, etc)
Get the user's current positions from Zerodha. Retrieves information about all open positions, including: Day positions, Net positions, Trading symbol, Exchange, Product type, Quantity, Average price, Last price, PnL (Profit and Loss), Overnight quantity, Multiplier
Get the authenticated user's Zerodha profile information. Retrieves details like: User ID, User name, Email, Trading experience, Products enabled, Order types allowed, Exchange memberships, Account activation status
Modify an existing order.
Place a new order on Zerodha.
Parameters lack enum constraints despite known valid values. 'exchange' in place_order accepts any string but should constrain to [NSE, BSE, NFO, etc.]. 'product' should be [CNC, MIS, etc.]. 'order_type' should be [MARKET, LIMIT, SL, SL-M]. 'transaction_type' should be [BUY, SELL]. 'validity' should be [DAY, IOC, etc.]. Descriptions mention valid values but schemas don't enforce them, inviting hallucinated values.
No error handling guidance. Tools have no documented error states or recovery steps. If place_order fails (insufficient margin, invalid symbol, market closed), the LLM receives no hint about what to do next. No error categorization (retryable vs. user-fixable vs. fatal).
Parameter descriptions lack constraint details. E.g., 'segment' in get_margins says 'Valid values are: equity, commodity' in prose but doesn't specify if null/empty defaults to all segments or fails. 'quantity' in place_order has no min/max bounds. 'price' has no guidance on decimal precision or rounding.
Incomplete parameter descriptions for mutation tools. 'modify_order' description is only 35 chars, 'Modify an existing order.', and doesn't explain which fields can be changed, whether partial updates are allowed, or what happens to unspecified fields. LLMs don't infer; they need explicit details.
No pagination support. 'get_orders', 'get_holdings', 'get_positions' return all items without limit, offset, or pagination fields. If a user has 500 orders, the entire list is dumped, wasting tokens and risking context overflow. No result limit is documented.
Authentication state management is unclear. 'get_access_token' calls 'kite.set_access_token(data['access_token'])', storing the token on the global kite instance. This implies stateful session handling. If multiple concurrent requests arrive, token conflicts or race conditions could occur. No documentation of session lifecycle or concurrency guarantees.