trackmcp
Back to directory
pyalgobot

angelone-mcp

View on GitHub

An MCP (Model Context Protocol) server that wraps Angel One's SmartAPI

0 stars PythonOthers Updated Aug 29, 2026
equity-marketsfinancemcp-server

Documentation

angelone-mcp

Listed on mcpservers.org

An MCP (Model Context Protocol) server that wraps Angel One's SmartAPI

trading, portfolio, market data, GTT rules, and margin/brokerage — so any MCP

client (Claude, Claude Code, etc.) can query your account and place orders

through natural conversation.

⚠️ This places real orders on a real trading account. Test with small

quantities first, and keep in mind Angel One (like most brokers) does not

let you "undo" a filled order.

What's included

  • `angelone_mcp/client.py` – REST client for every documented SmartAPI route:

auth, orders, positions/holdings, GTT rules, historical candles/OI,

quotes, option greeks, gainers/losers, margin calculator, brokerage

estimator. Handles TOTP login, auto re-login on token expiry, and paces

itself against SmartAPI's documented rate limits (see "Rate limiting"

below).

  • `angelone_mcp/server.py` – MCP server exposing 32 tools built on top of

the client (see full list below).

1. Prerequisites

  • Python 3.10+
  • An Angel One trading account with SmartAPI access
  • A SmartAPI app created at https://smartapi.angelone.in/ (gives you an API key)
  • TOTP set up on your Angel One account, and the base32 secret used to

set up that authenticator (not the 6-digit code — the secret behind it).

You get this once, when you first scan the QR code to enable TOTP; if you

don't have it saved, you'll need to reset/reconfigure TOTP on your account

to get a fresh secret.

2. Install

bash
cd angelone-mcp
python3 -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -r requirements.txt

3. Configure credentials

Set these environment variables (e.g. in a `.env` file you source, or

directly in your MCP client config):

VariableDescription
`ANGELONE_API_KEY`API key from your SmartAPI app
`ANGELONE_CLIENT_CODE`Your Angel One client/trading account code
`ANGELONE_PIN`Your login PIN
`ANGELONE_TOTP_SECRET`Base32 TOTP secret for your account

Never commit these to source control. Treat `ANGELONE_TOTP_SECRET` and

`ANGELONE_PIN` like passwords — anyone with them plus your API key can trade

on your account.

Optional: running behind an HTTP proxy

If your machine/network requires an outbound HTTP proxy to reach the

internet, set:

VariableDescription
`ANGELONE_HTTP_PROXY`Proxy URL used for `http://` requests, e.g. `http://user:pass@proxyhost:8080`
`ANGELONE_HTTPS_PROXY`Proxy URL used for `https://` requests (this is the one that matters — SmartAPI is https-only). Falls back to `ANGELONE_HTTP_PROXY` if unset.
`ANGELONE_NO_PROXY`Optional comma-separated list of hosts to bypass the proxy for

These are only needed if the standard `HTTP_PROXY` / `HTTPS_PROXY` environment

variables aren't already visible to the server process. That's commonly the

case for MCP servers, since MCP clients usually launch the server with an

explicit `env` block (like the JSON below) instead of inheriting your shell's

environment — so a proxy configured in your shell won't reach the server

unless you either add it to that `env` block yourself under `HTTPS_PROXY`, or

use the `ANGELONE_*` variables above. If neither `ANGELONE_HTTP_PROXY` nor

`ANGELONE_HTTPS_PROXY` is set, the server falls back to the standard

`HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` variables automatically.

4. Run it

Standalone (for testing):

bash
python -m angelone_mcp.server

It speaks MCP over stdio, so it's meant to be launched by an MCP client, not

run interactively.

Claude Desktop / Claude Code config

Add to your MCP client's config (e.g. `claude_desktop_config.json`):

json
{
  "mcpServers": {
    "angelone": {
      "command": "/absolute/path/to/angelone-mcp/.venv/bin/python",
      "args": ["-m", "angelone_mcp.server"],
      "cwd": "/absolute/path/to/angelone-mcp",
      "env": {
        "ANGELONE_API_KEY": "your_api_key",
        "ANGELONE_CLIENT_CODE": "your_client_code",
        "ANGELONE_PIN": "your_pin",
        "ANGELONE_TOTP_SECRET": "your_base32_totp_secret",
        "ANGELONE_HTTPS_PROXY": "http://user:pass@proxyhost:8080"
      }
    }
  }
}

Tools exposed

Session

`login`, `logout`, `get_profile`

Orders

`place_order`, `modify_order`, `cancel_order`, `get_order_book`,

`get_trade_book`, `get_individual_order_details`

Portfolio / funds

`get_positions`, `get_holdings`, `get_all_holdings`, `get_rms_limit`,

`convert_position`

GTT (Good Till Triggered) rules

`gtt_create_rule`, `gtt_modify_rule`, `gtt_cancel_rule`, `gtt_details`,

`gtt_list`

Market data

`get_ltp`, `get_market_quote`, `search_scrip`, `get_candle_data`,

`get_oi_data`, `get_option_greeks`, `get_gainers_losers`,

`get_put_call_ratio`, `get_oi_buildup`, `get_nse_intraday_data`,

`get_bse_intraday_data`

Margin & brokerage

`get_margin`, `estimate_charges`

How auth works

`AngelOneClient` logs in lazily on the first tool call using

`clientcode` + `pin` + a TOTP generated on the fly from

`ANGELONE_TOTP_SECRET` (via `pyotp`). It caches the resulting `jwtToken`,

`refreshToken`, and `feedToken` in memory for the life of the process. If any

call comes back with a 401/403 or a `TokenException`, it transparently

re-logs-in once and retries — you don't need to call `login` yourself unless

you want to force a fresh session.

Sessions issued by SmartAPI are valid until midnight IST regardless of

activity, so a long-running server may still need a fresh login the next day

— the auto-retry logic handles that automatically on the next call.

Session persistence across restarts

A successful login is also cached to a file on disk, so a fresh server

process doesn't need a fresh TOTP-based login every time it starts (handy

since TOTP requires the code to be freshly generated — restarting the server

several times in a row otherwise means several real logins in a row).

On startup, before serving any tool calls, the server calls

`AngelOneClient.restore_session()`, which:

1. Looks for a previously saved session file. If there isn't one, it does

nothing further — the client stays in its normal lazy mode and logs in on

the first tool call, same as before this feature existed.

2. If a saved session is found, it loads the cached tokens and verifies them

with a real `getProfile` call.

3. If that verification succeeds, the restored session is used as-is — no

fresh login needed.

4. If it fails for any reason (expired token, revoked session, corrupt file,

etc.), the cached tokens are discarded and a normal fresh login runs

instead.

Every successful login (fresh or via the automatic 401/403 retry described

above) re-saves the session file, so it stays current across the whole time

the server runs, not just at startup. `logout` deletes the file.

VariableDescription
`ANGELONE_SESSION_PERSIST`Set to `false`/`0`/`no`/`off` to disable session persistence entirely (default: enabled)
`ANGELONE_SESSION_FILE`Override the file path used to persist the session. Default: a file under the OS temp directory, named from a hash of your client code (so multiple accounts on the same machine don't collide)

The session file holds a live access token — not your PIN or TOTP secret,

but enough to call the API as you until it expires. It's written with

owner-only file permissions where the OS supports it; treat it as sensitive

the same way you'd treat any cached login session.

Rate limiting

`AngelOneClient` paces every outgoing call against

SmartAPI's documented per-endpoint rate limits

— login and most portfolio reads at 1 request/sec, `getProfile` at 3/sec,

quotes/GTT/order-detail lookups at 10/sec, order placement at 20/sec, and so

on. Limits are per SmartAPI endpoint, not global, so calling different tools

back-to-back is never slowed down by this — only a *repeat* call to the same

endpoint made faster than SmartAPI's own limit allows gets held back, which

you'd want anyway.

If SmartAPI reports its own limit was hit regardless (HTTP 403/429, "Access

denied because of exceeding access rate"), the call backs off and retries a

few times with increasing delay before giving up — and that response no

longer gets misread as an expired session and doesn't trigger a spurious

extra login the way it used to.

This applies to every tool automatically; there's nothing to configure to

get it. To turn client-side pacing off entirely (SmartAPI still enforces its

own limits server-side either way — this only controls whether the client

tries to stay under them proactively):

VariableDescription
`ANGELONE_RATE_LIMIT_DISABLED`Set to `true`/`1`/`yes`/`on` to disable proactive pacing (default: enabled)

Testing

bash
pip install -e ".[test]"

# Offline: verifies the server registers the expected tools. No credentials
# or network access needed.
python -m pytest tests/test_tool_registration.py -v

# Offline: unit tests for session persistence (login state cached to disk,
# restored + verified via get_profile on restart, falls back to a fresh
# login when the cache is missing/invalid). Uses a fake HTTP layer - no
# credentials or network access needed.
python -m pytest tests/test_session_persistence.py -v

# Offline: unit tests for AngelOneClient's own rate limiting (pacing per
# ROUTE_MIN_INTERVAL, backoff/retry on a 403/429 rate-limit response, and
# that such a response is never misread as an expired session). Uses a fake
# HTTP layer - no credentials or network access needed.
python -m pytest tests/test_client_rate_limiting.py -v

# Live, read-only smoke test against your real account. Calls get_profile,
# get_order_book, get_holdings, search_scrip, get_ltp, etc. through the
# actual MCP server subprocess, plus a check that a session survives a
# restart of the server without calling the "login" tool again. Never calls
# place_order/modify_order/cancel_order/gtt_create_rule/gtt_modify_rule/
# gtt_cancel_rule/convert_position/logout - a SafeSession wrapper
# hard-asserts those are never invoked. On top of the server's own rate
# limiting (see "Rate limiting" above), the test itself also paces its tool
# calls and backs off/retries if the API reports one was hit anyway (see
# "Rate limiting in the live test" below) - belt and suspenders. Requires
# ANGELONE_API_KEY/ANGELONE_CLIENT_CODE/ANGELONE_PIN/ANGELONE_TOTP_SECRET
# to be set; skips automatically if they aren't.
python -m pytest tests/test_readonly_live.py -v -s
# or, for a plain-text report without pytest:
python tests/test_readonly_live.py

Rate limiting in the live test

The live test (`tests/test_readonly_live.py`) calls a real account against

the real SmartAPI. The server it drives already paces itself (see "Rate

limiting" above), but the test adds its own independent pacing on top -

useful because it also exercises things the server-side limiter doesn't see

by itself, like two separate server subprocesses (the session-persistence

check) hitting the same account back to back:

  • A `RateLimiter` tracks the last time each MCP tool was called and, before

calling it again, waits out the rest of that endpoint's minimum interval

(1/req-per-second-limit, plus a ~20% safety margin). Distinct tools hit

distinct SmartAPI endpoints with independent limits, so this only ever

delays a *repeat* call to the same tool (e.g. `get_profile` being called

again by the second server spawn in the session-persistence check) - a

normal single pass through the suite, where every tool is called once or

twice, isn't slowed down by it in practice.

  • If SmartAPI reports a rate limit was hit anyway (HTTP 403, "Access denied

because of exceeding access rate"), the test backs off and retries a

couple of times with increasing delay instead of failing outright.

  • This governs the test suite's own request pace only - it has no effect on

how the MCP server behaves for a real MCP client (Claude, etc.); SmartAPI

still enforces its limits server-side either way.

Notes / limitations

  • Order params (`price`, `quantity`, etc.) are passed as strings, matching

what SmartAPI's `placeOrder` expects.

  • `get_margin` and `estimate_charges` take a list of position/order dicts —

see the SmartAPI docs for exact field names per instrument type

(https://smartapi.angelone.in/docs/Margin, .../Brokerage).

  • Rate limits are enforced by Angel One per endpoint; see

https://smartapi.angelone.in/docs/RateLimit. This server does not do its

own client-side rate limiting.

  • Not affiliated with or endorsed by Angel One / Angel Broking.

Frequently asked questions

What is angelone-mcp?

angelone-mcp is An MCP (Model Context Protocol) server that wraps Angel One's SmartAPI

How do I install angelone-mcp?

Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

Is angelone-mcp open source?

Yes — it is hosted on GitHub at https://github.com/pyalgobot/angelone-mcp.

Related MCP tools

Run your own MCP server? See who uses it and what to fix.

Measure it with TrackMCP