angelone-mcp

Um servidor MCP (Model Context Protocol) que encapsula a SmartAPI da Angel One — negociação, portfólio, dados de mercado, regras GTT e margem/corretagem.

Documentação

angelone-mcp

Listed on mcpservers.org

Um servidor MCP (Model Context Protocol) que encapsula a SmartAPI da Angel One — negociação, portfólio, dados de mercado, regras GTT e margem/corretagem — para que qualquer cliente MCP (Claude, Claude Code, etc.) possa consultar sua conta e fazer pedidos por meio de conversa natural.

⚠️

Isso faz pedidos reais em uma conta de negociação real. Teste primeiro com quantidades pequenas e lembre-se de que a Angel One (como a maioria das corretoras) não permite "desfazer" um pedido já executado.

O que está incluído

  • angelone_mcp/client.py – Cliente REST para todas as rotas documentadas da SmartAPI: autenticação, pedidos, posições/saldos, regras GTT, candles históricos/OI, cotações, gregas de opções, altas/baixas, calculadora de margem, estimador de corretagem. Gerencia login TOTP, re-login automático na expiração do token e se ajusta aos limites de taxa documentados da SmartAPI (veja "Limite de taxa" abaixo).
  • angelone_mcp/server.py – Servidor MCP expondo 32 ferramentas construídas sobre o cliente (veja a lista completa abaixo).

1. Pré-requisitos

  • Python 3.10+
  • Uma conta de negociação na Angel One com acesso à SmartAPI
  • Um aplicativo SmartAPI criado em https://smartapi.angelone.in/ (fornece uma chave de API)
  • TOTP configurado na sua conta Angel One e o segredo base32 usado para configurar esse autenticador (não o código de 6 dígitos — o segredo por trás dele). Você o obtém uma vez, ao escanear o código QR para habilitar o TOTP; se não o salvou, será necessário redefinir/reconfigurar o TOTP na sua conta para obter um novo segredo.

2. Instalação

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

3. Configurar credenciais

Defina estas variáveis de ambiente (por exemplo, em um arquivo .env que você carrega, ou diretamente na configuração do seu cliente MCP):

VariávelDescrição
ANGELONE_API_KEYChave de API do seu aplicativo SmartAPI
ANGELONE_CLIENT_CODESeu código de cliente/conta de negociação da Angel One
ANGELONE_PINSeu PIN de login
ANGELONE_TOTP_SECRETSegredo TOTP base32 da sua conta

Nunca envie isso para o controle de versão. Trate ANGELONE_TOTP_SECRET e ANGELONE_PIN como senhas — qualquer pessoa com eles, além da sua chave de API, pode negociar na sua conta.

Opcional: executando atrás de um proxy HTTP

Se sua máquina/rede exigir um proxy HTTP de saída para acessar a internet, defina:

VariávelDescrição
ANGELONE_HTTP_PROXYURL do proxy usado para requisições http://, ex.: http://user:pass@proxyhost:8080
ANGELONE_HTTPS_PROXYURL do proxy usado para requisições https:// (esta é a que importa — a SmartAPI é exclusivamente https). Usa ANGELONE_HTTP_PROXY como fallback se não estiver definida.
ANGELONE_NO_PROXYLista opcional separada por vírgulas de hosts para ignorar o proxy

Elas só são necessárias se as variáveis de ambiente padrão HTTP_PROXY / HTTPS_PROXY não estiverem visíveis para o processo do servidor. Isso é comum em servidores MCP, pois os clientes MCP geralmente iniciam o servidor com um bloco env explícito (como o JSON abaixo) em vez de herdar o ambiente do seu shell — portanto, um proxy configurado no seu shell não alcançará o servidor, a menos que você o adicione ao bloco env sob HTTPS_PROXY, ou use as variáveis ANGELONE_* acima. Se nem ANGELONE_HTTP_PROXY nem ANGELONE_HTTPS_PROXY estiverem definidas, o servidor usa automaticamente as variáveis padrão HTTP_PROXY / HTTPS_PROXY / NO_PROXY.

4. Executar

Autônomo (para testes):

python -m angelone_mcp.server

Ele fala MCP via stdio, portanto é feito para ser iniciado por um cliente MCP, não para execução interativa.

Configuração do Claude Desktop / Claude Code

Adicione à configuração do seu cliente MCP (ex.: claude_desktop_config.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"
      }
    }
  }
}

Ferramentas expostas

Sessão login, logout, get_profile

Pedidos place_order, modify_order, cancel_order, get_order_book, get_trade_book, get_individual_order_details

Portfólio / fundos get_positions, get_holdings, get_all_holdings, get_rms_limit, convert_position

Regras GTT (Good Till Triggered) gtt_create_rule, gtt_modify_rule, gtt_cancel_rule, gtt_details, gtt_list

Dados de mercado 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

Margem e corretagem get_margin, estimate_charges

Como funciona a autenticação

AngelOneClient faz login de forma preguiçosa na primeira chamada de ferramenta usando clientcode + pin + um TOTP gerado na hora a partir de ANGELONE_TOTP_SECRET (via pyotp). Ele armazena em cache o jwtToken, refreshToken e feedToken resultantes na memória durante a vida do processo. Se qualquer chamada retornar 401/403 ou um TokenException, ele faz re-login transparentemente uma vez e tenta novamente — você não precisa chamar login por conta própria, a menos que queira forçar uma nova sessão.

As sessões emitidas pela SmartAPI são válidas até a meia-noite no horário IST, independentemente da atividade, então um servidor de longa duração pode precisar de um novo login no dia seguinte — a lógica de nova tentativa automática lida com isso na próxima chamada.

Persistência de sessão entre reinicializações

Um login bem-sucedido também é armazenado em cache em um arquivo no disco, para que um novo processo de servidor não precise de um novo login baseado em TOTP toda vez que iniciar (útil, pois o TOTP exige que o código seja gerado recentemente — reiniciar o servidor várias vezes seguidas significaria vários logins reais seguidos).

Na inicialização, antes de atender qualquer chamada de ferramenta, o servidor chama AngelOneClient.restore_session(), que:

  1. Procura um arquivo de sessão salvo anteriormente. Se não houver, não faz mais nada — o cliente permanece no modo preguiçoso normal e faz login na primeira chamada de ferramenta, como antes desse recurso existir.
  2. Se uma sessão salva for encontrada, carrega os tokens em cache e os verifica com uma chamada real a getProfile.
  3. Se a verificação for bem-sucedida, a sessão restaurada é usada como está — sem novo login.
  4. Se falhar por qualquer motivo (token expirado, sessão revogada, arquivo corrompido, etc.), os tokens em cache são descartados e um novo login normal é executado.

Todo login bem-sucedido (novo ou via nova tentativa automática de 401/403 descrita acima) salva novamente o arquivo de sessão, mantendo-o atualizado durante todo o tempo em que o servidor roda, não apenas na inicialização. logout exclui o arquivo.

VariávelDescrição
ANGELONE_SESSION_PERSISTDefina como false / 0 / no / off para desativar a persistência de sessão completamente (padrão: ativada)
ANGELONE_SESSION_FILESubstitui o caminho do arquivo usado para persistir a sessão. Padrão: um arquivo no diretório temporário do SO, nomeado a partir de um hash do seu código de cliente (para que várias contas na mesma máquina não colidam)

O arquivo de sessão contém um token de acesso ativo — não seu PIN ou segredo TOTP, mas suficiente para chamar a API como você até expirar. Ele é gravado com permissões de arquivo somente do proprietário onde o SO suporta; trate-o como sensível, da mesma forma que trataria qualquer sessão de login em cache.

Limite de taxa

AngelOneClient ajusta cada chamada de saída aos limites de taxa por endpoint documentados da SmartAPI — login e a maioria das leituras de portfólio a 1 requisição/seg, getProfile a 3/seg, consultas de cotações/GTT/detalhes de pedidos a 10/seg, colocação de pedidos a 20/seg, e assim por diante. Os limites são por endpoint da SmartAPI, não globais, então chamar ferramentas diferentes em sequência nunca é atrasado por isso — apenas uma chamada repetida ao mesmo endpoint feita mais rápido do que o limite da própria SmartAPI é retida, o que você gostaria de qualquer forma.

Se a SmartAPI relatar que seu próprio limite foi atingido mesmo assim (HTTP 403/429, "Access denied because of exceeding access rate"), a chamada recua e tenta novamente algumas vezes com atraso crescente antes de desistir — e essa resposta não é mais interpretada erroneamente como uma sessão expirada e não aciona um login extra desnecessário como antes.

Isso se aplica automaticamente a todas as ferramentas; não há nada para configurar. Para desativar completamente o ajuste proativo do lado do cliente (a SmartAPI ainda aplica seus próprios limites no servidor de qualquer forma — isso apenas controla se o cliente tenta permanecer abaixo deles proativamente):

VariávelDescrição
ANGELONE_RATE_LIMIT_DISABLEDDefina como true / 1 / yes / on para desativar o ajuste proativo (padrão: ativado)

Testes

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

Limite de taxa no teste ao vivo

O teste ao vivo (tests/test_readonly_live.py) chama uma conta real contra a SmartAPI real. O servidor que ele aciona já se ajusta (veja "Limite de taxa" acima), mas o teste adiciona seu próprio ajuste independente por cima — útil porque também exercita coisas que o limitador do lado do servidor não vê sozinho, como dois subprocessos de servidor separados (a verificação de persistência de sessão) atingindo a mesma conta em sequência:

  • Um RateLimiter rastreia a última vez que cada ferramenta MCP foi chamada e, antes de chamá-la novamente, espera o restante do intervalo mínimo daquele endpoint (1/limite-de-requisições-por-segundo, mais uma margem de segurança de ~20%). Ferramentas distintas atingem endpoints distintos da SmartAPI com limites independentes, então isso só atrasa uma chamada repetida à mesma ferramenta (ex.: get_profile sendo chamada novamente pelo segundo spawn do servidor na verificação de persistência de sessão) — uma passagem normal pelo conjunto, onde cada ferramenta é chamada uma ou duas vezes, não é atrasada na prática.
  • Se a SmartAPI relatar que um limite de taxa foi atingido mesmo assim (HTTP 403, "Access denied because of exceeding access rate"), o teste recua e tenta novamente algumas vezes com atraso crescente em vez de falhar diretamente.
  • Isso governa apenas o ritmo de requisições do próprio conjunto de testes — não tem efeito sobre como o servidor MCP se comporta para um cliente MCP real (Claude, etc.); a SmartAPI ainda aplica seus limites no servidor de qualquer forma.

Notas / limitações

  • Parâmetros de pedido (price, quantity, etc.) são passados como strings, correspondendo ao que o placeOrder da SmartAPI espera.
  • get_margin e estimate_charges recebem uma lista de dicionários de posição/pedido — veja a documentação da SmartAPI para os nomes exatos dos campos por tipo de instrumento (https://smartapi.angelone.in/docs/Margin,.../Brokerage).
  • Os limites de taxa são aplicados pela Angel One por endpoint; veja https://smartapi.angelone.in/docs/RateLimit. Este servidor não faz seu próprio limite de taxa do lado do cliente.
  • Não é afiliado nem endossado pela Angel One / Angel Broking.