ragalgo-mcp-server 1.0.5 → 1.0.7
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.md +192 -119
- package/dist/check_sdk.d.ts +1 -0
- package/dist/check_sdk.js +11 -0
- package/dist/check_sse.d.ts +1 -0
- package/dist/check_sse.js +10 -0
- package/dist/index.d.ts +0 -7
- package/dist/index.js +490 -208
- package/dist/tools/chart.d.ts +37 -20
- package/dist/tools/chart.js +6 -7
- package/dist/tools/financials.d.ts +16 -5
- package/dist/tools/financials.js +1 -1
- package/dist/tools/news.d.ts +56 -11
- package/dist/tools/news.js +9 -22
- package/dist/tools/research.d.ts +27 -14
- package/dist/tools/research.js +9 -9
- package/dist/tools/rooms.d.ts +33 -0
- package/dist/tools/rooms.js +43 -0
- package/dist/tools/snapshots.d.ts +16 -1
- package/dist/tools/snapshots.js +16 -3
- package/dist/tools/tags.d.ts +56 -16
- package/dist/tools/tags.js +13 -2
- package/dist/tools/trends.d.ts +8 -1
- package/dist/utils/api.js +100 -26
- package/package.json +45 -39
- package/server.json +32 -0
package/dist/tools/trends.d.ts
CHANGED
|
@@ -5,7 +5,13 @@ import { z } from 'zod';
|
|
|
5
5
|
export declare const TrendsParamsSchema: z.ZodObject<{
|
|
6
6
|
tag_code: z.ZodString;
|
|
7
7
|
days: z.ZodDefault<z.ZodNumber>;
|
|
8
|
-
}, z.
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
tag_code: string;
|
|
10
|
+
days: number;
|
|
11
|
+
}, {
|
|
12
|
+
tag_code: string;
|
|
13
|
+
days?: number | undefined;
|
|
14
|
+
}>;
|
|
9
15
|
export type TrendsParams = z.infer<typeof TrendsParamsSchema>;
|
|
10
16
|
export declare function getTrends(params: TrendsParams): Promise<{
|
|
11
17
|
success: boolean;
|
|
@@ -13,6 +19,7 @@ export declare function getTrends(params: TrendsParams): Promise<{
|
|
|
13
19
|
code: string;
|
|
14
20
|
name: string;
|
|
15
21
|
type: string;
|
|
22
|
+
name_en?: string;
|
|
16
23
|
};
|
|
17
24
|
trend: Array<{
|
|
18
25
|
date: string;
|
package/dist/utils/api.js
CHANGED
|
@@ -2,20 +2,80 @@
|
|
|
2
2
|
* RagAlgo API 유틸리티
|
|
3
3
|
* Supabase Edge Functions 호출
|
|
4
4
|
*/
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
const CACHE_TTL_MS = 5 * 60 * 1000; // 5분
|
|
6
|
+
const cache = new Map();
|
|
7
|
+
function getCacheKey(endpoint, params) {
|
|
8
|
+
const sortedParams = params
|
|
9
|
+
? Object.entries(params)
|
|
10
|
+
.filter(([, v]) => v !== undefined)
|
|
11
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
12
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
13
|
+
.join('&')
|
|
14
|
+
: '';
|
|
15
|
+
return `${endpoint}?${sortedParams}`;
|
|
16
|
+
}
|
|
17
|
+
function getFromCache(key) {
|
|
18
|
+
const entry = cache.get(key);
|
|
19
|
+
if (!entry)
|
|
20
|
+
return null;
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
if (now - entry.timestamp > CACHE_TTL_MS) {
|
|
23
|
+
cache.delete(key);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return entry.data;
|
|
27
|
+
}
|
|
28
|
+
function setCache(key, data) {
|
|
29
|
+
// 캐시 크기 제한 (최대 100개)
|
|
30
|
+
if (cache.size > 100) {
|
|
31
|
+
const oldestKey = cache.keys().next().value;
|
|
32
|
+
if (oldestKey)
|
|
33
|
+
cache.delete(oldestKey);
|
|
34
|
+
}
|
|
35
|
+
cache.set(key, {
|
|
36
|
+
data,
|
|
37
|
+
timestamp: Date.now()
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// 캐시 통계 (디버그용)
|
|
41
|
+
let cacheHits = 0;
|
|
42
|
+
let cacheMisses = 0;
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// [CHANGED] Dynamic URL Support
|
|
45
|
+
// If SUPABASE_URL is injected (from Desktop .env), use it. Otherwise fallback to hardcoded (Public default).
|
|
46
|
+
const DEFAULT_URL = 'https://xunrsikkybgxkybjzrgz.supabase.co/functions/v1';
|
|
47
|
+
const SUPABASE_URL = (process.env.SUPABASE_URL ? `${process.env.SUPABASE_URL}/functions/v1` : DEFAULT_URL).replace(/\/+$/, ''); // Remove trailing slash if double
|
|
48
|
+
// [DEBUG] Log active configuration
|
|
49
|
+
console.error(`[API Init] Target URL: ${SUPABASE_URL}`);
|
|
50
|
+
console.error(`[API Init] Env Override: ${!!process.env.SUPABASE_URL}`);
|
|
51
|
+
// [CHANGED] Get Keys from Environment (Injected by mcp_manager.py)
|
|
52
|
+
const getKeys = () => {
|
|
53
|
+
const apiKey = process.env.RAGALGO_API_KEY;
|
|
54
|
+
const anonKey = process.env.SUPABASE_ANON_KEY;
|
|
55
|
+
if (!apiKey) {
|
|
56
|
+
throw new Error('RAGALGO_API_KEY environment variable is missing.');
|
|
57
|
+
}
|
|
58
|
+
if (!anonKey) {
|
|
59
|
+
// Fallback for local testing if not injected, but log warning
|
|
60
|
+
console.error('[API] Warning: SUPABASE_ANON_KEY not found in env. Calls may fail.');
|
|
61
|
+
}
|
|
62
|
+
// [FALLBACK] Hardcoded Anon Key for reliability
|
|
63
|
+
const fallbackAnon = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh1bnJzaWtreWJneGt5Ymp6cmd6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjQ0NTExNTgsImV4cCI6MjA4MDAyNzE1OH0.SsXri828-Rf0gHlu4Bls-pewhfMNNII4mbiuLnc9ACs";
|
|
64
|
+
return { apiKey, anonKey: anonKey || fallbackAnon };
|
|
14
65
|
};
|
|
15
|
-
// API 호출 기본 함수
|
|
66
|
+
// API 호출 기본 함수 (5분 캐시 적용)
|
|
16
67
|
export async function callApi(endpoint, params) {
|
|
17
|
-
|
|
18
|
-
|
|
68
|
+
// [CACHE] 캐시 확인
|
|
69
|
+
const cacheKey = getCacheKey(endpoint, params);
|
|
70
|
+
const cachedData = getFromCache(cacheKey);
|
|
71
|
+
if (cachedData !== null) {
|
|
72
|
+
cacheHits++;
|
|
73
|
+
console.error(`[CACHE HIT] ${endpoint} (hits: ${cacheHits}, misses: ${cacheMisses})`);
|
|
74
|
+
return cachedData;
|
|
75
|
+
}
|
|
76
|
+
cacheMisses++;
|
|
77
|
+
console.error(`[CACHE MISS] ${endpoint} (hits: ${cacheHits}, misses: ${cacheMisses})`);
|
|
78
|
+
const { apiKey, anonKey } = getKeys();
|
|
19
79
|
const url = new URL(`${SUPABASE_URL}/${endpoint}`);
|
|
20
80
|
if (params) {
|
|
21
81
|
Object.entries(params).forEach(([key, value]) => {
|
|
@@ -24,35 +84,49 @@ export async function callApi(endpoint, params) {
|
|
|
24
84
|
}
|
|
25
85
|
});
|
|
26
86
|
}
|
|
87
|
+
const headers = {
|
|
88
|
+
'Authorization': `Bearer ${anonKey.trim()}`,
|
|
89
|
+
'apikey': anonKey.trim(),
|
|
90
|
+
'x-api-key': apiKey.trim(),
|
|
91
|
+
'Content-Type': 'application/json',
|
|
92
|
+
};
|
|
27
93
|
const response = await fetch(url.toString(), {
|
|
28
94
|
method: 'GET',
|
|
29
|
-
headers:
|
|
30
|
-
'Authorization': `Bearer ${SUPABASE_ANON_KEY}`,
|
|
31
|
-
'x-api-key': apiKey,
|
|
32
|
-
'Content-Type': 'application/json',
|
|
33
|
-
},
|
|
95
|
+
headers: headers,
|
|
34
96
|
});
|
|
35
97
|
if (!response.ok) {
|
|
36
98
|
const error = await response.text();
|
|
37
|
-
|
|
99
|
+
const debugInfo = `[DEBUG] keys_present=${!!anonKey}, URL: ${url.toString()}`;
|
|
100
|
+
if (response.status === 429) {
|
|
101
|
+
throw new Error(`[RATE LIMIT EXCEEDED] API 요청 제한에 도달했습니다. 잠시 후 다시 시도하거나 요청량을 줄여주세요. (Plan Quota Exceeded) | ${debugInfo}`);
|
|
102
|
+
}
|
|
103
|
+
throw new Error(`API 호출 실패: ${response.status} - ${error} | ${debugInfo}`);
|
|
38
104
|
}
|
|
39
|
-
|
|
105
|
+
const data = await response.json();
|
|
106
|
+
// [CACHE] 성공 시 캐시에 저장
|
|
107
|
+
setCache(cacheKey, data);
|
|
108
|
+
return data;
|
|
40
109
|
}
|
|
41
|
-
// POST API 호출
|
|
110
|
+
// POST API 호출 (POST는 캐시하지 않음 - 데이터 변경 가능성)
|
|
42
111
|
export async function callApiPost(endpoint, body) {
|
|
43
|
-
const apiKey =
|
|
112
|
+
const { apiKey, anonKey } = getKeys();
|
|
44
113
|
const url = `${SUPABASE_URL}/${endpoint}`;
|
|
114
|
+
const headers = {
|
|
115
|
+
'Authorization': `Bearer ${anonKey.trim()}`,
|
|
116
|
+
'apikey': anonKey.trim(),
|
|
117
|
+
'x-api-key': apiKey.trim(), // [FIX] anonKey → apiKey 수정
|
|
118
|
+
'Content-Type': 'application/json',
|
|
119
|
+
};
|
|
45
120
|
const response = await fetch(url, {
|
|
46
121
|
method: 'POST',
|
|
47
|
-
headers:
|
|
48
|
-
'Authorization': `Bearer ${SUPABASE_ANON_KEY}`,
|
|
49
|
-
'x-api-key': apiKey,
|
|
50
|
-
'Content-Type': 'application/json',
|
|
51
|
-
},
|
|
122
|
+
headers: headers,
|
|
52
123
|
body: JSON.stringify(body),
|
|
53
124
|
});
|
|
54
125
|
if (!response.ok) {
|
|
55
126
|
const error = await response.text();
|
|
127
|
+
if (response.status === 429) {
|
|
128
|
+
throw new Error(`[RATE LIMIT EXCEEDED] API 요청 제한에 도달했습니다. 잠시 후 다시 시도하거나 요청량을 줄여주세요. (Plan Quota Exceeded)`);
|
|
129
|
+
}
|
|
56
130
|
throw new Error(`API 호출 실패: ${response.status} - ${error}`);
|
|
57
131
|
}
|
|
58
132
|
return response.json();
|
package/package.json
CHANGED
|
@@ -1,41 +1,47 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
2
|
+
"name": "ragalgo-mcp-server",
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"mcpName": "io.github.kokogo100/ragalgo",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"README.md",
|
|
8
|
+
"server.json"
|
|
9
|
+
],
|
|
10
|
+
"description": "Dynamic RAG Engine for AI Reliability. We provide mathematically scored context & sanitized data to prevent hallucinations in both static & volatile domains (starting with Korean Finance).",
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"bin": {
|
|
13
|
+
"ragalgo-mcp-server": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "npx tsc",
|
|
18
|
+
"start": "node dist/index.js",
|
|
19
|
+
"dev": "npx tsx src/index.ts"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"mcp",
|
|
23
|
+
"rag",
|
|
24
|
+
"ai-reliability",
|
|
25
|
+
"context-scoring",
|
|
26
|
+
"finance",
|
|
27
|
+
"korea-market"
|
|
28
|
+
],
|
|
29
|
+
"author": "RagAlgo Team",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
33
|
+
"@types/uuid": "^10.0.0",
|
|
34
|
+
"cors": "^2.8.5",
|
|
35
|
+
"express": "^4.21.2",
|
|
36
|
+
"uuid": "^13.0.0",
|
|
37
|
+
"zod": "^3.25.0",
|
|
38
|
+
"zod-to-json-schema": "^3.25.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/cors": "^2.8.19",
|
|
42
|
+
"@types/express": "^5.0.6",
|
|
43
|
+
"@types/node": "^20.19.26",
|
|
44
|
+
"tsx": "^4.21.0",
|
|
45
|
+
"typescript": "^5.9.3"
|
|
46
|
+
}
|
|
41
47
|
}
|
package/server.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.kokogo100/ragalgo",
|
|
4
|
+
"description": "Dynamic RAG Engine preventing AI hallucinations in Korean Finance and Crypto markets.",
|
|
5
|
+
"status": "active",
|
|
6
|
+
"repository": {
|
|
7
|
+
"url": "https://github.com/kokogo100/ragalgo-mcp-server",
|
|
8
|
+
"source": "github"
|
|
9
|
+
},
|
|
10
|
+
"version": "1.0.7",
|
|
11
|
+
"packages": [
|
|
12
|
+
{
|
|
13
|
+
"registryType": "npm",
|
|
14
|
+
"registry_type": "npm",
|
|
15
|
+
"registry_base_url": "https://registry.npmjs.org",
|
|
16
|
+
"identifier": "ragalgo-mcp-server",
|
|
17
|
+
"version": "1.0.7",
|
|
18
|
+
"transport": {
|
|
19
|
+
"type": "stdio"
|
|
20
|
+
},
|
|
21
|
+
"environment_variables": [
|
|
22
|
+
{
|
|
23
|
+
"description": "Your API key for the RagAlgo service",
|
|
24
|
+
"is_required": true,
|
|
25
|
+
"format": "string",
|
|
26
|
+
"is_secret": true,
|
|
27
|
+
"name": "RAGALGO_API_KEY"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|