# 🏗️ DhanHQ MCP Server Architecture
## System Overview
```
┌─────────────────────────────────────────────────────────────────────┐
│ MCP Inspector (Browser) │
│ Interactive Tool Testing UI │
└──────────────────────────────┬──────────────────────────────────────┘
│
Stdio Communication
│
┌──────────────────────────────▼──────────────────────────────────────┐
│ MCP Server (Node.js) │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Tool Handlers (index.ts) │ │
│ │ ├─ start_authentication │ │
│ │ ├─ get_login_instructions │ │
│ │ ├─ complete_authentication │ │
│ │ ├─ check_auth_status │ │
│ │ └─ reset_authentication │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Authentication Module (authentication.ts) │ │
│ │ ├─ generateConsent() → Step 1 │ │
│ │ ├─ getStep2Instructions() → Step 2 Info │ │
│ │ ├─ consumeConsent() → Step 3 │ │
│ │ ├─ getAccessToken() │ │
│ │ └─ isTokenValid() │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Config & State Management (config.ts, types.ts) │ │
│ │ ├─ Environment Variables (.env) │ │
│ │ ├─ In-Memory Auth State │ │
│ │ └─ Type Definitions │ │
│ └────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────┬───────────────────────────────────────┘
│
HTTPS / REST API
(Axios HTTP Client)
│
┌──────────────────────┴──────────────────────┐
│ │
┌───────▼────────────────┐ ┌───────────▼─────────┐
│ DhanHQ OAuth Endpoints │ │ User's Browser │
├────────────────────────┤ ├─────────────────────┤
│ Step 1: │ ────────> │ Step 2: User Login │
│ generate-consent │ │ & 2FA Verification │
│ │ │ │
│ Step 3: │ <──────── │ Step 2: Redirect │
│ consumeApp-consent │ tokenId │ with tokenId │
└────────────────────────┘ └─────────────────────┘
```
## Authentication Flow Sequence
```
┌─────────────┐
│ User │
└──────┬──────┘
│
│ 1. Call start_authentication
▼
┌──────────────────────┐
│ MCP Inspector UI │
└──────┬───────────────┘
│
│ 2. MCP Request
▼
┌──────────────────────────────────────┐
│ MCP Server (index.ts) │
│ - Receives start_authentication │
│ - Routes to authentication.ts │
└──────┬───────────────────────────────┘
│
│ 3. HTTP POST with API key/secret
▼
┌──────────────────────────────────────┐
│ DhanHQ: generate-consent API │
│ POST /app/generate-consent │
└──────┬───────────────────────────────┘
│
│ 4. Returns consentAppId
▼
┌──────────────────────────────────────┐
│ MCP Server (authentication.ts) │
│ - Stores consentAppId in memory │
│ - Generates login URL │
└──────┬───────────────────────────────┘
│
│ 5. Response to Inspector
▼
┌──────────────────────────────────────┐
│ MCP Inspector Shows: │
│ - loginUrl │
│ - consentAppId │
│ - Instructions │
└──────┬───────────────────────────────┘
│
│ 6. User opens loginUrl in browser (MANUAL STEP)
▼
┌──────────────────────────────────────┐
│ DhanHQ Login Page │
│ - User enters credentials │
│ - Completes 2FA │
│ - Redirected to callback URL │
└──────┬───────────────────────────────┘
│
│ 7. Redirect: callback?tokenId=xyz
▼
┌──────────────────────────────────────┐
│ User's Browser │
│ - Extracts tokenId from URL │
│ - Copies tokenId │
└──────┬───────────────────────────────┘
│
│ 8. Call complete_authentication with tokenId
▼
┌──────────────────────────────────────┐
│ MCP Inspector UI │
│ - Input: { tokenId: "xyz..." } │
└──────┬───────────────────────────────┘
│
│ 9. MCP Request
▼
┌──────────────────────────────────────┐
│ MCP Server (index.ts) │
│ - Receives complete_authentication │
│ - Routes to authentication.ts │
└──────┬───────────────────────────────┘
│
│ 10. HTTP GET with API key/secret
▼
┌──────────────────────────────────────┐
│ DhanHQ: consumeApp-consent API │
│ GET /app/consumeApp-consent?tokenId │
└──────┬───────────────────────────────┘
│
│ 11. Returns JWT access token
▼
┌──────────────────────────────────────┐
│ MCP Server (authentication.ts) │
│ - Stores accessToken in memory │
│ - Stores client details │
│ - Validates expiry time │
└──────┬───────────────────────────────┘
│
│ 12. Response to Inspector
▼
┌──────────────────────────────────────┐
│ MCP Inspector Shows: │
│ - success: true │
│ - authToken { │
│ accessToken, │
│ dhanClientId, │
│ dhanClientName, │
│ expiryTime, │
│ ... │
│ } │
└──────────────────────────────────────┘
✅ Authentication Complete!
Ready for API requests.
```
## Component Relationships
```
┌─────────────────────────────────────────────────────────────┐
│ │
│ index.ts (Entry Point) │
│ - Creates MCP Server │
│ - Registers tool handlers │
│ - Validates config │
│ - Connects stdio transport │
│ │
│ ┌────────────────────────────────────────────────────────┤
│ │ │
│ │ Tool Handlers (switch statement) │
│ │ - Parse incoming requests │
│ │ - Call authentication functions │
│ │ - Format responses │
│ │ - Handle errors │
│ │ │
│ │ ┌───────────────────────────────────────────────────┤
│ │ │ │
│ │ │ authentication.ts (Business Logic) │
│ │ │ - HTTP calls to DhanHQ │
│ │ │ - Token management │
│ │ │ - State persistence │
│ │ │ │
│ │ │ ┌────────────────────────────────────────────┤
│ │ │ │ │
│ │ │ │ config.ts (Configuration) │
│ │ │ │ - Load .env variables │
│ │ │ │ - Validate credentials │
│ │ │ │ │
│ │ │ │ types.ts (Type Definitions) │
│ │ │ │ - AuthState interface │
│ │ │ │ - DhanAuthToken interface │
│ │ │ │ - API response types │
│ │ │ │ │
│ │ │ └────────────────────────────────────────────┤
│ │ │ │
│ │ └──────────────────────────────────────────────────┤
│ │ │
│ └────────────────────────────────────────────────────┤
│ │
└─────────────────────────────────────────────────────┘
```
## State Management
```
In-Memory Auth State (authState object)
┌─────────────────────────────────────────────────────┐
│ Authentication State Structure │
├─────────────────────────────────────────────────────┤
│ │
│ authState = { │
│ consentAppId: string | undefined, │
│ consentAppStatus: string | undefined, │
│ tokenId: string | undefined, │
│ authToken: { │
│ accessToken: string, │
│ dhanClientId: string, │
│ dhanClientName: string, │
│ dhanClientUcc: string, │
│ expiryTime: ISO 8601 string, │
│ givenPowerOfAttorney: boolean, │
│ generatedAt: ISO 8601 string │
│ } | undefined │
│ } │
│ │
└─────────────────────────────────────────────────────┘
⚠️ Note: Stored in-memory only
- Lost on server restart
- Not persistent
- Suitable for development/testing
🔄 Production Upgrade Path:
- Migrate to database (MongoDB/PostgreSQL)
- Add token refresh mechanism
- Implement secure session storage
```
## Error Handling Flow
```
┌──────────────────────────┐
│ Tool Handler in index.ts│
└──────────┬───────────────┘
│
▼
try-catch block
│
┌──────┴──────┐
│ │
▼ ▼
Success Error
│ │
│ ├─ Parse error message
│ │
│ ├─ Log to console
│ │
│ └─ Return error response
│ to MCP Inspector
│
└─ Format response
└─ Return to MCP Inspector
```
## Data Flow for Each Tool
### start_authentication
```
User Input → Tool Handler
↓
validateConfig()
↓
axios.post (generate-consent API)
↓
Store consentAppId in-memory
↓
Generate loginUrl
↓
Format Response
↓
Return to Inspector
```
### complete_authentication
```
User Input (tokenId) → Tool Handler
↓
Get tokenId from args
↓
axios.get (consumeApp-consent API)
↓
Extract accessToken & details
↓
Store authToken in-memory
↓
Return Response
↓
Return to Inspector
```
### check_auth_status
```
User Input → Tool Handler
↓
Get authState from memory
↓
Validate token expiry
↓
Redact sensitive data
↓
Build status object
↓
Return to Inspector
```
## Security Layers
```
┌─────────────────────────────────────────────────────┐
│ Layer 1: Input Validation │
│ - Check tokenId exists │
│ - Validate required parameters │
└────────────────┬────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ Layer 2: Configuration Security │
│ - Environment variables for credentials │
│ - NOT hardcoded │
│ - Validated on startup │
└────────────────┬────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ Layer 3: API Communication │
│ - HTTPS to DhanHQ APIs │
│ - API Key/Secret in headers │
│ - OAuth token obtained securely │
└────────────────┬────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ Layer 4: Data Redaction │
│ - Tokens redacted in responses │
│ - Sensitive data marked as ***REDACTED*** │
│ - Console logs don't expose tokens │
└─────────────────────────────────────────────────────┘
```
## Deployment Architecture (Future)
```
┌─────────────────────────────────────────────────┐
│ React Frontend │
│ (User Interface & UX) │
└──────────────┬──────────────────────────────────┘
│ HTTP/WebSocket
▼
┌─────────────────────────────────────────────────┐
│ Backend API Gateway │
│ (Node.js Express or similar) │
└──────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ MCP Server (DhanHQ) │
│ (This project - authentication layer) │
└──────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ PostgreSQL Database │
│ (Token storage, user sessions) │
└─────────────────────────────────────────────────┘
```
---
This architecture is designed for:
- ✅ Local development with MCP Inspector
- ✅ Gradual expansion with new trading tools
- ✅ Easy migration to production
- ✅ Type-safe TypeScript throughout
- ✅ Clear separation of concerns