finhay-mcp-server 1.0.9 → 1.1.1
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 +4 -4
- package/README.md +4 -4
- package/dist/client/FinhayClient.js +3 -0
- package/dist/index.js +1 -1
- package/dist/install.js +20 -10
- package/dist/tools/market.js +54 -22
- package/dist/tools/portfolio.js +1 -1
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -93,11 +93,9 @@ Open Claude and ask:
|
|
|
93
93
|
| Tool | Description |
|
|
94
94
|
|------|-------------|
|
|
95
95
|
| `get_stock_realtime` | Realtime stock prices (single, multiple, or by exchange) |
|
|
96
|
-
| `
|
|
96
|
+
| `get_news` | Stock corporate events (dividends, rights issues, AGM...) |
|
|
97
|
+
| `get_price_history_chart` | OHLCV price history (1D/5/15/30/1H/4H) |
|
|
97
98
|
| `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
99
|
| `get_gold_prices` | Gold prices (SJC, DOJI, PNJ, BTMC) |
|
|
102
100
|
| `get_gold_chart` | Gold price chart |
|
|
103
101
|
| `get_gold_providers` | Gold prices by provider |
|
|
@@ -107,6 +105,8 @@ Open Claude and ask:
|
|
|
107
105
|
| `get_all_financial_data` | All-in-one: gold, silver, crypto, rates, FX |
|
|
108
106
|
| `get_bank_interest_rates` | Bank savings interest rates |
|
|
109
107
|
| `get_crypto_top_trending` | Top trending cryptocurrencies |
|
|
108
|
+
| `get_market_data` | Global indices (SP500, Nikkei...), big-tech stocks, commodities, forex |
|
|
109
|
+
| `get_economic_calendar_events` | Upcoming economic events (CPI, Fed meetings, PMI...) |
|
|
110
110
|
| `get_company_financial_overview` | Company financial overview (PE, PB, ROE, EPS...) |
|
|
111
111
|
| `get_company_financial_analysis` | Financial analysis by year/quarter |
|
|
112
112
|
| `get_financial_statement` | Financial statements (income, balance sheet, cash flow) |
|
package/README.md
CHANGED
|
@@ -93,11 +93,9 @@ Mở Claude, hỏi:
|
|
|
93
93
|
| Tool | Mô tả |
|
|
94
94
|
|------|-------|
|
|
95
95
|
| `get_stock_realtime` | Giá cổ phiếu realtime (1 mã, nhiều mã, hoặc theo sàn) |
|
|
96
|
-
| `
|
|
96
|
+
| `get_news` | Sự kiện doanh nghiệp (cổ tức, quyền mua, ĐHĐCĐ...) |
|
|
97
|
+
| `get_price_history_chart` | Lịch sử giá OHLCV (1D/5/15/30/1H/4H) |
|
|
97
98
|
| `get_recommendation_reports` | Báo cáo phân tích từ chuyên gia |
|
|
98
|
-
| `get_funds` | Danh sách quỹ đầu tư |
|
|
99
|
-
| `get_fund_portfolio` | Danh mục của quỹ |
|
|
100
|
-
| `get_fund_months` | Các tháng có dữ liệu quỹ |
|
|
101
99
|
| `get_gold_prices` | Giá vàng (SJC, DOJI, PNJ, BTMC) |
|
|
102
100
|
| `get_gold_chart` | Biểu đồ giá vàng |
|
|
103
101
|
| `get_gold_providers` | Giá vàng theo nhà cung cấp |
|
|
@@ -107,6 +105,8 @@ Mở Claude, hỏi:
|
|
|
107
105
|
| `get_all_financial_data` | Tổng hợp: vàng, bạc, crypto, lãi suất, tỷ giá |
|
|
108
106
|
| `get_bank_interest_rates` | Lãi suất tiết kiệm ngân hàng |
|
|
109
107
|
| `get_crypto_top_trending` | Crypto xu hướng |
|
|
108
|
+
| `get_market_data` | Dữ liệu chỉ số global (SP500, Nikkei...), big-tech, hàng hoá, forex |
|
|
109
|
+
| `get_economic_calendar_events` | Sự kiện kinh tế sắp tới (CPI, họp Fed, PMI...) |
|
|
110
110
|
| `get_company_financial_overview` | Tổng quan tài chính doanh nghiệp (PE, PB, ROE, EPS...) |
|
|
111
111
|
| `get_company_financial_analysis` | Phân tích tài chính theo năm/quý |
|
|
112
112
|
| `get_financial_statement` | Báo cáo tài chính (BCTC, CDKT, LCTT) |
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const account = new AccountContext(client);
|
|
|
17
17
|
await account.init();
|
|
18
18
|
const server = new McpServer({
|
|
19
19
|
name: 'finhay-mcp-server',
|
|
20
|
-
version: '1.
|
|
20
|
+
version: '1.1.0',
|
|
21
21
|
});
|
|
22
22
|
registerAllTools(server, client, account);
|
|
23
23
|
const transport = new StdioServerTransport();
|
package/dist/install.js
CHANGED
|
@@ -123,13 +123,13 @@ function updateClaudeConfig() {
|
|
|
123
123
|
args: ['-y', 'finhay-mcp-server'],
|
|
124
124
|
};
|
|
125
125
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
126
|
-
|
|
126
|
+
return configPath;
|
|
127
127
|
}
|
|
128
128
|
async function main() {
|
|
129
129
|
console.log('\n Finhay MCP Server — Cai dat cho Claude Desktop\n');
|
|
130
|
-
console.log(' Tao API Key tai: https://www.finhay.com.vn/finhay-skills\n');
|
|
131
130
|
let apiKey = '';
|
|
132
131
|
let apiSecret = '';
|
|
132
|
+
let overwroteCreds = false;
|
|
133
133
|
if (fs.existsSync(CREDENTIALS_PATH)) {
|
|
134
134
|
const content = fs.readFileSync(CREDENTIALS_PATH, 'utf-8');
|
|
135
135
|
const keyMatch = content.match(/FINHAY_API_KEY=(.+)/);
|
|
@@ -138,8 +138,11 @@ async function main() {
|
|
|
138
138
|
const maskedKey = keyMatch[1].trim().slice(0, 8) + '***';
|
|
139
139
|
console.log(` Tim thay credentials tai ${CREDENTIALS_PATH}`);
|
|
140
140
|
console.log(` API Key: ${maskedKey}\n`);
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
141
|
+
const replace = await ask('Ban co muon thay the khong? (y/n): ');
|
|
142
|
+
if (replace.toLowerCase() === 'y') {
|
|
143
|
+
overwroteCreds = true;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
143
146
|
apiKey = keyMatch[1].trim();
|
|
144
147
|
apiSecret = secretMatch[1].trim();
|
|
145
148
|
}
|
|
@@ -147,12 +150,16 @@ async function main() {
|
|
|
147
150
|
}
|
|
148
151
|
}
|
|
149
152
|
if (!apiKey) {
|
|
150
|
-
apiKey =
|
|
153
|
+
apiKey = overwroteCreds
|
|
154
|
+
? await ask('Nhap API Key moi: ')
|
|
155
|
+
: await ask('Nhap API Key: ');
|
|
151
156
|
if (!apiKey) {
|
|
152
157
|
console.error('\n Loi: API Key khong duoc de trong.\n');
|
|
153
158
|
process.exit(1);
|
|
154
159
|
}
|
|
155
|
-
apiSecret =
|
|
160
|
+
apiSecret = overwroteCreds
|
|
161
|
+
? await askMasked('Nhap Secret Key moi: ')
|
|
162
|
+
: await askMasked('Nhap Secret Key: ');
|
|
156
163
|
if (!apiSecret) {
|
|
157
164
|
console.error('\n Loi: API Secret khong duoc de trong.\n');
|
|
158
165
|
process.exit(1);
|
|
@@ -162,11 +169,14 @@ async function main() {
|
|
|
162
169
|
FINHAY_API_SECRET: apiSecret,
|
|
163
170
|
FINHAY_BASE_URL: 'https://open-api.fhsc.com.vn',
|
|
164
171
|
});
|
|
165
|
-
console.log(`\n Credentials: ${CREDENTIALS_PATH} (permission: 600)\n`);
|
|
166
172
|
}
|
|
167
|
-
updateClaudeConfig();
|
|
168
|
-
console.log(
|
|
169
|
-
console.log('
|
|
173
|
+
const configPath = updateClaudeConfig();
|
|
174
|
+
console.log();
|
|
175
|
+
console.log(overwroteCreds ? 'Da Cap nhat Credentials thanh cong!' : 'Da cai dat thanh cong!');
|
|
176
|
+
console.log(` - Credentials: ${CREDENTIALS_PATH}`);
|
|
177
|
+
console.log(` - Claude Desktop config: ${configPath}`);
|
|
178
|
+
console.log('Hay khoi dong lai ung dung de su dung');
|
|
179
|
+
console.log();
|
|
170
180
|
}
|
|
171
181
|
export const run = main().catch((err) => {
|
|
172
182
|
console.error('Loi:', err.message);
|
package/dist/tools/market.js
CHANGED
|
@@ -17,10 +17,29 @@ export function registerMarketTools(server, client) {
|
|
|
17
17
|
const data = await client.get('/market/stock-realtime', query);
|
|
18
18
|
return JSON.stringify(data.result, null, 2);
|
|
19
19
|
}));
|
|
20
|
+
// --- News (corporate events) ---
|
|
21
|
+
server.tool('get_news', 'Get stock corporate events (rights issues, dividends, AGM dates, etc.) filtered by symbol(s) and/or date range. Dates must be DD/MM/YYYY format.', {
|
|
22
|
+
stock: z.string().optional().describe('Single stock symbol (e.g., VNM)'),
|
|
23
|
+
stocks: z.string().optional().describe('Comma-separated symbols (e.g., VNM,VIC,HPG)'),
|
|
24
|
+
from_date: z.string().optional().describe('Start date in DD/MM/YYYY (defaults to 1 year ago)'),
|
|
25
|
+
to_date: z.string().optional().describe('End date in DD/MM/YYYY (only applied when both dates provided)'),
|
|
26
|
+
}, safeHandler(async ({ stock, stocks, from_date, to_date }) => {
|
|
27
|
+
const query = {};
|
|
28
|
+
if (stock)
|
|
29
|
+
query.stock = stock.toUpperCase();
|
|
30
|
+
if (stocks)
|
|
31
|
+
query.stocks = stocks.toUpperCase();
|
|
32
|
+
if (from_date)
|
|
33
|
+
query.from_date = from_date;
|
|
34
|
+
if (to_date)
|
|
35
|
+
query.to_date = to_date;
|
|
36
|
+
const data = await client.get('/market/news', query);
|
|
37
|
+
return JSON.stringify(data.result, null, 2);
|
|
38
|
+
}));
|
|
20
39
|
// --- Price history chart ---
|
|
21
40
|
server.tool('get_price_history_chart', 'Get OHLCV price history chart for a stock. Timestamps must be Unix seconds (not milliseconds).', {
|
|
22
41
|
symbol: z.string().describe('Stock symbol (e.g., FPT)'),
|
|
23
|
-
resolution: z.
|
|
42
|
+
resolution: z.enum(['1D', '5', '15', '30', '1H', '4H']).optional().describe('Chart resolution: 1D (daily), 5/15/30 (minutes), 1H, 4H. Default 1D.').default('1D'),
|
|
24
43
|
from: z.number().describe('Start timestamp in Unix SECONDS'),
|
|
25
44
|
to: z.number().describe('End timestamp in Unix SECONDS'),
|
|
26
45
|
}, safeHandler(async ({ symbol, resolution, from, to }) => {
|
|
@@ -37,25 +56,6 @@ export function registerMarketTools(server, client) {
|
|
|
37
56
|
const data = await client.get(`/market/recommendation-reports/${symbol.toUpperCase()}`);
|
|
38
57
|
return JSON.stringify(data.data, null, 2);
|
|
39
58
|
}));
|
|
40
|
-
// --- Funds ---
|
|
41
|
-
server.tool('get_funds', 'Get list of all available investment funds with performance data', {}, safeHandler(async () => {
|
|
42
|
-
const data = await client.get('/market/funds');
|
|
43
|
-
return JSON.stringify(data.data, null, 2);
|
|
44
|
-
}));
|
|
45
|
-
server.tool('get_fund_portfolio', 'Get portfolio composition of a specific fund', {
|
|
46
|
-
fund: z.string().describe('Fund code (e.g., DCDS)'),
|
|
47
|
-
month: z.string().optional().describe('Month in YYYY-MM format (defaults to latest)'),
|
|
48
|
-
}, safeHandler(async ({ fund, month }) => {
|
|
49
|
-
const query = {};
|
|
50
|
-
if (month)
|
|
51
|
-
query.month = month;
|
|
52
|
-
const data = await client.get(`/market/funds/${fund}/portfolio`, query);
|
|
53
|
-
return JSON.stringify(data.data, null, 2);
|
|
54
|
-
}));
|
|
55
|
-
server.tool('get_fund_months', 'Get available months for a fund portfolio', { fund: z.string().describe('Fund code (e.g., DCDS)') }, safeHandler(async ({ fund }) => {
|
|
56
|
-
const data = await client.get(`/market/funds/${fund}/months`);
|
|
57
|
-
return JSON.stringify(data.data, null, 2);
|
|
58
|
-
}));
|
|
59
59
|
// --- Gold ---
|
|
60
60
|
server.tool('get_gold_prices', 'Get current gold prices from Vietnamese providers (SJC, DOJI, PNJ, BTMC)', {}, safeHandler(async () => {
|
|
61
61
|
const data = await client.get('/market/financial-data/gold');
|
|
@@ -96,6 +96,38 @@ export function registerMarketTools(server, client) {
|
|
|
96
96
|
const data = await client.get('/market/financial-data/cryptos/top-trending');
|
|
97
97
|
return JSON.stringify(data.data, null, 2);
|
|
98
98
|
}));
|
|
99
|
+
// --- Market data (global indices, big-tech, commodities, forex) ---
|
|
100
|
+
server.tool('get_market_data', 'Get historical data points for a global market index, big-tech stock, commodity, or forex pair. Results ordered descending by date.', {
|
|
101
|
+
type: z.enum([
|
|
102
|
+
'SP500', 'DOW_JONES', 'NASDAQ', 'RUSSELL2000', 'VIX', 'DXY',
|
|
103
|
+
'KOSPI', 'HANGSENG', 'SHANGHAI', 'NIKKEI',
|
|
104
|
+
'APPLE', 'MICROSOFT', 'ALPHABET', 'AMAZON', 'META', 'NVIDIA', 'TESLA',
|
|
105
|
+
'GOLD', 'SILVER', 'COPPER', 'CRUDE_OIL', 'BRENT_OIL', 'NATURAL_GAS',
|
|
106
|
+
'EURUSD', 'USDJPY', 'GBPUSD',
|
|
107
|
+
]).describe('Market data type (US/Asian indices, big-tech stocks, commodities, forex)'),
|
|
108
|
+
limit: z.number().min(1).max(500).optional().describe('Number of data points (default 50, max 500)'),
|
|
109
|
+
}, safeHandler(async ({ type, limit }) => {
|
|
110
|
+
const query = { type };
|
|
111
|
+
if (limit)
|
|
112
|
+
query.limit = String(limit);
|
|
113
|
+
const data = await client.get('/market/financial-data/market', query);
|
|
114
|
+
return JSON.stringify(data.data, null, 2);
|
|
115
|
+
}));
|
|
116
|
+
// --- Economic calendar events ---
|
|
117
|
+
server.tool('get_economic_calendar_events', 'Get upcoming global economic events (CPI releases, Fed meetings, PMI announcements, etc.)', {
|
|
118
|
+
weeks: z.number().optional().describe('Number of weeks ahead to fetch (default 1)'),
|
|
119
|
+
country: z.enum([
|
|
120
|
+
'China', 'Euro Area', 'Japan', 'United States', 'United Kingdom', 'Vietnam',
|
|
121
|
+
]).optional().describe('Filter by country (omit for all countries)'),
|
|
122
|
+
}, safeHandler(async ({ weeks, country }) => {
|
|
123
|
+
const query = {};
|
|
124
|
+
if (weeks)
|
|
125
|
+
query.weeks = String(weeks);
|
|
126
|
+
if (country)
|
|
127
|
+
query.country = country;
|
|
128
|
+
const data = await client.get('/market/financial-data/economic-calendar-events', query);
|
|
129
|
+
return JSON.stringify(data.data, null, 2);
|
|
130
|
+
}));
|
|
99
131
|
// --- Company financials ---
|
|
100
132
|
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
133
|
symbol: z.string().describe('Stock symbol (e.g., VNM)'),
|
|
@@ -133,13 +165,13 @@ export function registerMarketTools(server, client) {
|
|
|
133
165
|
return JSON.stringify(data.data, null, 2);
|
|
134
166
|
}));
|
|
135
167
|
// --- Macro ---
|
|
136
|
-
server.tool('get_macro_data', 'Get macroeconomic indicators for Vietnam or US (CPI, PMI, IIP, FED rate, etc.)', {
|
|
168
|
+
server.tool('get_macro_data', 'Get macroeconomic indicators for Vietnam or US (CPI, PMI, IIP, FED rate, etc.). JP and DE are only valid when type=GOVERNMENT_10Y_BOND_YIELD.', {
|
|
137
169
|
type: z.enum([
|
|
138
170
|
'IIP', 'CPI', 'PMI', 'PCE', 'CORE_PCE', 'NFP', 'GOODS_RETAIL', 'SERVICE_RETAIL',
|
|
139
171
|
'TOTAL_EXPORT', 'FDI_EXPORT', 'DOMESTIC_EXPORT', 'FED_FUNDS_RATE', 'INTERBANK_RATE',
|
|
140
172
|
'GOVERNMENT_10Y_BOND_YIELD', 'UNEMPLOYMENT_RATE',
|
|
141
173
|
]).describe('Macro indicator type'),
|
|
142
|
-
country: z.enum(['VN', 'US']).describe('Country code'),
|
|
174
|
+
country: z.enum(['VN', 'US', 'JP', 'DE']).describe('Country code (JP/DE only for GOVERNMENT_10Y_BOND_YIELD)'),
|
|
143
175
|
period: z.enum(['ONE_MONTH', 'ONE_YEAR', 'YTD']).optional().describe('Time period filter'),
|
|
144
176
|
}, safeHandler(async ({ type, country, period }) => {
|
|
145
177
|
const query = { type, country };
|
package/dist/tools/portfolio.js
CHANGED
|
@@ -14,7 +14,7 @@ export function registerPortfolioTools(server, client, account) {
|
|
|
14
14
|
userId: z.string().optional().describe('User ID (auto-detected if omitted)'),
|
|
15
15
|
}, safeHandler(async ({ userId }) => {
|
|
16
16
|
const uid = account.resolveUserId(userId);
|
|
17
|
-
const data = await client.get(`/users/
|
|
17
|
+
const data = await client.get(`/users/v3/users/${uid}/assets/summary`);
|
|
18
18
|
return JSON.stringify(data.data, null, 2);
|
|
19
19
|
}));
|
|
20
20
|
// --- Portfolio ---
|