groww-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 85f7916a5021489757b9b108c915bd191f3bc09bc21fa39bfb60508db5710e94
4
+ data.tar.gz: c57656b6ce73bd2497a6720f34e51c01fc473db1a028114aeec17ec11d9fbf0b
5
+ SHA512:
6
+ metadata.gz: 3079e0713ab14eadc60ad0c38354714eda6fd0e405f67f597e07eda7a795ce71d533b30a7e10c549366b52643618eb67a420692edc10d4b88811fc5848bbbf23
7
+ data.tar.gz: 94ec58d7f5ef2635f065f7b139bdcda0ce6e4dc0afaeb298cbf83818fdd404be5400bf19d99aee166aab7ff32ac76b96020f0cb0cca286e4e0d328f358645609
data/.env.example ADDED
@@ -0,0 +1,19 @@
1
+ # Groww MCP Configuration
2
+ # Copy this file to .env and fill in your credentials
3
+ # See README.md for setup instructions
4
+
5
+ # === Authentication (choose one method) ===
6
+
7
+ # Method 1: TOTP (Recommended — fully automated, no daily manual steps)
8
+ # Get these from: Groww App → Settings → Trading APIs → Generate TOTP token
9
+ GROWW_TOTP_KEY=your_totp_api_key_here
10
+ GROWW_TOTP_SECRET=your_totp_qr_code_secret_here
11
+
12
+ # Method 2: API Key + Secret (Requires daily approval on Groww website)
13
+ # Get these from: Groww App → Settings → Trading APIs → Generate API key
14
+ # GROWW_API_KEY=your_api_key_here
15
+ # GROWW_API_SECRET=your_api_secret_here
16
+
17
+ # Method 3: Direct Access Token (Manual — expires daily at 6:00 AM IST)
18
+ # Get from: Groww App → Settings → Trading APIs → Generate Access Token
19
+ # GROWW_ACCESS_TOKEN=your_access_token_here
data/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [1.0.0] - 2026-07-28
6
+
7
+ First public release.
8
+
9
+ ### Added
10
+
11
+ - 25 MCP tools across 8 categories:
12
+ - **Auth** — `authenticate`
13
+ - **Portfolio** — `get_holdings`, `get_positions`, `get_margins`, `calculate_margin`
14
+ - **Orders** — `get_orders`, `get_order_detail`, `get_order_trades`, `place_order`, `modify_order`, `cancel_order`
15
+ - **Smart Orders (GTT/OCO)** — `get_smart_orders`, `create_smart_order`, `modify_smart_order`, `cancel_smart_order`
16
+ - **Market Data** — `get_quote`, `get_ltp`, `get_ohlc`, `get_option_chain`, `get_greeks`, `get_historical_data`
17
+ - **Instruments** — `search_instruments`, `get_instrument_detail`, `download_instruments`
18
+ - **User** — `get_profile`
19
+ - 3 authentication methods: TOTP (fully automated), API Key + Secret (approval flow), direct access token
20
+ - Auto token refresh with 5-minute expiry buffer
21
+ - Option chain with Greeks (Delta, Gamma, Theta, Vega)
22
+ - Local CSV-based instrument search — no API calls needed for symbol lookup
23
+ - Rate limit handling with exponential backoff
24
+ - Clear error messages for endpoints that require a paid Groww API subscription
25
+
26
+ ### Fixed (pre-release hardening)
27
+
28
+ - Critical order-safety bugs in the API client and order tools
29
+ - All endpoint paths aligned with the official Groww API (holdings, orders, market data, option chain)
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jai Rajput
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,308 @@
1
+ # Groww MCP Server
2
+
3
+ [![Ruby](https://img.shields.io/badge/Ruby-%3E%3D%203.1-red?logo=ruby)](https://www.ruby-lang.org/)
4
+ [![MCP](https://img.shields.io/badge/MCP-compatible-blue?logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=)](https://modelcontextprotocol.io/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
6
+ [![Groww API](https://img.shields.io/badge/Groww-Trade%20API-00d09c?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==)](https://groww.in/trade-api)
7
+
8
+ > **The most complete MCP server for Groww** — 25 tools, automated TOTP auth, smart orders (GTT/OCO), option chain with Greeks, and local instrument search. No other Groww MCP has all of these.
9
+
10
+ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that connects AI assistants (Claude, GPT, Gemini) to the [Groww](https://groww.in/) trading platform. Trade stocks, manage your portfolio, place F&O orders, and access live market data — all through natural language.
11
+
12
+ Built with Ruby, powered by the official [MCP Ruby SDK](https://github.com/modelcontextprotocol/ruby-sdk).
13
+
14
+ ### Key Highlights
15
+
16
+ - **25 tools** — most comprehensive Groww MCP available
17
+ - **Zero manual auth** — automated TOTP token generation (no daily website visits)
18
+ - **Smart Orders** — GTT and OCO support (only Groww MCP with this)
19
+ - **Option Chain** — with Greeks (Δ, Γ, Θ, ν) for options analysis
20
+ - **Works with** — Claude Code, Claude Desktop, any MCP-compatible AI assistant
21
+
22
+ ## Why This MCP?
23
+
24
+ | Feature | groww-mcp (this) | [darved2305](https://github.com/darved2305/groww-mcp) (TS) | [arkapravasinha](https://github.com/arkapravasinha/groww-mcp-server) (Python) | [karthik1729](https://github.com/karthik1729/groww-mcp) (Go) |
25
+ |---------|:-:|:-:|:-:|:-:|
26
+ | **Tools** | **25** | 23 | ~20 | 15 |
27
+ | **Auto TOTP auth** | ✅ | ❌ | ❌ | ❌ |
28
+ | **Token auto-refresh** | ✅ | ❌ | ❌ | ❌ |
29
+ | **3 auth methods** | ✅ | Token only | API Key only | Token only |
30
+ | **Smart Orders (GTT/OCO)** | ✅ | ❌ | ❌ | ❌ |
31
+ | **Option Chain + Greeks** | ✅ | ❌ | ❌ | ❌ |
32
+ | **Instruments Search** (local, CSV-based) | ✅ | ❌ | ✅ | ❌ |
33
+ | **F&O support** | ✅ | ❌ | ✅ | ✅ |
34
+ | **Subscription hints** | ✅ | ❌ | ❌ | ❌ |
35
+ | **Official MCP SDK** | ✅ | ✅ | ✅ | Custom |
36
+ | **Language** | Ruby | TypeScript | Python | Go |
37
+
38
+ ## Quick Start
39
+
40
+ ### Prerequisites
41
+
42
+ - Ruby >= 3.1.0 (tested on 4.0.1)
43
+ - A [Groww](https://groww.in/) trading account with API access
44
+
45
+ ### Installation
46
+
47
+ ```bash
48
+ git clone https://github.com/developerjai/groww-mcp.git
49
+ cd groww-mcp
50
+ bundle install
51
+ ```
52
+
53
+ ### Configuration
54
+
55
+ ```bash
56
+ cp .env.example .env
57
+ ```
58
+
59
+ Edit `.env` with your Groww credentials (see [Authentication](#authentication) below).
60
+
61
+ ### Connect to Claude Code
62
+
63
+ Add to your `.mcp.json`:
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "groww": {
69
+ "type": "stdio",
70
+ "command": "ruby",
71
+ "args": ["/path/to/groww-mcp/bin/groww-mcp"],
72
+ "env": {
73
+ "GROWW_TOTP_KEY": "your_totp_key",
74
+ "GROWW_TOTP_SECRET": "your_totp_secret"
75
+ }
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ Or use with **Claude Desktop** — add to `claude_desktop_config.json`:
82
+
83
+ ```json
84
+ {
85
+ "mcpServers": {
86
+ "groww": {
87
+ "command": "ruby",
88
+ "args": ["/path/to/groww-mcp/bin/groww-mcp"]
89
+ }
90
+ }
91
+ }
92
+ ```
93
+
94
+ ## Authentication
95
+
96
+ Groww MCP supports **3 authentication methods**. Choose the one that fits your workflow:
97
+
98
+ ### Method 1: TOTP (Recommended)
99
+
100
+ **Fully automated.** No daily manual steps. The server generates access tokens automatically using a TOTP secret.
101
+
102
+ #### Setup (one-time, 2 minutes):
103
+
104
+ 1. Go to [groww.in](https://groww.in/) → Log in
105
+ 2. Navigate to **Profile** → **Settings** → **Trading APIs**
106
+ 3. Click **"Generate API key"** dropdown → **"Generate TOTP token"**
107
+ 4. You'll get two values:
108
+ - **TOTP Token** (a long JWT string starting with `eyJ...`) → This is your `GROWW_TOTP_KEY`
109
+ - **TOTP QR Secret** (a short base32 string like `UG3X...`) → This is your `GROWW_TOTP_SECRET`
110
+
111
+ 5. Add to your `.env`:
112
+ ```bash
113
+ GROWW_TOTP_KEY=eyJraWQi...your_totp_jwt_key
114
+ GROWW_TOTP_SECRET=UG3XTATB22XLH5SGGLHHV736PEOYUZSB
115
+ ```
116
+
117
+ That's it. The server will automatically generate fresh access tokens on every startup. No manual steps, no daily website visits.
118
+
119
+ ### Method 2: API Key + Secret (Approval)
120
+
121
+ Requires **daily approval** on the Groww website before the server can generate tokens.
122
+
123
+ #### Setup:
124
+
125
+ 1. Go to [groww.in](https://groww.in/) → **Settings** → **Trading APIs**
126
+ 2. Click **"Generate API key"** → Create a key
127
+ 3. Copy the API Key and API Secret
128
+ 4. Add to `.env`:
129
+ ```bash
130
+ GROWW_API_KEY=eyJraWQi...your_api_key
131
+ GROWW_API_SECRET=your_api_secret
132
+ ```
133
+ 5. **Daily**: Visit the Trading APIs page and click "Approve" next to your key
134
+
135
+ ### Method 3: Direct Access Token (Manual)
136
+
137
+ For quick testing. Token expires daily at **6:00 AM IST**.
138
+
139
+ 1. Go to [groww.in](https://groww.in/) → **Settings** → **Trading APIs**
140
+ 2. Click **"Generate API key"** dropdown → **"Generate Access Token"**
141
+ 3. Copy the token
142
+ 4. Add to `.env`:
143
+ ```bash
144
+ GROWW_ACCESS_TOKEN=eyJraWQi...your_access_token
145
+ ```
146
+
147
+ > ⚠️ You'll need to regenerate this token every day before 6:00 AM IST.
148
+
149
+ ## Tools
150
+
151
+ ### Portfolio (Free)
152
+
153
+ | Tool | Description |
154
+ |------|-------------|
155
+ | `get_holdings` | All stocks in your DEMAT account with avg price, quantity, ISIN |
156
+ | `get_positions` | Open intraday/F&O positions with unrealized P&L |
157
+ | `get_margins` | Available cash, collateral, equity & F&O margin details |
158
+ | `calculate_margin` | Pre-check margin requirement for a basket of orders before placing them |
159
+
160
+ ### Orders (Free)
161
+
162
+ | Tool | Description |
163
+ |------|-------------|
164
+ | `get_orders` | List all orders with status, filterable by segment |
165
+ | `get_order_detail` | Detailed status of a specific order |
166
+ | `get_order_trades` | Partial fill details for a specific order |
167
+ | `place_order` | Place BUY/SELL orders (MARKET, LIMIT, SL, SL-M) |
168
+ | `modify_order` | Modify pending orders (price, quantity, type) |
169
+ | `cancel_order` | Cancel open/pending orders |
170
+
171
+ ### Smart Orders — GTT/OCO (Free)
172
+
173
+ | Tool | Description |
174
+ |------|-------------|
175
+ | `get_smart_orders` | List all GTT and OCO orders |
176
+ | `create_smart_order` | Create GTT (trigger-based) or OCO (stop-loss + target) |
177
+ | `modify_smart_order` | Update triggers, quantities, and prices |
178
+ | `cancel_smart_order` | Cancel pending smart orders |
179
+
180
+ > **GTT** (Good Till Triggered): Automatically places an order when price hits your target.
181
+ > **OCO** (One Cancels Other): Sets both stop-loss AND target — whichever hits first executes.
182
+
183
+ ### Market Data (₹499/mo subscription)
184
+
185
+ | Tool | Description |
186
+ |------|-------------|
187
+ | `get_quote` | Live quote with OHLC, bid/ask, volume, change % |
188
+ | `get_ltp` | Last traded price for up to 50 symbols at once |
189
+ | `get_ohlc` | OHLC data for up to 50 symbols |
190
+ | `get_option_chain` | Full option chain for an expiry with OI, IV, and Greeks (Δ, Γ, Θ, ν) |
191
+ | `get_greeks` | Greeks (Δ, Γ, Θ, ν, ρ) and IV for a specific option contract |
192
+ | `get_historical_data` | Historical candlestick data for analysis (custom intervals supported) |
193
+
194
+ > Market data tools require the [Groww Live Data subscription](https://groww.in/trade-api) (₹499 + GST/month). Without it, these tools will return a clear error message explaining how to subscribe.
195
+
196
+ ### Instruments (Free)
197
+
198
+ Instrument lookup runs **locally** against Groww's public instruments CSV (cached for 24h) — fast, and no Live Data subscription needed.
199
+
200
+ | Tool | Description |
201
+ |------|-------------|
202
+ | `search_instruments` | Find stocks, F&O, ETFs by name or symbol (local CSV search) |
203
+ | `get_instrument_detail` | Lot size, tick size, expiry, contract details (local CSV lookup) |
204
+ | `download_instruments` | Complete CSV of all tradable instruments |
205
+
206
+ > **Note on backtesting:** the Groww API does not offer a backtesting endpoint, so this server doesn't ship a `run_backtest` tool. Use `get_historical_data` to pull candles and let your AI assistant run the analysis.
207
+
208
+ ### Other
209
+
210
+ | Tool | Description |
211
+ |------|-------------|
212
+ | `authenticate` | Manually trigger token refresh (auto-handled normally) |
213
+ | `get_profile` | Account info: UCC, exchanges, segments, DDPI status |
214
+
215
+ ## Groww API Rate Limits
216
+
217
+ | Category | Requests/sec | Requests/min |
218
+ |----------|:---:|:---:|
219
+ | Orders (create, modify, cancel) | 10 | 250 |
220
+ | Live Data (quote, LTP, OHLC) | 10 | 300 |
221
+ | Non-Trading (orders, holdings, positions) | 20 | 500 |
222
+
223
+ ## Examples
224
+
225
+ Once connected, you can use natural language with your AI assistant:
226
+
227
+ ```
228
+ "Show me my current holdings"
229
+ "What's my available margin?"
230
+ "Place a limit buy order for 10 shares of RELIANCE at ₹2,800"
231
+ "Cancel order ORD123456"
232
+ "Get the current price of INFY" (requires Live Data subscription)
233
+ ```
234
+
235
+ ## Project Structure
236
+
237
+ ```
238
+ groww-mcp/
239
+ ├── bin/
240
+ │ └── groww-mcp # Executable entry point
241
+ ├── lib/
242
+ │ ├── groww_mcp.rb # Main module, tool registry (25 tools)
243
+ │ └── groww_mcp/
244
+ │ ├── version.rb # Gem version
245
+ │ ├── auth.rb # 3-method authentication (TOTP, approval, manual)
246
+ │ ├── client.rb # Groww API client (net/http, correct endpoints)
247
+ │ ├── base_tool.rb # Shared tool helpers
248
+ │ └── tools/
249
+ │ ├── auth_tools.rb # authenticate
250
+ │ ├── portfolio_tools.rb # holdings, positions, margins
251
+ │ ├── order_tools.rb # place, modify, cancel, list, detail
252
+ │ ├── smart_order_tools.rb # GTT, OCO (create, modify, cancel, list)
253
+ │ ├── market_tools.rb # quote, LTP, OHLC, historical
254
+ │ ├── option_chain_tools.rb # option chain, Greeks, order trades
255
+ │ ├── instrument_tools.rb # local search, detail, CSV download
256
+ │ └── user_tools.rb # profile
257
+ ├── .env.example # Configuration template
258
+ ├── Gemfile # Dependencies
259
+ ├── groww-mcp.gemspec # Gem specification
260
+ ├── LICENSE # MIT
261
+ └── README.md # This file
262
+ ```
263
+
264
+ ## Important Notes
265
+
266
+ - **Access tokens expire daily at 6:00 AM IST.** TOTP auth handles this automatically.
267
+ - **SEBI compliance**: Groww requires a static IP for order placement. Register yours at Trading APIs → "Add static IP".
268
+ - **Live Data** (quotes, LTP, OHLC, historical) requires the ₹499/mo subscription.
269
+ - **Order placement** executes real trades with real money. The AI will always confirm before placing orders.
270
+
271
+ ## Other Groww MCP Servers
272
+
273
+ Looking for alternatives? Here's every Groww MCP server available:
274
+
275
+ | Project | Language | Tools | Highlights | Limitations |
276
+ |---------|----------|:-----:|------------|-------------|
277
+ | **[groww-mcp](https://github.com/developerjai/groww-mcp)** (this) | Ruby | 25 | Auto TOTP, GTT/OCO, option chain + Greeks, local instrument search | — |
278
+ | [darved2305/groww-mcp](https://github.com/darved2305/groww-mcp) | TypeScript | 23 | Mock mode, SIP/MF tools | No auto-auth, no smart orders |
279
+ | [arkapravasinha/groww-mcp-server](https://github.com/arkapravasinha/groww-mcp-server) | Python | ~20 | 11 technical analysis tools | No auto-auth, no smart orders |
280
+ | [venkatakaushikvemani/groww-mcp](https://github.com/venkatakaushikvemani/groww-mcp) | TypeScript | 8 | npm published, intent-based routing | Minimal tool set |
281
+ | [karthik1729/groww-mcp](https://github.com/karthik1729/groww-mcp) | Go | 15 | Correct API paths, margin calculator | No auto-auth, no option chain |
282
+
283
+ ## Built for Groww
284
+
285
+ This project is built on top of the [Groww Trade API](https://groww.in/trade-api) to make algorithmic and AI-assisted trading accessible to every Groww user.
286
+
287
+ **[@AskGroww](https://twitter.com/AskGroww)** — If you're from the Groww team, I'd love to collaborate. This MCP server makes your Trade API accessible to every AI assistant (Claude, GPT, Gemini) through the open [MCP standard](https://modelcontextprotocol.io/). Let's make Groww the most AI-friendly broker in India.
288
+
289
+ ## Contributing
290
+
291
+ Contributions are welcome! Whether it's a bug fix, new tool, documentation improvement, or feature idea — all PRs are appreciated.
292
+
293
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
294
+
295
+ **Some ideas to get started:**
296
+
297
+ - Add support for mutual fund tools (SIP, redemption, NAV)
298
+ - Improve error messages and edge case handling
299
+ - Add tests with mock API responses
300
+ - Documentation and examples for different AI assistants
301
+
302
+ ## License
303
+
304
+ [MIT](LICENSE)
305
+
306
+ ## Author
307
+
308
+ Building AI-powered tools for Indian markets.
data/bin/groww-mcp ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "mcp"
6
+ require_relative "../lib/groww_mcp"
7
+
8
+ # Load .env file if present
9
+ env_file = File.join(__dir__, "..", ".env")
10
+ if File.exist?(env_file)
11
+ File.readlines(env_file).each do |line|
12
+ line = line.strip
13
+ next if line.empty? || line.start_with?("#")
14
+
15
+ key, value = line.split("=", 2)
16
+ ENV[key] = value if key && value
17
+ end
18
+ end
19
+
20
+ # Initialize auth and client
21
+ auth = GrowwMcp::Auth.new
22
+ client = GrowwMcp::Client.new(auth)
23
+
24
+ # Auto-authenticate on startup
25
+ begin
26
+ auth.authenticate!
27
+ rescue GrowwMcp::AuthError => e
28
+ $stderr.puts "[groww-mcp] Warning: #{e.message}"
29
+ $stderr.puts "[groww-mcp] Tools will attempt authentication on first use."
30
+ end
31
+
32
+ # Create MCP server
33
+ server = MCP::Server.new(
34
+ name: "groww-mcp",
35
+ version: GrowwMcp::VERSION,
36
+ tools: GrowwMcp::ALL_TOOLS,
37
+ server_context: { auth: auth, client: client },
38
+ )
39
+
40
+ $stderr.puts "[groww-mcp] Groww MCP Server v#{GrowwMcp::VERSION}"
41
+ $stderr.puts "[groww-mcp] #{GrowwMcp::ALL_TOOLS.length} tools registered"
42
+ $stderr.puts "[groww-mcp] Auth: #{auth.access_token ? 'connected' : 'pending'}"
43
+
44
+ # Start stdio transport
45
+ transport = MCP::Server::Transports::StdioTransport.new(server)
46
+ transport.open
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "digest"
6
+ require "rotp"
7
+
8
+ module GrowwMcp
9
+ class Auth
10
+ TOKEN_ENDPOINT = "/v1/token/api/access"
11
+ BASE_URL = "https://api.groww.in"
12
+
13
+ attr_reader :access_token, :token_expiry
14
+
15
+ def initialize
16
+ @access_token = nil
17
+ @token_expiry = nil
18
+ end
19
+
20
+ # Authenticate using the best available method
21
+ # Priority: Direct token > TOTP > API Key + Secret
22
+ def authenticate!
23
+ if ENV["GROWW_ACCESS_TOKEN"] && !ENV["GROWW_ACCESS_TOKEN"].empty?
24
+ @access_token = ENV["GROWW_ACCESS_TOKEN"]
25
+ @token_expiry = nil # Unknown expiry for manual tokens
26
+ log "Authenticated with direct access token"
27
+ elsif ENV["GROWW_TOTP_KEY"] && ENV["GROWW_TOTP_SECRET"]
28
+ authenticate_totp!
29
+ elsif ENV["GROWW_API_KEY"] && ENV["GROWW_API_SECRET"]
30
+ authenticate_approval!
31
+ else
32
+ raise AuthError, "No credentials configured. Set GROWW_TOTP_KEY + GROWW_TOTP_SECRET (recommended), " \
33
+ "or GROWW_API_KEY + GROWW_API_SECRET, or GROWW_ACCESS_TOKEN in your .env file."
34
+ end
35
+
36
+ @access_token
37
+ end
38
+
39
+ # Check if token needs refresh (expired or expiring in 5 minutes)
40
+ def token_valid?
41
+ return false unless @access_token
42
+ return true unless @token_expiry # Manual tokens — assume valid
43
+
44
+ Time.now < (@token_expiry - 300) # 5 minute buffer
45
+ end
46
+
47
+ # Ensure we have a valid token, refresh if needed
48
+ def ensure_token!
49
+ authenticate! unless token_valid?
50
+ @access_token
51
+ end
52
+
53
+ # Drop the cached token so the next ensure_token! re-authenticates.
54
+ # Called by the client when the API returns 401 (stale/expired token).
55
+ def invalidate!
56
+ @access_token = nil
57
+ @token_expiry = nil
58
+ end
59
+
60
+ private
61
+
62
+ # TOTP-based authentication (fully automated, no manual steps)
63
+ def authenticate_totp!
64
+ totp = ROTP::TOTP.new(ENV["GROWW_TOTP_SECRET"])
65
+ code = totp.now
66
+
67
+ body = { key_type: "totp", totp: code }
68
+ result = post_token(ENV["GROWW_TOTP_KEY"], body)
69
+
70
+ @access_token = result["token"]
71
+ @token_expiry = Time.parse(result["expiry"]) if result["expiry"]
72
+
73
+ log "Authenticated via TOTP (expires: #{result['expiry']})"
74
+ end
75
+
76
+ # API Key + Secret authentication (requires daily approval on Groww website)
77
+ def authenticate_approval!
78
+ timestamp = Time.now.to_i.to_s
79
+ checksum = Digest::SHA256.hexdigest("#{ENV['GROWW_API_SECRET']}#{timestamp}")
80
+
81
+ body = { key_type: "approval", checksum: checksum, timestamp: timestamp }
82
+ result = post_token(ENV["GROWW_API_KEY"], body)
83
+
84
+ @access_token = result["token"]
85
+ @token_expiry = Time.parse(result["expiry"]) if result["expiry"]
86
+
87
+ log "Authenticated via API Key approval (expires: #{result['expiry']})"
88
+ end
89
+
90
+ def post_token(api_key, body)
91
+ uri = URI("#{BASE_URL}#{TOKEN_ENDPOINT}")
92
+ http = Net::HTTP.new(uri.host, uri.port)
93
+ http.use_ssl = true
94
+
95
+ request = Net::HTTP::Post.new(uri.path)
96
+ request["Authorization"] = "Bearer #{api_key}"
97
+ request["Content-Type"] = "application/json"
98
+ request["X-API-VERSION"] = "1.0"
99
+ request.body = body.to_json
100
+
101
+ response = http.request(request)
102
+
103
+ unless response.is_a?(Net::HTTPSuccess)
104
+ error_body = JSON.parse(response.body) rescue {}
105
+ message = error_body.dig("error", "errorMessage") || error_body.dig("error", "message") || response.body
106
+ raise AuthError, "Token generation failed (#{response.code}): #{message}"
107
+ end
108
+
109
+ JSON.parse(response.body)
110
+ end
111
+
112
+ def log(message)
113
+ $stderr.puts "[groww-mcp] #{message}"
114
+ end
115
+ end
116
+
117
+ class AuthError < StandardError; end
118
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mcp"
4
+ require "json"
5
+
6
+ module GrowwMcp
7
+ # Extend MCP::Tool with response helpers used by all Groww tools
8
+ class BaseTool < MCP::Tool
9
+ class << self
10
+ private
11
+
12
+ def format_response(data)
13
+ text = JSON.pretty_generate(data)
14
+ MCP::Tool::Response.new([{ type: "text", text: text }])
15
+ end
16
+
17
+ def error_response(error)
18
+ MCP::Tool::Response.new([{ type: "text", text: "❌ #{error.message}" }])
19
+ end
20
+ end
21
+ end
22
+ end