stockmatrix-mcp 0.1.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.
- package/LICENSE +21 -0
- package/README.md +133 -0
- package/dist/fetch-helper.d.ts +3 -0
- package/dist/fetch-helper.js +45 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +26 -0
- package/dist/tools/get-stock-theme.d.ts +2 -0
- package/dist/tools/get-stock-theme.js +23 -0
- package/dist/tools/get-theme-detail.d.ts +2 -0
- package/dist/tools/get-theme-detail.js +23 -0
- package/dist/tools/get-theme-history.d.ts +2 -0
- package/dist/tools/get-theme-history.js +23 -0
- package/dist/tools/get-theme-ranking.d.ts +2 -0
- package/dist/tools/get-theme-ranking.js +42 -0
- package/dist/tools/search-themes.d.ts +2 -0
- package/dist/tools/search-themes.js +23 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 StockMatrix
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# stockmatrix-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for Korean stock market theme lifecycle analysis. Provides real-time theme scores, lifecycle stages, related stocks, and news for 250+ KOSPI/KOSDAQ investment themes.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx -y stockmatrix-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
### Claude Desktop
|
|
14
|
+
|
|
15
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"stockmatrix": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": ["-y", "stockmatrix-mcp"]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Cursor
|
|
29
|
+
|
|
30
|
+
Add to `.cursor/mcp.json`:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"stockmatrix": {
|
|
36
|
+
"command": "npx",
|
|
37
|
+
"args": ["-y", "stockmatrix-mcp"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### VS Code
|
|
44
|
+
|
|
45
|
+
Add to `.vscode/mcp.json`:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"servers": {
|
|
50
|
+
"stockmatrix": {
|
|
51
|
+
"command": "npx",
|
|
52
|
+
"args": ["-y", "stockmatrix-mcp"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Available Tools
|
|
59
|
+
|
|
60
|
+
### `get_theme_ranking`
|
|
61
|
+
|
|
62
|
+
한국 주식시장 테마 생명주기 랭킹을 조회합니다. Retrieves theme lifecycle rankings by stage.
|
|
63
|
+
|
|
64
|
+
| Parameter | Type | Required | Description |
|
|
65
|
+
|-----------|------|----------|-------------|
|
|
66
|
+
| `stage` | string | No | Filter by stage: `emerging`, `growth`, `peak`, `decline`, `reigniting` |
|
|
67
|
+
|
|
68
|
+
### `get_theme_detail`
|
|
69
|
+
|
|
70
|
+
특정 테마의 상세 정보를 조회합니다. Gets detailed theme info including score, stage, related stocks, and news.
|
|
71
|
+
|
|
72
|
+
| Parameter | Type | Required | Description |
|
|
73
|
+
|-----------|------|----------|-------------|
|
|
74
|
+
| `theme_id` | string (UUID) | Yes | Theme UUID |
|
|
75
|
+
|
|
76
|
+
### `get_theme_history`
|
|
77
|
+
|
|
78
|
+
테마의 최근 30일 점수 이력을 조회합니다. Returns 30-day score history for a theme.
|
|
79
|
+
|
|
80
|
+
| Parameter | Type | Required | Description |
|
|
81
|
+
|-----------|------|----------|-------------|
|
|
82
|
+
| `theme_id` | string (UUID) | Yes | Theme UUID |
|
|
83
|
+
|
|
84
|
+
### `search_themes`
|
|
85
|
+
|
|
86
|
+
테마를 검색합니다. Searches themes by name in Korean or English.
|
|
87
|
+
|
|
88
|
+
| Parameter | Type | Required | Description |
|
|
89
|
+
|-----------|------|----------|-------------|
|
|
90
|
+
| `query` | string | Yes | Search query (e.g. `"AI"`, `"반도체"`, `"삼성전자"`) |
|
|
91
|
+
|
|
92
|
+
### `get_stock_theme`
|
|
93
|
+
|
|
94
|
+
특정 종목이 속한 테마를 조회합니다. Finds themes related to a specific stock code.
|
|
95
|
+
|
|
96
|
+
| Parameter | Type | Required | Description |
|
|
97
|
+
|-----------|------|----------|-------------|
|
|
98
|
+
| `symbol` | string | Yes | 6-digit Korean stock code (e.g. `"005930"` for Samsung) |
|
|
99
|
+
|
|
100
|
+
## Environment Variables
|
|
101
|
+
|
|
102
|
+
| Variable | Default | Description |
|
|
103
|
+
|----------|---------|-------------|
|
|
104
|
+
| `STOCKMATRIX_API_URL` | `https://stockmatrix.co.kr` | API base URL |
|
|
105
|
+
|
|
106
|
+
## Examples
|
|
107
|
+
|
|
108
|
+
**"What are the hottest stock themes in Korea right now?"**
|
|
109
|
+
→ `get_theme_ranking` with `stage: "growth"`
|
|
110
|
+
|
|
111
|
+
**"Tell me about the semiconductor theme"**
|
|
112
|
+
→ `search_themes` with `query: "반도체"` → `get_theme_detail` with the returned theme ID
|
|
113
|
+
|
|
114
|
+
**"What themes is Samsung Electronics part of?"**
|
|
115
|
+
→ `get_stock_theme` with `symbol: "005930"`
|
|
116
|
+
|
|
117
|
+
## Data Sources
|
|
118
|
+
|
|
119
|
+
- Naver DataLab search interest trends
|
|
120
|
+
- Naver Finance theme stock data
|
|
121
|
+
- Naver News article collection
|
|
122
|
+
- KRX (Korea Exchange) market data
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
MIT
|
|
127
|
+
|
|
128
|
+
## Links
|
|
129
|
+
|
|
130
|
+
- [Website](https://stockmatrix.co.kr)
|
|
131
|
+
- [Developer Guide](https://stockmatrix.co.kr/developers)
|
|
132
|
+
- [GitHub](https://github.com/MongLong0214/stock-ai-newsletter)
|
|
133
|
+
- [llms.txt](https://stockmatrix.co.kr/llms.txt)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const BASE_URL = process.env.STOCKMATRIX_API_URL || 'https://stockmatrix.co.kr';
|
|
2
|
+
// 시작 시 URL 유효성 검증
|
|
3
|
+
try {
|
|
4
|
+
new URL(BASE_URL);
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
throw new Error(`Invalid STOCKMATRIX_API_URL: "${BASE_URL}" is not a valid URL`);
|
|
8
|
+
}
|
|
9
|
+
export const fetchApi = async (path, params) => {
|
|
10
|
+
const url = new URL(path, BASE_URL);
|
|
11
|
+
if (params) {
|
|
12
|
+
for (const [key, value] of Object.entries(params)) {
|
|
13
|
+
url.searchParams.set(key, value);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const response = await fetch(url.toString(), {
|
|
17
|
+
headers: { Accept: 'application/json' },
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
const errorText = await response.text().catch(() => 'Unknown error');
|
|
21
|
+
throw new Error(`API request failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
22
|
+
}
|
|
23
|
+
const contentType = response.headers.get('content-type') || '';
|
|
24
|
+
if (!contentType.includes('application/json')) {
|
|
25
|
+
const preview = await response.text().catch(() => '');
|
|
26
|
+
throw new Error(`Expected JSON response but got ${contentType || 'unknown'}: ${preview.slice(0, 200)}`);
|
|
27
|
+
}
|
|
28
|
+
const json = (await response.json());
|
|
29
|
+
if (json !== null &&
|
|
30
|
+
typeof json === 'object' &&
|
|
31
|
+
'success' in json &&
|
|
32
|
+
'data' in json) {
|
|
33
|
+
const wrapped = json;
|
|
34
|
+
if (!wrapped.success) {
|
|
35
|
+
throw new Error(wrapped.error?.message || 'API returned unsuccessful response');
|
|
36
|
+
}
|
|
37
|
+
return wrapped.data;
|
|
38
|
+
}
|
|
39
|
+
return json;
|
|
40
|
+
};
|
|
41
|
+
export const formatResult = (data) => JSON.stringify(data, null, 2);
|
|
42
|
+
export const formatError = (error) => {
|
|
43
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
44
|
+
return `Error: ${message}`;
|
|
45
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { registerGetThemeRanking } from './tools/get-theme-ranking.js';
|
|
5
|
+
import { registerGetThemeDetail } from './tools/get-theme-detail.js';
|
|
6
|
+
import { registerGetThemeHistory } from './tools/get-theme-history.js';
|
|
7
|
+
import { registerSearchThemes } from './tools/search-themes.js';
|
|
8
|
+
import { registerGetStockTheme } from './tools/get-stock-theme.js';
|
|
9
|
+
const server = new McpServer({
|
|
10
|
+
name: 'stockmatrix-mcp',
|
|
11
|
+
version: '0.1.0',
|
|
12
|
+
});
|
|
13
|
+
registerGetThemeRanking(server);
|
|
14
|
+
registerGetThemeDetail(server);
|
|
15
|
+
registerGetThemeHistory(server);
|
|
16
|
+
registerSearchThemes(server);
|
|
17
|
+
registerGetStockTheme(server);
|
|
18
|
+
const main = async () => {
|
|
19
|
+
const transport = new StdioServerTransport();
|
|
20
|
+
await server.connect(transport);
|
|
21
|
+
console.error('StockMatrix MCP server running on stdio');
|
|
22
|
+
};
|
|
23
|
+
main().catch((error) => {
|
|
24
|
+
console.error('Fatal error in main():', error);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { fetchApi, formatResult, formatError } from '../fetch-helper.js';
|
|
3
|
+
export const registerGetStockTheme = (server) => {
|
|
4
|
+
server.tool('get_stock_theme', '특정 종목이 속한 테마를 조회합니다. 종목 코드로 관련 테마 정보를 확인할 수 있습니다.', {
|
|
5
|
+
symbol: z
|
|
6
|
+
.string()
|
|
7
|
+
.regex(/^\d{6}$/, 'Korean stock code must be 6 digits')
|
|
8
|
+
.describe('Korean stock code (e.g. "005930" for Samsung Electronics, "000660" for SK Hynix)'),
|
|
9
|
+
}, async ({ symbol }) => {
|
|
10
|
+
try {
|
|
11
|
+
const data = await fetchApi(`/api/tli/stocks/${symbol}/theme`);
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: 'text', text: formatResult(data) }],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: 'text', text: formatError(error) }],
|
|
19
|
+
isError: true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { fetchApi, formatResult, formatError } from '../fetch-helper.js';
|
|
3
|
+
export const registerGetThemeDetail = (server) => {
|
|
4
|
+
server.tool('get_theme_detail', '특정 테마의 상세 정보를 조회합니다. 테마 점수, 생명주기 단계, 관련 종목, 뉴스 등을 포함합니다.', {
|
|
5
|
+
theme_id: z
|
|
6
|
+
.string()
|
|
7
|
+
.uuid('Theme ID must be a valid UUID')
|
|
8
|
+
.describe('Theme UUID (e.g. "a1b2c3d4-e5f6-7890-abcd-ef1234567890")'),
|
|
9
|
+
}, async ({ theme_id }) => {
|
|
10
|
+
try {
|
|
11
|
+
const data = await fetchApi(`/api/tli/themes/${theme_id}`);
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: 'text', text: formatResult(data) }],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: 'text', text: formatError(error) }],
|
|
19
|
+
isError: true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { fetchApi, formatResult, formatError } from '../fetch-helper.js';
|
|
3
|
+
export const registerGetThemeHistory = (server) => {
|
|
4
|
+
server.tool('get_theme_history', '테마의 최근 30일 점수 이력을 조회합니다. 생명주기 추이를 파악할 수 있습니다.', {
|
|
5
|
+
theme_id: z
|
|
6
|
+
.string()
|
|
7
|
+
.uuid('Theme ID must be a valid UUID')
|
|
8
|
+
.describe('Theme UUID (e.g. "a1b2c3d4-e5f6-7890-abcd-ef1234567890")'),
|
|
9
|
+
}, async ({ theme_id }) => {
|
|
10
|
+
try {
|
|
11
|
+
const data = await fetchApi(`/api/tli/themes/${theme_id}/history`);
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: 'text', text: formatResult(data) }],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: 'text', text: formatError(error) }],
|
|
19
|
+
isError: true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { fetchApi, formatResult, formatError } from '../fetch-helper.js';
|
|
3
|
+
const VALID_STAGES = [
|
|
4
|
+
'emerging',
|
|
5
|
+
'growth',
|
|
6
|
+
'peak',
|
|
7
|
+
'decline',
|
|
8
|
+
'reigniting',
|
|
9
|
+
];
|
|
10
|
+
export const registerGetThemeRanking = (server) => {
|
|
11
|
+
server.tool('get_theme_ranking', '한국 주식시장 테마 생명주기 랭킹을 조회합니다. 단계별(초기/성장/정점/쇠퇴/재점화) 테마 목록과 점수를 반환합니다.', {
|
|
12
|
+
stage: z
|
|
13
|
+
.enum(VALID_STAGES)
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Filter by lifecycle stage: emerging (초기), growth (성장), peak (정점), decline (쇠퇴), reigniting (재점화)'),
|
|
16
|
+
}, async ({ stage }) => {
|
|
17
|
+
try {
|
|
18
|
+
const data = await fetchApi('/api/tli/scores/ranking');
|
|
19
|
+
if (stage) {
|
|
20
|
+
const stageData = data[stage];
|
|
21
|
+
const summary = data.summary;
|
|
22
|
+
return {
|
|
23
|
+
content: [
|
|
24
|
+
{
|
|
25
|
+
type: 'text',
|
|
26
|
+
text: formatResult({ stage, themes: stageData, summary }),
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: 'text', text: formatResult(data) }],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: 'text', text: formatError(error) }],
|
|
38
|
+
isError: true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { fetchApi, formatResult, formatError } from '../fetch-helper.js';
|
|
3
|
+
export const registerSearchThemes = (server) => {
|
|
4
|
+
server.tool('search_themes', '테마를 검색합니다. 이름(한국어/영문)으로 필터링하여 일치하는 테마의 점수, 단계 정보를 반환합니다.', {
|
|
5
|
+
query: z
|
|
6
|
+
.string()
|
|
7
|
+
.min(1)
|
|
8
|
+
.describe('Search query (theme name or related stock name, e.g. "AI", "반도체", "삼성전자")'),
|
|
9
|
+
}, async ({ query }) => {
|
|
10
|
+
try {
|
|
11
|
+
const data = await fetchApi('/api/tli/themes', { q: query });
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: 'text', text: formatResult(data) }],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: 'text', text: formatError(error) }],
|
|
19
|
+
isError: true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stockmatrix-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "StockMatrix MCP Server - Korean stock market theme lifecycle analysis for AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"stockmatrix-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"start": "node dist/index.js",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"mcp",
|
|
20
|
+
"model-context-protocol",
|
|
21
|
+
"korean-stocks",
|
|
22
|
+
"theme-lifecycle",
|
|
23
|
+
"finance",
|
|
24
|
+
"kospi",
|
|
25
|
+
"kosdaq",
|
|
26
|
+
"ai-agent"
|
|
27
|
+
],
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/MongLong0214/stock-ai-newsletter.git",
|
|
31
|
+
"directory": "mcp"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://stockmatrix.co.kr/developers",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/MongLong0214/stock-ai-newsletter/issues"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"author": "StockMatrix <aistockmatrix@gmail.com>",
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
44
|
+
"zod": "^3.23.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"typescript": "^5.6.0"
|
|
48
|
+
}
|
|
49
|
+
}
|