MCP server for Angel One's SmartAPI (trading, portfolio, market data, GTT, margins)
Server has 22 tools with consistent naming (verb_noun pattern) and descriptions present for all. However, parameter schemas lack type constraints (enums, ranges), descriptions are often generic, and output schemas are undocumented. Error handling is minimal, most tools return raw API responses wrapped in JSON without recovery guidance. No tool annotations (readOnlyHint/destructiveHint) despite clear risk levels. Descriptions average ~120 chars, below the 194-char baseline for A+ tools. Parameters lack format constraints and dependency documentation.
Cancel an open order by its order id. variety: NORMAL | STOPLOSS | AMO | ROBO
Convert a position from one product type to another (e.g. INTRADAY -> DELIVERY).
Get holdings plus a portfolio-level summary (total investment, current value, P&L).
Get the equity holdings currently in the demat account.
Get full lifecycle detail/history for a single order by its unique order id.
Get the last traded price (LTP) for a single instrument.
No enum constraints on order/GTT parameters. Tools like place_order accept 'variety', 'ordertype', 'producttype', 'exchange' as free-form strings without enums. LLMs will hallucinate invalid values (e.g. 'MARKET_LIMIT' instead of 'LIMIT'). All 8 order/GTT tools affected.
Output schemas completely undocumented. Tools return JSON via _fmt(fn(...)) but no schema describes what fields are in the response. LLMs cannot plan downstream calls or extract required IDs (e.g. order_id from place_order response). Affects all 22 tools.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 64 | 2026-07-28+ | v2 |
Get market quotes for up to 50 instruments per exchange in one call. mode: LTP | OHLC | FULL exchange_tokens: e.g. {"NSE": ["3045", "881"], "NFO": ["58662"]} - a map of exchange -> list of symbol tokens.
Get all orders placed today, with their current status.
Get the day's open and net positions (intraday + carryforward).
Get the logged-in user's profile: client code, name, email, exchanges enabled, products enabled, and broker.
Get available margin / funds (RMS limits): net cash, available margin, utilised margin, etc.
Get all executed trades for the day.
Cancel a GTT rule by its id.
Create a GTT (Good Till Triggered) rule that auto-places an order when the trigger price is hit.
Get details of a single GTT rule by id.
List GTT rules. status is a list of any of: NEW, CANCELLED, ACTIVE, SENTTOEXCHANGE, FORALL, REJECTED, EXPIRED, DELETED.
Modify an existing GTT rule.
Explicitly (re)authenticate with Angel One using the configured client code, PIN, and TOTP secret. Normally not needed - the client logs in automatically on first use - but useful to force a fresh session or verify credentials are configured correctly.
Terminate the current Angel One trading session.
Modify an existing open order. All identifying fields (tradingsymbol, symboltoken, exchange) must match the original order.
Place an order. variety: NORMAL | STOPLOSS | AMO | ROBO transactiontype: BUY | SELL exchange: NSE | BSE | NFO | MCX | BFO | CDS ordertype: MARKET | LIMIT | STOPLOSS_LIMIT | STOPLOSS_MARKET producttype: DELIVERY | CARRYFORWARD | MARGIN | INTRADAY | BO duration: DAY | IOC price/triggerprice: required for LIMIT/STOPLOSS order types (as strings, e.g. "199.50") squareoff/stoploss/trailingStopLoss: only used when variety=ROBO (bracket order)
Search for the tradingsymbol and symboltoken of an instrument by name, e.g. exchange='NSE', searchscrip='INFY'. Use this to resolve symboltoken before placing orders or requesting quotes.
No tool annotations (readOnlyHint/destructiveHint/idempotentHint). Tools are marked with Risk levels (READ_ONLY, REVERSIBLE, IRREVERSIBLE) in the spec but not exposed in MCP schema. LLMs cannot distinguish safe reads from destructive writes without parsing descriptions.
Parameter descriptions lack format/constraint details. E.g. 'quantity' is just 'Order quantity' with no min/max. 'price' is 'Order price' with no decimal places or range. 'page' in gtt_list has no bounds. LLMs will pass invalid values (negative quantities, absurd prices).
Error handling returns raw API errors wrapped in JSON without recovery guidance. E.g. 'status: false, error: "Invalid order"' gives LLM no actionable next step. No distinction between retryable (network timeout) vs user-fixable (invalid symbol) vs fatal errors.