finhay-mcp-server 1.0.7 → 1.0.9

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.
package/README.en.md ADDED
@@ -0,0 +1,133 @@
1
+ # finhay-mcp-server
2
+
3
+ <!-- mcp-name: io.github.finhay/mcp-server -->
4
+
5
+ [Tiếng Việt](README.md) | [English](README.en.md)
6
+
7
+ MCP Server for Finhay Securities — view stock prices, portfolio, gold, crypto via Claude AI.
8
+
9
+ ## Installation
10
+
11
+ ### Step 1: Create API Key
12
+
13
+ Go to [https://www.finhay.com.vn/finhay-skills](https://www.finhay.com.vn/finhay-skills) → Login → Create API Key.
14
+
15
+ You will receive:
16
+ - **API Key**: `ak_live_xxx`
17
+ - **API Secret**: `sk_live_yyy`
18
+
19
+ ### Step 2: Connect to Claude
20
+
21
+ Choose **one of three** methods below:
22
+
23
+ #### Method 1: Automatic install (no Node.js required — Recommended)
24
+
25
+ Open Terminal (macOS) or PowerShell (Windows), paste this command and press Enter:
26
+
27
+ **macOS:**
28
+ ```bash
29
+ curl -fsSL https://raw.githubusercontent.com/finhay/mcp-server/main/install.sh | bash
30
+ ```
31
+
32
+ **Windows (PowerShell):**
33
+ ```powershell
34
+ irm https://raw.githubusercontent.com/finhay/mcp-server/main/install.ps1 | iex
35
+ ```
36
+
37
+ The script will auto-install Node.js (if needed), prompt for API Key/Secret, and configure Claude Desktop.
38
+
39
+ #### Method 2: Quick install (Node.js required)
40
+
41
+ If you already have Node.js (>= 18), run:
42
+
43
+ ```bash
44
+ npx -y finhay-mcp-server --install
45
+ ```
46
+
47
+ The script will prompt for API Key/Secret (Secret is masked with `*`), then automatically write the config to Claude Desktop.
48
+
49
+ #### Method 3: Manual configuration
50
+
51
+ **Step 3a.** Create credentials file at `~/.finhay/credentials/.env`:
52
+
53
+ ```
54
+ FINHAY_API_KEY=ak_live_xxx
55
+ FINHAY_API_SECRET=sk_live_yyy
56
+ ```
57
+
58
+ **Step 3b.** Add to Claude Desktop config:
59
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
60
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
61
+ - Windows (Microsoft Store): `%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json`
62
+
63
+ ```json
64
+ {
65
+ "mcpServers": {
66
+ "finhay": {
67
+ "command": "npx",
68
+ "args": ["-y", "finhay-mcp-server"]
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ > API Key/Secret are **not stored** in Claude config — they live separately at `~/.finhay/credentials/.env` (shared with Finhay Skills).
75
+
76
+ Restart Claude Desktop after setup.
77
+
78
+ ### Step 3: Usage
79
+
80
+ Open Claude and ask:
81
+
82
+ - "What's VNM stock price today?"
83
+ - "Show my investment portfolio"
84
+ - "Compare FPT and VNM"
85
+ - "What's SJC gold price today?"
86
+ - "Which bank has the highest savings rate?"
87
+ - "Recent Vietnam CPI index?"
88
+
89
+ ## Tools
90
+
91
+ ### Market data (20 tools)
92
+
93
+ | Tool | Description |
94
+ |------|-------------|
95
+ | `get_stock_realtime` | Realtime stock prices (single, multiple, or by exchange) |
96
+ | `get_price_history_chart` | OHLCV price history |
97
+ | `get_recommendation_reports` | Analyst recommendation reports |
98
+ | `get_funds` | List of investment funds |
99
+ | `get_fund_portfolio` | Fund portfolio composition |
100
+ | `get_fund_months` | Available months for fund data |
101
+ | `get_gold_prices` | Gold prices (SJC, DOJI, PNJ, BTMC) |
102
+ | `get_gold_chart` | Gold price chart |
103
+ | `get_gold_providers` | Gold prices by provider |
104
+ | `get_silver_prices` | Silver prices |
105
+ | `get_silver_chart` | Silver price chart |
106
+ | `get_metal_providers` | Gold + silver prices by provider |
107
+ | `get_all_financial_data` | All-in-one: gold, silver, crypto, rates, FX |
108
+ | `get_bank_interest_rates` | Bank savings interest rates |
109
+ | `get_crypto_top_trending` | Top trending cryptocurrencies |
110
+ | `get_company_financial_overview` | Company financial overview (PE, PB, ROE, EPS...) |
111
+ | `get_company_financial_analysis` | Financial analysis by year/quarter |
112
+ | `get_financial_statement` | Financial statements (income, balance sheet, cash flow) |
113
+ | `get_macro_data` | Macro indicators (CPI, PMI, IIP, FED rate...) |
114
+ | `get_market_session` | Trading session status |
115
+
116
+ ### Account (8 tools)
117
+
118
+ | Tool | Description |
119
+ |------|-------------|
120
+ | `get_account_summary` | Balance: cash, securities, margin |
121
+ | `get_asset_summary` | Total assets |
122
+ | `get_portfolio` | Stock portfolio with P/L |
123
+ | `get_pnl_today` | Today's profit/loss |
124
+ | `get_order_history` | Order history |
125
+ | `get_order_book` | Today's order book |
126
+ | `get_order_detail` | Single order detail |
127
+ | `get_user_rights` | Shareholder rights: dividends, rights issues... |
128
+
129
+
130
+ ## Requirements
131
+
132
+ - Node.js >= 18
133
+ - Finhay Securities account with API Key
package/README.md CHANGED
@@ -1,67 +1,61 @@
1
1
  # finhay-mcp-server
2
2
 
3
- MCP Server cho Finhay Securities — xem gia co phieu, danh muc dau tu, vang, crypto qua Claude AI.
3
+ <!-- mcp-name: io.github.finhay/mcp-server -->
4
4
 
5
- ## Cai dat
5
+ [Tiếng Việt](README.md) | [English](README.en.md)
6
6
 
7
- ### Buoc 1: Tao API Key
7
+ MCP Server cho Finhay Securities — xem giá cổ phiếu, danh mục đầu tư, vàng, crypto qua Claude AI.
8
8
 
9
- Vao [https://www.finhay.com.vn/finhay-skills](https://www.finhay.com.vn/finhay-skills) → Dang nhap → Tao API Key.
9
+ ## Cài đặt
10
10
 
11
- Ban se nhan duoc:
12
- - **API Key**: `ak_live_xxx`
13
- - **API Secret**: `sk_live_yyy`
14
-
15
- ### Buoc 2: Ket noi voi Claude
11
+ ### Bước 1: Tạo API Key
16
12
 
17
- Chon **mot trong bon** cach sau:
13
+ Vào [https://www.finhay.com.vn/finhay-skills](https://www.finhay.com.vn/finhay-skills) Đăng nhập → Tạo API Key.
18
14
 
19
- #### Cach 1: Cai dat nhanh (can Node.js)
20
-
21
- Neu ban da co Node.js (>= 18), chay lenh sau:
15
+ Bạn sẽ nhận được:
16
+ - **API Key**: `ak_live_xxx`
17
+ - **API Secret**: `sk_live_yyy`
22
18
 
23
- ```bash
24
- npx -y finhay-mcp-server --install
25
- ```
19
+ ### Bước 2: Kết nối với Claude
26
20
 
27
- Script se hoi API Key/Secret (Secret duoc an bang dau `*`), tu dong ghi config vao Claude Desktop.
21
+ Chọn **một trong ba** cách sau:
28
22
 
29
- #### Cach 2: Cai dat tu dong (khong can Node.js)
23
+ #### Cách 1: Cài đặt tự động (không cần Node.js — khuyên dùng)
30
24
 
31
- Mo Terminal (macOS) hoac PowerShell (Windows), dan lenh sau va nhan Enter:
25
+ Mở Terminal (macOS) hoặc PowerShell (Windows), dán lệnh sau nhấn Enter:
32
26
 
33
27
  **macOS:**
34
28
  ```bash
35
- curl -fsSL https://raw.githubusercontent.com/finhay-pro/finhay-skills-hub/main/skills/_shared/scripts/mcp/install.sh | bash
29
+ curl -fsSL https://raw.githubusercontent.com/finhay/mcp-server/main/install.sh | bash
36
30
  ```
37
31
 
38
32
  **Windows (PowerShell):**
39
33
  ```powershell
40
- irm https://raw.githubusercontent.com/finhay-pro/finhay-skills-hub/main/skills/_shared/scripts/mcp/install.ps1 | iex
34
+ irm https://raw.githubusercontent.com/finhay/mcp-server/main/install.ps1 | iex
41
35
  ```
42
36
 
43
- Script se tu dong cai Node.js (neu chua co), hoi API Key/Secret, va cau hinh Claude Desktop.
37
+ Script sẽ tự động cài Node.js (nếu chưa ), hỏi API Key/Secret, cấu hình Claude Desktop.
44
38
 
45
- #### Cach 3: Claude Code CLI
39
+ #### Cách 2: Cài đặt nhanh (cần Node.js)
46
40
 
47
- Neu ban da cai [Claude Code](https://docs.anthropic.com/en/docs/claude-code) va muon su dung trong terminal:
41
+ Nếu bạn đã Node.js (>= 18), chạy lệnh sau:
48
42
 
49
43
  ```bash
50
- claude mcp add finhay -- npx -y finhay-mcp-server
44
+ npx -y finhay-mcp-server --install
51
45
  ```
52
46
 
53
- > Luu y: Cach nay chi them MCP server vao Claude Code CLI, **khong dong bo** sang Claude Desktop. Neu muon dung tren Claude Desktop, hay dung Cach 1, 2 hoac 4.
47
+ Script sẽ hỏi API Key/Secret (Secret được ẩn bằng dấu `*`), tự động ghi config vào Claude Desktop.
54
48
 
55
- #### Cach 4: Cau hinh thu cong
49
+ #### Cách 3: Cấu hình thủ công
56
50
 
57
- **Buoc 3a.** Tao file credentials tai `~/.finhay/credentials/.env`:
51
+ **Bước 3a.** Tạo file credentials tại `~/.finhay/credentials/.env`:
58
52
 
59
53
  ```
60
54
  FINHAY_API_KEY=ak_live_xxx
61
55
  FINHAY_API_SECRET=sk_live_yyy
62
56
  ```
63
57
 
64
- **Buoc 3b.** Them vao file config Claude Desktop:
58
+ **Bước 3b.** Thêm vào file config Claude Desktop:
65
59
  - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
66
60
  - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
67
61
  - Windows (Microsoft Store): `%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json`
@@ -77,61 +71,63 @@ FINHAY_API_SECRET=sk_live_yyy
77
71
  }
78
72
  ```
79
73
 
80
- > API Key/Secret **khong nam** trong file config Claude — duoc luu rieng tai `~/.finhay/credentials/.env` (dung chung voi Finhay Skills).
74
+ > API Key/Secret **không nằm** trong file config Claude — được lưu riêng tại `~/.finhay/credentials/.env` (dùng chung với Finhay Skills).
81
75
 
82
- Sau khi hoan tat, khoi dong lai Claude Desktop la xong.
76
+ Sau khi hoàn tất, khởi động lại Claude Desktop xong.
83
77
 
84
- ### Buoc 3: Su dung
78
+ ### Bước 3: Sử dụng
85
79
 
86
- Mo Claude, hoi:
80
+ Mở Claude, hỏi:
87
81
 
88
- - "Gia co phieu VNM hom nay?"
89
- - "Xem danh muc dau tu cua toi"
90
- - "So sanh FPT va VNM"
91
- - "Gia vang SJC hom nay bao nhieu?"
92
- - "Lai suat tiet kiem ngan hang nao cao nhat?"
93
- - "Chi so CPI Viet Nam gan day?"
82
+ - "Giá cổ phiếu VNM hôm nay?"
83
+ - "Xem danh mục đầu của tôi"
84
+ - "So sánh FPT VNM"
85
+ - "Giá vàng SJC hôm nay bao nhiêu?"
86
+ - "Lãi suất tiết kiệm ngân hàng nào cao nhất?"
87
+ - "Chỉ số CPI Việt Nam gần đây?"
94
88
 
95
89
  ## Tools
96
90
 
97
- ### Thi truong (18 tools)
91
+ ### Thị trường (20 tools)
98
92
 
99
- | Tool | Mo ta |
93
+ | Tool | tả |
100
94
  |------|-------|
101
- | `get_stock_realtime` | Gia co phieu realtime (1 ma, nhieu ma, hoac theo san) |
102
- | `get_price_history_chart` | Lich su gia OHLCV |
103
- | `get_recommendation_reports` | Bao cao phan tich tu chuyen gia |
104
- | `get_funds` | Danh sach quy dau tu |
105
- | `get_fund_portfolio` | Danh muc cua quy |
106
- | `get_fund_months` | Cac thang co du lieu quy |
107
- | `get_gold_prices` | Gia vang (SJC, DOJI, PNJ, BTMC) |
108
- | `get_gold_chart` | Bieu do gia vang |
109
- | `get_gold_providers` | Gia vang theo nha cung cap |
110
- | `get_silver_prices` | Gia bac |
111
- | `get_silver_chart` | Bieu do gia bac |
112
- | `get_all_financial_data` | Tong hop: vang, bac, crypto, lai suat, ty gia |
113
- | `get_bank_interest_rates` | Lai suat tiet kiem ngan hang |
114
- | `get_crypto_top_trending` | Crypto xu huong |
115
- | `get_macro_data` | Chi so vi mo (CPI, PMI, IIP, FED rate...) |
116
- | `get_market_session` | Trang thai phien giao dich |
117
-
118
- ### Tai khoan (11 tools)
119
-
120
- | Tool | Mo ta |
95
+ | `get_stock_realtime` | Giá cổ phiếu realtime (1 mã, nhiều mã, hoặc theo sàn) |
96
+ | `get_price_history_chart` | Lịch sử giá OHLCV |
97
+ | `get_recommendation_reports` | Báo cáo phân tích từ chuyên gia |
98
+ | `get_funds` | Danh sách quỹ đầu |
99
+ | `get_fund_portfolio` | Danh mục của quỹ |
100
+ | `get_fund_months` | Các tháng dữ liệu quỹ |
101
+ | `get_gold_prices` | Giá vàng (SJC, DOJI, PNJ, BTMC) |
102
+ | `get_gold_chart` | Biểu đồ giá vàng |
103
+ | `get_gold_providers` | Giá vàng theo nhà cung cấp |
104
+ | `get_silver_prices` | Giá bạc |
105
+ | `get_silver_chart` | Biểu đồ giá bạc |
106
+ | `get_metal_providers` | Giá vàng + bạc theo nhà cung cấp |
107
+ | `get_all_financial_data` | Tổng hợp: vàng, bạc, crypto, lãi suất, tỷ giá |
108
+ | `get_bank_interest_rates` | Lãi suất tiết kiệm ngân hàng |
109
+ | `get_crypto_top_trending` | Crypto xu hướng |
110
+ | `get_company_financial_overview` | Tổng quan tài chính doanh nghiệp (PE, PB, ROE, EPS...) |
111
+ | `get_company_financial_analysis` | Phân tích tài chính theo năm/quý |
112
+ | `get_financial_statement` | Báo cáo tài chính (BCTC, CDKT, LCTT) |
113
+ | `get_macro_data` | Chỉ số vĩ mô (CPI, PMI, IIP, FED rate...) |
114
+ | `get_market_session` | Trạng thái phiên giao dịch |
115
+
116
+ ### Tài khoản (8 tools)
117
+
118
+ | Tool | Mô tả |
121
119
  |------|-------|
122
- | `get_owner_info` | Thong tin chu tai khoan |
123
- | `get_account_summary` | So du: tien mat, chung khoan, ky quy |
124
- | `get_asset_summary` | Tong tai san |
125
- | `get_portfolio` | Danh muc co phieu voi lai/lo |
126
- | `get_pnl_today` | Lai/lo hom nay |
127
- | `get_order_history` | Lich su lenh |
128
- | `get_order_book` | So lenh trong ngay |
129
- | `get_order_detail` | Chi tiet 1 lenh |
130
- | `get_user_rights` | Quyen co dong: co tuc, quyen mua... |
131
- | `get_trade_info` | Suc mua / so luong ban duoc |
120
+ | `get_account_summary` | Số dư: tiền mặt, chứng khoán, ký quỹ |
121
+ | `get_asset_summary` | Tổng tài sản |
122
+ | `get_portfolio` | Danh mục cổ phiếu với lãi/lỗ |
123
+ | `get_pnl_today` | Lãi/lỗ hôm nay |
124
+ | `get_order_history` | Lịch sử lệnh |
125
+ | `get_order_book` | Sổ lệnh trong ngày |
126
+ | `get_order_detail` | Chi tiết 1 lệnh |
127
+ | `get_user_rights` | Quyền cổ đông: cổ tức, quyền mua... |
132
128
 
133
129
 
134
- ## Yeu cau
130
+ ## Yêu cầu
135
131
 
136
132
  - Node.js >= 18
137
- - Tai khoan Finhay Securities voi API Key
133
+ - Tài khoản Finhay Securities với API Key
@@ -1,11 +1,15 @@
1
1
  import { FinhayClient } from './FinhayClient.js';
2
+ export interface SubAccount {
3
+ id: string;
4
+ type: string;
5
+ subAccountExt: string;
6
+ }
2
7
  export interface AccountInfo {
3
8
  userId: string;
4
- defaultSubAccountId: string;
5
- subAccountIds: string[];
9
+ subAccounts: SubAccount[];
6
10
  }
7
11
  /**
8
- * Fetches and caches account info (userId, subAccountIds) on startup.
12
+ * Fetches and caches account info (userId, subAccounts) on startup.
9
13
  * Tools use this as default when user does not provide subAccountId.
10
14
  */
11
15
  export declare class AccountContext {
@@ -14,6 +18,7 @@ export declare class AccountContext {
14
18
  constructor(client: FinhayClient);
15
19
  init(): Promise<void>;
16
20
  getUserId(): string | undefined;
21
+ getSubAccountByType(type: string): SubAccount | undefined;
17
22
  getDefaultSubAccountId(): string | undefined;
18
23
  getSubAccountIds(): string[];
19
24
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Fetches and caches account info (userId, subAccountIds) on startup.
2
+ * Fetches and caches account info (userId, subAccounts) on startup.
3
3
  * Tools use this as default when user does not provide subAccountId.
4
4
  */
5
5
  export class AccountContext {
@@ -10,24 +10,27 @@ export class AccountContext {
10
10
  }
11
11
  async init() {
12
12
  try {
13
- // Step 1: get userId
13
+ // Step 1: get userId from .data.user_id
14
14
  const meData = await this.client.get('/users/v1/users/me');
15
- const meResult = meData.result ?? meData.data;
16
- const userId = meResult?.user_id ?? meResult?.userId ?? meResult?.id ?? '';
15
+ const userId = meData.data?.user_id ?? '';
17
16
  if (!userId) {
18
- throw new Error('Could not extract userId from /users/v1/users/me');
17
+ throw new Error('Could not extract user_id from /users/v1/users/me');
19
18
  }
20
- // Step 2: get sub-accounts
19
+ // Step 2: get sub-accounts with type and sub_account_ext
21
20
  const subData = await this.client.get(`/users/v1/users/${userId}/sub-accounts`);
22
- const subResult = subData.result ?? subData.data ?? [];
23
- const subAccounts = Array.isArray(subResult) ? subResult : subResult?.subAccounts ?? subResult?.sub_accounts ?? [];
24
- const subAccountIds = subAccounts.map((sa) => sa.subAccountId ?? sa.sub_account_id ?? sa.id ?? '').filter(Boolean);
25
- this.info = {
26
- userId: String(userId),
27
- defaultSubAccountId: subAccountIds[0] ?? '',
28
- subAccountIds,
29
- };
30
- console.error(`[finhay-mcp] Account loaded: userId=${this.info.userId}, subAccounts=[${subAccountIds.join(', ')}]`);
21
+ const subResult = Array.isArray(subData.result) ? subData.result
22
+ : Array.isArray(subData.data) ? subData.data
23
+ : [];
24
+ const subAccounts = subResult
25
+ .map((sa) => ({
26
+ id: sa.id ?? '',
27
+ type: (sa.type ?? '').toUpperCase(),
28
+ subAccountExt: sa.sub_account_ext ?? '',
29
+ }))
30
+ .filter((sa) => sa.id);
31
+ this.info = { userId: String(userId), subAccounts };
32
+ const summary = subAccounts.map((sa) => `${sa.type}=${sa.id}`).join(', ');
33
+ console.error(`[finhay-mcp] Account loaded: userId=${this.info.userId}, subAccounts=[${summary}]`);
31
34
  }
32
35
  catch (err) {
33
36
  console.error(`[finhay-mcp] Warning: could not fetch account info: ${err.message}`);
@@ -37,18 +40,23 @@ export class AccountContext {
37
40
  getUserId() {
38
41
  return this.info?.userId || undefined;
39
42
  }
43
+ getSubAccountByType(type) {
44
+ return this.info?.subAccounts.find((sa) => sa.type === type.toUpperCase());
45
+ }
40
46
  getDefaultSubAccountId() {
41
- return this.info?.defaultSubAccountId || undefined;
47
+ // Prefer NORMAL, fallback to first available
48
+ const normal = this.getSubAccountByType('NORMAL');
49
+ return normal?.id || this.info?.subAccounts[0]?.id || undefined;
42
50
  }
43
51
  getSubAccountIds() {
44
- return this.info?.subAccountIds ?? [];
52
+ return this.info?.subAccounts.map((sa) => sa.id) ?? [];
45
53
  }
46
54
  /**
47
55
  * Returns the given subAccountId if provided, otherwise falls back to default.
48
56
  * Throws if neither is available.
49
57
  */
50
58
  resolveSubAccountId(subAccountId) {
51
- const resolved = subAccountId || this.info?.defaultSubAccountId;
59
+ const resolved = subAccountId || this.getDefaultSubAccountId();
52
60
  if (!resolved) {
53
61
  throw new Error('subAccountId is required. Could not auto-detect — provide it explicitly or check your API credentials.');
54
62
  }
@@ -1,6 +1,6 @@
1
1
  import { registerMarketTools } from './market.js';
2
2
  import { registerPortfolioTools } from './portfolio.js';
3
3
  export function registerAllTools(server, client, account) {
4
- registerMarketTools(server, client); // 18 tools: stock, funds, gold, silver, crypto, macro, etc.
5
- registerPortfolioTools(server, client, account); // 11 tools: account, portfolio, orders, pnl, rights, etc.
4
+ registerMarketTools(server, client); // 20 tools: stock, funds, gold, silver, metals, crypto, macro, company financials, etc.
5
+ registerPortfolioTools(server, client, account); // 8 tools: account, portfolio, orders, pnl, rights, etc.
6
6
  }
@@ -78,6 +78,11 @@ export function registerMarketTools(server, client) {
78
78
  const data = await client.get('/market/financial-data/silver-chart', { days: String(days) });
79
79
  return JSON.stringify(data.data, null, 2);
80
80
  }));
81
+ // --- Metal providers ---
82
+ server.tool('get_metal_providers', 'Get gold and silver prices grouped by provider (superset of gold-providers and silver data)', {}, safeHandler(async () => {
83
+ const data = await client.get('/market/financial-data/metal-providers');
84
+ return JSON.stringify(data.data, null, 2);
85
+ }));
81
86
  // --- Financial data ---
82
87
  server.tool('get_all_financial_data', 'Get all financial data: gold, silver, crypto, bank rates, USD exchange rate', {}, safeHandler(async () => {
83
88
  const data = await client.get('/market/financial-data');
@@ -91,6 +96,42 @@ export function registerMarketTools(server, client) {
91
96
  const data = await client.get('/market/financial-data/cryptos/top-trending');
92
97
  return JSON.stringify(data.data, null, 2);
93
98
  }));
99
+ // --- Company financials ---
100
+ server.tool('get_company_financial_overview', 'Get financial overview for a company: PE, PB, EV/EBITDA, gross margin, ROE, EPS, dividend yield, NIM, ROA, and industry averages', {
101
+ symbol: z.string().describe('Stock symbol (e.g., VNM)'),
102
+ }, safeHandler(async ({ symbol }) => {
103
+ const data = await client.get('/market/company-financial/overview', {
104
+ symbol: symbol.toUpperCase(),
105
+ });
106
+ return JSON.stringify(data.data, null, 2);
107
+ }));
108
+ server.tool('get_company_financial_analysis', 'Get financial analysis entries by year or quarter for a company', {
109
+ symbol: z.string().describe('Stock symbol (e.g., VNM)'),
110
+ period: z.enum(['annual', 'quarterly']).optional().describe('Period type (default: annual)'),
111
+ }, safeHandler(async ({ symbol, period }) => {
112
+ const query = { symbol: symbol.toUpperCase() };
113
+ if (period)
114
+ query.period = period;
115
+ const data = await client.get('/market/company-financial/analysis', query);
116
+ return JSON.stringify(data.data, null, 2);
117
+ }));
118
+ server.tool('get_financial_statement', 'Get financial statements (income statement, balance sheet, or cash flow) for a company', {
119
+ symbol: z.string().describe('Stock symbol (e.g., VNM)'),
120
+ type: z.enum(['income-statement', 'balance-sheet', 'cash-flow']).describe('Statement type'),
121
+ period: z.enum(['annual', 'quarterly']).optional().describe('Period type'),
122
+ limit: z.number().min(1).max(5).optional().describe('Number of periods to return (1-5, default: 5)'),
123
+ }, safeHandler(async ({ symbol, type, period, limit }) => {
124
+ const query = {
125
+ symbol: symbol.toUpperCase(),
126
+ type,
127
+ };
128
+ if (period)
129
+ query.period = period;
130
+ if (limit)
131
+ query.limit = String(limit);
132
+ const data = await client.get('/market/v2/financial-statement/statement', query);
133
+ return JSON.stringify(data.data, null, 2);
134
+ }));
94
135
  // --- Macro ---
95
136
  server.tool('get_macro_data', 'Get macroeconomic indicators for Vietnam or US (CPI, PMI, IIP, FED rate, etc.)', {
96
137
  type: z.enum([
@@ -1,11 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { safeHandler } from '../utils/safeTool.js';
3
3
  export function registerPortfolioTools(server, client, account) {
4
- // --- Owner ---
5
- server.tool('get_owner_info', 'Get owner identity info (name, accounts, sub-account IDs, etc.)', {}, safeHandler(async () => {
6
- const data = await client.get('/users/v1/users/me');
7
- return JSON.stringify(data.result, null, 2);
8
- }));
9
4
  // --- Account summary ---
10
5
  server.tool('get_account_summary', 'Get account balance summary: cash, securities value, margin, net asset value', {
11
6
  subAccountId: z.string().optional().describe('Sub-account ID (auto-detected if omitted)'),
@@ -16,10 +11,10 @@ export function registerPortfolioTools(server, client, account) {
16
11
  }));
17
12
  // --- Asset summary ---
18
13
  server.tool('get_asset_summary', 'Get asset summary with total valuation', {
19
- subAccountId: z.string().optional().describe('Sub-account ID (auto-detected if omitted)'),
20
- }, safeHandler(async ({ subAccountId }) => {
21
- const id = account.resolveSubAccountId(subAccountId);
22
- const data = await client.get(`/trading/sub-accounts/${id}/asset-summary`);
14
+ userId: z.string().optional().describe('User ID (auto-detected if omitted)'),
15
+ }, safeHandler(async ({ userId }) => {
16
+ const uid = account.resolveUserId(userId);
17
+ const data = await client.get(`/users/v4/users/${uid}/assets/summary`);
23
18
  return JSON.stringify(data.data, null, 2);
24
19
  }));
25
20
  // --- Portfolio ---
@@ -85,9 +80,10 @@ export function registerPortfolioTools(server, client, account) {
85
80
  fromDate: z.string().optional().describe('Start date (YYYY-MM-DD)'),
86
81
  toDate: z.string().optional().describe('End date (YYYY-MM-DD)'),
87
82
  catType: z.string().optional().describe('Category type, comma-separated or ALL (default: ALL)'),
83
+ isCom: z.string().optional().describe('Commission filter (default: ALL)'),
88
84
  symbol: z.string().optional().describe('Filter by symbol (default: ALL)'),
89
85
  status: z.string().optional().describe('Status filter, comma-separated or ALL (default: ALL)'),
90
- }, safeHandler(async ({ subAccountId, fromDate, toDate, catType, symbol, status }) => {
86
+ }, safeHandler(async ({ subAccountId, fromDate, toDate, catType, isCom, symbol, status }) => {
91
87
  const id = account.resolveSubAccountId(subAccountId);
92
88
  const query = {};
93
89
  if (fromDate)
@@ -96,6 +92,8 @@ export function registerPortfolioTools(server, client, account) {
96
92
  query.toDate = toDate;
97
93
  if (catType)
98
94
  query.catType = catType;
95
+ if (isCom)
96
+ query.isCom = isCom;
99
97
  if (symbol)
100
98
  query.symbol = symbol.toUpperCase();
101
99
  if (status)
@@ -103,19 +101,4 @@ export function registerPortfolioTools(server, client, account) {
103
101
  const data = await client.get(`/trading/v5/account/${id}/user-rights`, query);
104
102
  return JSON.stringify(data.result, null, 2);
105
103
  }));
106
- // --- Trade info (pre-order check) ---
107
- server.tool('get_trade_info', 'Get buying power (BUY) or available quantity (SELL) before placing an order', {
108
- subAccountId: z.string().optional().describe('Sub-account ID (auto-detected if omitted)'),
109
- symbol: z.string().describe('Stock symbol'),
110
- side: z.enum(['BUY', 'SELL']).describe('Order side'),
111
- quotePrice: z.number().describe('Quote price in VND'),
112
- }, safeHandler(async ({ subAccountId, symbol, side, quotePrice }) => {
113
- const id = account.resolveSubAccountId(subAccountId);
114
- const data = await client.get(`/trading/sub-accounts/${id}/trade-info`, {
115
- symbol: symbol.toUpperCase(),
116
- side,
117
- quote_price: String(quotePrice),
118
- });
119
- return JSON.stringify(data.result, null, 2);
120
- }));
121
104
  }
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "finhay-mcp-server",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
+ "mcpName": "io.github.finhay/mcp-server",
4
5
  "description": "Finhay MCP Server — xem gia co phieu, danh muc dau tu qua Claude AI",
5
6
  "type": "module",
6
7
  "license": "MIT",