@isnow890/naver-search-mcp 1.0.19 → 1.0.30
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 +45 -0
- package/dist/src/handlers/datalab.handlers.js +36 -9
- package/dist/src/handlers/search.handlers.js +44 -11
- package/dist/src/index.js +237 -97
- package/dist/src/tools/datalab.tools.js +13 -13
- package/dist/src/tools/search.tools.js +11 -12
- package/package.json +8 -11
- package/dist/package.json +0 -43
- package/dist/src/handlers/unified-search.handlers.js +0 -144
- package/dist/src/schemas/unified-search.schemas.js +0 -70
- package/dist/src/tools/unified-search.tools.js +0 -14
- package/dist/tests/unified-search.handlers.test.js +0 -194
- package/dist/tests/unified-search.schemas.test.js +0 -187
- package/dist/tests/unified-search.tools.test.js +0 -38
package/README.md
CHANGED
|
@@ -8,6 +8,12 @@ MCP server for Naver Search API and DataLab API integration, enabling comprehens
|
|
|
8
8
|
|
|
9
9
|
#### Version History
|
|
10
10
|
|
|
11
|
+
###### 1.0.30 (2025-08-04)
|
|
12
|
+
|
|
13
|
+
- MCP SDK upgraded to 1.17.1
|
|
14
|
+
- Fixed compatibility issues with Smithery specification changes
|
|
15
|
+
- Added comprehensive DataLab shopping category code documentation
|
|
16
|
+
|
|
11
17
|
###### 1.0.2 (2025-04-26)
|
|
12
18
|
|
|
13
19
|
- README updated: cafe article search tool and version history section improved
|
|
@@ -47,6 +53,7 @@ MCP server for Naver Search API and DataLab API integration, enabling comprehens
|
|
|
47
53
|
|
|
48
54
|
### Available tools:
|
|
49
55
|
|
|
56
|
+
#### Search Tools
|
|
50
57
|
- **search_webkr**: Search Naver web documents
|
|
51
58
|
- **search_news**: Search Naver news
|
|
52
59
|
- **search_blog**: Search Naver blogs
|
|
@@ -58,6 +65,8 @@ MCP server for Naver Search API and DataLab API integration, enabling comprehens
|
|
|
58
65
|
- **search_encyc**: Search Naver encyclopedia
|
|
59
66
|
- **search_academic**: Search Naver academic papers
|
|
60
67
|
- **search_local**: Search Naver local places
|
|
68
|
+
|
|
69
|
+
#### DataLab Tools
|
|
61
70
|
- **datalab_search**: Analyze search term trends
|
|
62
71
|
- **datalab_shopping_category**: Analyze shopping category trends
|
|
63
72
|
- **datalab_shopping_by_device**: Analyze shopping trends by device
|
|
@@ -68,6 +77,42 @@ MCP server for Naver Search API and DataLab API integration, enabling comprehens
|
|
|
68
77
|
- **datalab_shopping_keyword_by_gender**: Analyze shopping keyword trends by gender
|
|
69
78
|
- **datalab_shopping_keyword_by_age**: Analyze shopping keyword trends by age group
|
|
70
79
|
|
|
80
|
+
### DataLab Shopping Category Codes
|
|
81
|
+
|
|
82
|
+
For DataLab shopping analysis tools, you need to use specific **8-digit category codes**. Here are some common examples:
|
|
83
|
+
|
|
84
|
+
#### Popular Category Codes:
|
|
85
|
+
- **50000000**: Fashion/Clothing (패션의류)
|
|
86
|
+
- **50000002**: Cosmetics/Beauty (화장품/미용)
|
|
87
|
+
- **50000003**: Digital/Home Appliances (디지털/가전)
|
|
88
|
+
- **50000004**: Sports/Leisure (스포츠/레저)
|
|
89
|
+
- **50000005**: Automotive/Tools (자동차/공구)
|
|
90
|
+
- **50000006**: Books/Music/DVDs (도서/음반/DVD)
|
|
91
|
+
- **50000007**: Toys/Hobbies (완구/취미)
|
|
92
|
+
- **50000008**: Food/Beverages (식품/음료)
|
|
93
|
+
- **50000009**: Health/Medical (건강/의료용품)
|
|
94
|
+
- **50000010**: Household/Living (생활/주방용품)
|
|
95
|
+
|
|
96
|
+
#### How to Find Category Codes:
|
|
97
|
+
1. Visit [Naver Shopping](https://shopping.naver.com)
|
|
98
|
+
2. Navigate to desired category
|
|
99
|
+
3. Check the `cat_id` parameter in the URL
|
|
100
|
+
4. Use the 8-digit code (e.g., `cat_id=50000000` → use `"50000000"`)
|
|
101
|
+
|
|
102
|
+
#### Usage Example:
|
|
103
|
+
When using shopping category tools, specify category like:
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"category": "50000000",
|
|
107
|
+
"startDate": "2024-01-01",
|
|
108
|
+
"endDate": "2024-01-31",
|
|
109
|
+
"timeUnit": "month"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### Complete Category List:
|
|
114
|
+
For a complete list of category codes, you can download from Naver Shopping Partner Center or extract them by browsing Naver Shopping categories.
|
|
115
|
+
|
|
71
116
|
## Installation
|
|
72
117
|
|
|
73
118
|
### Option 1: Quick Install via Smithery (Recommended)
|
|
@@ -7,15 +7,42 @@ const client = NaverSearchClient.getInstance();
|
|
|
7
7
|
* index.ts에서 도구 실행 분기 없이 바로 사용
|
|
8
8
|
*/
|
|
9
9
|
export const datalabToolHandlers = {
|
|
10
|
-
datalab_search: (args) =>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
datalab_search: (args) => {
|
|
11
|
+
console.error("datalab_search called with args:", JSON.stringify(args, null, 2));
|
|
12
|
+
return handleSearchTrend(args);
|
|
13
|
+
},
|
|
14
|
+
datalab_shopping_category: (args) => {
|
|
15
|
+
console.error("datalab_shopping_category called with args:", JSON.stringify(args, null, 2));
|
|
16
|
+
return handleShoppingCategoryTrend(args);
|
|
17
|
+
},
|
|
18
|
+
datalab_shopping_by_device: (args) => {
|
|
19
|
+
console.error("datalab_shopping_by_device called with args:", JSON.stringify(args, null, 2));
|
|
20
|
+
return handleShoppingByDeviceTrend(args);
|
|
21
|
+
},
|
|
22
|
+
datalab_shopping_by_gender: (args) => {
|
|
23
|
+
console.error("datalab_shopping_by_gender called with args:", JSON.stringify(args, null, 2));
|
|
24
|
+
return handleShoppingByGenderTrend(args);
|
|
25
|
+
},
|
|
26
|
+
datalab_shopping_by_age: (args) => {
|
|
27
|
+
console.error("datalab_shopping_by_age called with args:", JSON.stringify(args, null, 2));
|
|
28
|
+
return handleShoppingByAgeTrend(args);
|
|
29
|
+
},
|
|
30
|
+
datalab_shopping_keywords: (args) => {
|
|
31
|
+
console.error("datalab_shopping_keywords called with args:", JSON.stringify(args, null, 2));
|
|
32
|
+
return handleShoppingKeywordsTrend(args);
|
|
33
|
+
},
|
|
34
|
+
datalab_shopping_keyword_by_device: (args) => {
|
|
35
|
+
console.error("datalab_shopping_keyword_by_device called with args:", JSON.stringify(args, null, 2));
|
|
36
|
+
return handleShoppingKeywordByDeviceTrend(args);
|
|
37
|
+
},
|
|
38
|
+
datalab_shopping_keyword_by_gender: (args) => {
|
|
39
|
+
console.error("datalab_shopping_keyword_by_gender called with args:", JSON.stringify(args, null, 2));
|
|
40
|
+
return handleShoppingKeywordByGenderTrend(args);
|
|
41
|
+
},
|
|
42
|
+
datalab_shopping_keyword_by_age: (args) => {
|
|
43
|
+
console.error("datalab_shopping_keyword_by_age called with args:", JSON.stringify(args, null, 2));
|
|
44
|
+
return handleShoppingKeywordByAgeTrend(args);
|
|
45
|
+
},
|
|
19
46
|
};
|
|
20
47
|
/**
|
|
21
48
|
* 검색어 트렌드 핸들러
|
|
@@ -3,17 +3,50 @@ import { SearchArgsSchema } from "../schemas/search.schemas.js";
|
|
|
3
3
|
// 클라이언트 인스턴스
|
|
4
4
|
const client = NaverSearchClient.getInstance();
|
|
5
5
|
export const searchToolHandlers = {
|
|
6
|
-
search_webkr: (args) =>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
search_webkr: (args) => {
|
|
7
|
+
console.error("search_webkr called with args:", JSON.stringify(args, null, 2));
|
|
8
|
+
return handleWebKrSearch(SearchArgsSchema.parse(args));
|
|
9
|
+
},
|
|
10
|
+
search_news: (args) => {
|
|
11
|
+
console.error("search_news called with args:", JSON.stringify(args, null, 2));
|
|
12
|
+
return handleNewsSearch(SearchArgsSchema.parse(args));
|
|
13
|
+
},
|
|
14
|
+
search_blog: (args) => {
|
|
15
|
+
console.error("search_blog called with args:", JSON.stringify(args, null, 2));
|
|
16
|
+
return handleBlogSearch(SearchArgsSchema.parse(args));
|
|
17
|
+
},
|
|
18
|
+
search_shop: (args) => {
|
|
19
|
+
console.error("search_shop called with args:", JSON.stringify(args, null, 2));
|
|
20
|
+
return handleShopSearch(SearchArgsSchema.parse(args));
|
|
21
|
+
},
|
|
22
|
+
search_image: (args) => {
|
|
23
|
+
console.error("search_image called with args:", JSON.stringify(args, null, 2));
|
|
24
|
+
return handleImageSearch(SearchArgsSchema.parse(args));
|
|
25
|
+
},
|
|
26
|
+
search_kin: (args) => {
|
|
27
|
+
console.error("search_kin called with args:", JSON.stringify(args, null, 2));
|
|
28
|
+
return handleKinSearch(SearchArgsSchema.parse(args));
|
|
29
|
+
},
|
|
30
|
+
search_book: (args) => {
|
|
31
|
+
console.error("search_book called with args:", JSON.stringify(args, null, 2));
|
|
32
|
+
return handleBookSearch(SearchArgsSchema.parse(args));
|
|
33
|
+
},
|
|
34
|
+
search_encyc: (args) => {
|
|
35
|
+
console.error("search_encyc called with args:", JSON.stringify(args, null, 2));
|
|
36
|
+
return handleEncycSearch(SearchArgsSchema.parse(args));
|
|
37
|
+
},
|
|
38
|
+
search_academic: (args) => {
|
|
39
|
+
console.error("search_academic called with args:", JSON.stringify(args, null, 2));
|
|
40
|
+
return handleAcademicSearch(SearchArgsSchema.parse(args));
|
|
41
|
+
},
|
|
42
|
+
search_local: (args) => {
|
|
43
|
+
console.error("search_local called with args:", JSON.stringify(args, null, 2));
|
|
44
|
+
return handleLocalSearch(args);
|
|
45
|
+
},
|
|
46
|
+
search_cafearticle: (args) => {
|
|
47
|
+
console.error("search_cafearticle called with args:", JSON.stringify(args, null, 2));
|
|
48
|
+
return handleCafeArticleSearch(SearchArgsSchema.parse(args));
|
|
49
|
+
},
|
|
17
50
|
};
|
|
18
51
|
/**
|
|
19
52
|
* 전문자료 검색 핸들러
|
package/dist/src/index.js
CHANGED
|
@@ -1,109 +1,249 @@
|
|
|
1
|
-
|
|
2
|
-
import * as dotenv from "dotenv";
|
|
3
|
-
import pkg from "../package.json" with { type: "json" };
|
|
4
|
-
console.error("[MCP] dotenv import 완료");
|
|
5
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
-
import {
|
|
3
|
+
import { z } from "zod";
|
|
8
4
|
import { NaverSearchClient } from "./clients/naver-search.client.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (!NAVER_CLIENT_ID || !NAVER_CLIENT_SECRET) {
|
|
18
|
-
console.error("[MCP] Error: NAVER_CLIENT_ID and NAVER_CLIENT_SECRET environment variables are required");
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
|
-
// 네이버 검색 클라이언트 초기화
|
|
22
|
-
const client = NaverSearchClient.getInstance();
|
|
23
|
-
client.initialize({
|
|
24
|
-
clientId: NAVER_CLIENT_ID,
|
|
25
|
-
clientSecret: NAVER_CLIENT_SECRET,
|
|
26
|
-
});
|
|
27
|
-
console.error("[MCP] NaverSearchClient 초기화 완료");
|
|
28
|
-
// MCP 서버 인스턴스 생성
|
|
29
|
-
const server = new Server({
|
|
30
|
-
name: "naver-search",
|
|
31
|
-
version: pkg.version,
|
|
32
|
-
}, {
|
|
33
|
-
capabilities: {
|
|
34
|
-
tools: {},
|
|
35
|
-
},
|
|
5
|
+
import { searchToolHandlers } from "./handlers/search.handlers.js";
|
|
6
|
+
import { datalabToolHandlers } from "./handlers/datalab.handlers.js";
|
|
7
|
+
import { SearchArgsSchema, NaverLocalSearchParamsSchema } from "./schemas/search.schemas.js";
|
|
8
|
+
import { DatalabSearchSchema, DatalabShoppingSchema, DatalabShoppingDeviceSchema, DatalabShoppingGenderSchema, DatalabShoppingAgeSchema, DatalabShoppingKeywordsSchema, DatalabShoppingKeywordDeviceSchema, DatalabShoppingKeywordGenderSchema, DatalabShoppingKeywordAgeSchema } from "./schemas/datalab.schemas.js";
|
|
9
|
+
// Configuration schema for Smithery
|
|
10
|
+
export const configSchema = z.object({
|
|
11
|
+
NAVER_CLIENT_ID: z.string().describe("Naver API Client ID"),
|
|
12
|
+
NAVER_CLIENT_SECRET: z.string().describe("Naver API Client Secret")
|
|
36
13
|
});
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
server
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
14
|
+
function createNaverSearchServer({ config }) {
|
|
15
|
+
// Create a new MCP server per MCP spec
|
|
16
|
+
const server = new McpServer({
|
|
17
|
+
name: "naver-search",
|
|
18
|
+
version: "1.0.30",
|
|
19
|
+
});
|
|
20
|
+
// Initialize Naver client with config
|
|
21
|
+
const client = NaverSearchClient.getInstance();
|
|
22
|
+
client.initialize({
|
|
23
|
+
clientId: config.NAVER_CLIENT_ID,
|
|
24
|
+
clientSecret: config.NAVER_CLIENT_SECRET,
|
|
25
|
+
});
|
|
26
|
+
// Register search tools using new 1.17.1 API
|
|
27
|
+
server.registerTool("search_webkr", {
|
|
28
|
+
description: "Perform a search on Naver Web Documents. (네이버 웹문서 검색)",
|
|
29
|
+
inputSchema: SearchArgsSchema.shape
|
|
30
|
+
}, async (args) => {
|
|
31
|
+
const result = await searchToolHandlers.search_webkr(args);
|
|
32
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
33
|
+
});
|
|
34
|
+
server.registerTool("search_news", {
|
|
35
|
+
description: "Perform a search on Naver News. (네이버 뉴스 검색)",
|
|
36
|
+
inputSchema: SearchArgsSchema.shape
|
|
37
|
+
}, async (args) => {
|
|
38
|
+
const result = await searchToolHandlers.search_news(args);
|
|
39
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
40
|
+
});
|
|
41
|
+
server.registerTool("search_blog", {
|
|
42
|
+
description: "Perform a search on Naver Blog. (네이버 블로그 검색)",
|
|
43
|
+
inputSchema: SearchArgsSchema.shape
|
|
44
|
+
}, async (args) => {
|
|
45
|
+
const result = await searchToolHandlers.search_blog(args);
|
|
46
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
47
|
+
});
|
|
48
|
+
server.registerTool("search_shop", {
|
|
49
|
+
description: "Perform a search on Naver Shopping. (네이버 쇼핑 검색)",
|
|
50
|
+
inputSchema: SearchArgsSchema.shape
|
|
51
|
+
}, async (args) => {
|
|
52
|
+
const result = await searchToolHandlers.search_shop(args);
|
|
53
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
54
|
+
});
|
|
55
|
+
server.registerTool("search_image", {
|
|
56
|
+
description: "Perform a search on Naver Image. (네이버 이미지 검색)",
|
|
57
|
+
inputSchema: SearchArgsSchema.shape
|
|
58
|
+
}, async (args) => {
|
|
59
|
+
const result = await searchToolHandlers.search_image(args);
|
|
60
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
61
|
+
});
|
|
62
|
+
server.registerTool("search_kin", {
|
|
63
|
+
description: "Perform a search on Naver KnowledgeiN. (네이버 지식iN 검색)",
|
|
64
|
+
inputSchema: SearchArgsSchema.shape
|
|
65
|
+
}, async (args) => {
|
|
66
|
+
const result = await searchToolHandlers.search_kin(args);
|
|
67
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
68
|
+
});
|
|
69
|
+
server.registerTool("search_book", {
|
|
70
|
+
description: "Perform a search on Naver Book. (네이버 책 검색)",
|
|
71
|
+
inputSchema: SearchArgsSchema.shape
|
|
72
|
+
}, async (args) => {
|
|
73
|
+
const result = await searchToolHandlers.search_book(args);
|
|
74
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
75
|
+
});
|
|
76
|
+
server.registerTool("search_encyc", {
|
|
77
|
+
description: "Perform a search on Naver Encyclopedia. (네이버 지식백과 검색)",
|
|
78
|
+
inputSchema: SearchArgsSchema.shape
|
|
79
|
+
}, async (args) => {
|
|
80
|
+
const result = await searchToolHandlers.search_encyc(args);
|
|
81
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
82
|
+
});
|
|
83
|
+
server.registerTool("search_academic", {
|
|
84
|
+
description: "Perform a search on Naver Academic. (네이버 전문자료 검색)",
|
|
85
|
+
inputSchema: SearchArgsSchema.shape
|
|
86
|
+
}, async (args) => {
|
|
87
|
+
const result = await searchToolHandlers.search_academic(args);
|
|
88
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
89
|
+
});
|
|
90
|
+
server.registerTool("search_local", {
|
|
91
|
+
description: "Perform a search on Naver Local. (네이버 지역 검색)",
|
|
92
|
+
inputSchema: NaverLocalSearchParamsSchema.shape
|
|
93
|
+
}, async (args) => {
|
|
94
|
+
const result = await searchToolHandlers.search_local(args);
|
|
95
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
96
|
+
});
|
|
97
|
+
server.registerTool("search_cafearticle", {
|
|
98
|
+
description: "Perform a search on Naver Cafe Articles. (네이버 카페글 검색)",
|
|
99
|
+
inputSchema: SearchArgsSchema.shape
|
|
100
|
+
}, async (args) => {
|
|
101
|
+
const result = await searchToolHandlers.search_cafearticle(args);
|
|
102
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
103
|
+
});
|
|
104
|
+
// Register datalab tools
|
|
105
|
+
server.registerTool("datalab_search", {
|
|
106
|
+
description: "Perform a trend analysis on Naver search keywords. (네이버 검색어 트렌드 분석)",
|
|
107
|
+
inputSchema: DatalabSearchSchema.shape
|
|
108
|
+
}, async (args) => {
|
|
109
|
+
const result = await datalabToolHandlers.datalab_search(args);
|
|
110
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
111
|
+
});
|
|
112
|
+
server.registerTool("datalab_shopping_category", {
|
|
113
|
+
description: "Perform a trend analysis on Naver Shopping category. (네이버 쇼핑 카테고리별 트렌드 분석)",
|
|
114
|
+
inputSchema: DatalabShoppingSchema.shape
|
|
115
|
+
}, async (args) => {
|
|
116
|
+
const result = await datalabToolHandlers.datalab_shopping_category(args);
|
|
117
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
118
|
+
});
|
|
119
|
+
server.registerTool("datalab_shopping_by_device", {
|
|
120
|
+
description: "Perform a trend analysis on Naver Shopping by device. (네이버 쇼핑 기기별 트렌드 분석)",
|
|
121
|
+
inputSchema: DatalabShoppingDeviceSchema.pick({
|
|
122
|
+
startDate: true,
|
|
123
|
+
endDate: true,
|
|
124
|
+
timeUnit: true,
|
|
125
|
+
category: true,
|
|
126
|
+
device: true,
|
|
127
|
+
}).shape
|
|
128
|
+
}, async (args) => {
|
|
129
|
+
const result = await datalabToolHandlers.datalab_shopping_by_device(args);
|
|
130
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
131
|
+
});
|
|
132
|
+
server.registerTool("datalab_shopping_by_gender", {
|
|
133
|
+
description: "Perform a trend analysis on Naver Shopping by gender. (네이버 쇼핑 성별 트렌드 분석)",
|
|
134
|
+
inputSchema: DatalabShoppingGenderSchema.pick({
|
|
135
|
+
startDate: true,
|
|
136
|
+
endDate: true,
|
|
137
|
+
timeUnit: true,
|
|
138
|
+
category: true,
|
|
139
|
+
gender: true,
|
|
140
|
+
}).shape
|
|
141
|
+
}, async (args) => {
|
|
142
|
+
const result = await datalabToolHandlers.datalab_shopping_by_gender(args);
|
|
143
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
144
|
+
});
|
|
145
|
+
server.registerTool("datalab_shopping_by_age", {
|
|
146
|
+
description: "Perform a trend analysis on Naver Shopping by age. (네이버 쇼핑 연령별 트렌드 분석)",
|
|
147
|
+
inputSchema: DatalabShoppingAgeSchema.pick({
|
|
148
|
+
startDate: true,
|
|
149
|
+
endDate: true,
|
|
150
|
+
timeUnit: true,
|
|
151
|
+
category: true,
|
|
152
|
+
ages: true,
|
|
153
|
+
}).shape
|
|
154
|
+
}, async (args) => {
|
|
155
|
+
const result = await datalabToolHandlers.datalab_shopping_by_age(args);
|
|
156
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
157
|
+
});
|
|
158
|
+
server.registerTool("datalab_shopping_keywords", {
|
|
159
|
+
description: "Perform a trend analysis on Naver Shopping keywords. (네이버 쇼핑 키워드별 트렌드 분석)",
|
|
160
|
+
inputSchema: DatalabShoppingKeywordsSchema.shape
|
|
161
|
+
}, async (args) => {
|
|
162
|
+
const result = await datalabToolHandlers.datalab_shopping_keywords(args);
|
|
163
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
164
|
+
});
|
|
165
|
+
server.registerTool("datalab_shopping_keyword_by_device", {
|
|
166
|
+
description: "Perform a trend analysis on Naver Shopping keywords by device. (네이버 쇼핑 키워드 기기별 트렌드 분석)",
|
|
167
|
+
inputSchema: DatalabShoppingKeywordDeviceSchema.shape
|
|
168
|
+
}, async (args) => {
|
|
169
|
+
const result = await datalabToolHandlers.datalab_shopping_keyword_by_device(args);
|
|
170
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
171
|
+
});
|
|
172
|
+
server.registerTool("datalab_shopping_keyword_by_gender", {
|
|
173
|
+
description: "Perform a trend analysis on Naver Shopping keywords by gender. (네이버 쇼핑 키워드 성별 트렌드 분석)",
|
|
174
|
+
inputSchema: DatalabShoppingKeywordGenderSchema.shape
|
|
175
|
+
}, async (args) => {
|
|
176
|
+
const result = await datalabToolHandlers.datalab_shopping_keyword_by_gender(args);
|
|
177
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
178
|
+
});
|
|
179
|
+
server.registerTool("datalab_shopping_keyword_by_age", {
|
|
180
|
+
description: "Perform a trend analysis on Naver Shopping keywords by age. (네이버 쇼핑 키워드 연령별 트렌드 분석)",
|
|
181
|
+
inputSchema: DatalabShoppingKeywordAgeSchema.shape
|
|
182
|
+
}, async (args) => {
|
|
183
|
+
const result = await datalabToolHandlers.datalab_shopping_keyword_by_age(args);
|
|
184
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
185
|
+
});
|
|
186
|
+
return server.server;
|
|
62
187
|
}
|
|
63
|
-
//
|
|
64
|
-
|
|
188
|
+
// Export default for Smithery compatibility
|
|
189
|
+
export default createNaverSearchServer;
|
|
190
|
+
// Main function to run the server when executed directly
|
|
191
|
+
async function main() {
|
|
65
192
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
193
|
+
console.error("Starting Naver Search MCP Server...");
|
|
194
|
+
// Get config from environment variables - check for empty strings too
|
|
195
|
+
const clientId = process.env.NAVER_CLIENT_ID?.trim();
|
|
196
|
+
const clientSecret = process.env.NAVER_CLIENT_SECRET?.trim();
|
|
197
|
+
console.error("Environment variables:", {
|
|
198
|
+
NAVER_CLIENT_ID: process.env.NAVER_CLIENT_ID ? `[${process.env.NAVER_CLIENT_ID.length} chars]` : 'undefined',
|
|
199
|
+
NAVER_CLIENT_SECRET: process.env.NAVER_CLIENT_SECRET ? `[${process.env.NAVER_CLIENT_SECRET.length} chars]` : 'undefined'
|
|
200
|
+
});
|
|
201
|
+
if (!clientId || !clientSecret) {
|
|
202
|
+
throw new Error(`Missing required environment variables:
|
|
203
|
+
NAVER_CLIENT_ID: ${clientId ? 'provided' : 'missing'}
|
|
204
|
+
NAVER_CLIENT_SECRET: ${clientSecret ? 'provided' : 'missing'}
|
|
205
|
+
|
|
206
|
+
Please set these environment variables before running the server.`);
|
|
70
207
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const result = await handler(args);
|
|
75
|
-
console.error(`[MCP] Tool ${name} executed successfully`);
|
|
76
|
-
return {
|
|
77
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
208
|
+
const config = {
|
|
209
|
+
NAVER_CLIENT_ID: clientId,
|
|
210
|
+
NAVER_CLIENT_SECRET: clientSecret
|
|
78
211
|
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
console.error("[MCP] runServer 진입");
|
|
212
|
+
console.error("Config loaded successfully");
|
|
213
|
+
// Validate config
|
|
214
|
+
const validatedConfig = configSchema.parse(config);
|
|
215
|
+
console.error("Config validated successfully");
|
|
216
|
+
// Create server instance
|
|
217
|
+
const serverFactory = createNaverSearchServer({ config: validatedConfig });
|
|
218
|
+
console.error("Server factory created");
|
|
219
|
+
// Create transport and run server
|
|
88
220
|
const transport = new StdioServerTransport();
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
93
|
-
process.on("unhandledRejection", (reason, promise) => {
|
|
94
|
-
console.error("[MCP] Unhandled Rejection at:", promise, "reason:", reason);
|
|
95
|
-
});
|
|
96
|
-
await server.connect(transport);
|
|
97
|
-
console.error("[MCP] Naver Search MCP Server running on stdio");
|
|
221
|
+
console.error("Transport created, connecting...");
|
|
222
|
+
await serverFactory.connect(transport);
|
|
223
|
+
console.error("Server connected and running");
|
|
98
224
|
}
|
|
99
225
|
catch (error) {
|
|
100
|
-
console.error("
|
|
101
|
-
|
|
226
|
+
console.error("Error in main function:", error);
|
|
227
|
+
throw error;
|
|
102
228
|
}
|
|
103
229
|
}
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
230
|
+
// Run main function if this file is executed directly
|
|
231
|
+
// Note: Always run main in CLI mode since this is an MCP server
|
|
232
|
+
console.error("Starting MCP server initialization...");
|
|
233
|
+
console.error("import.meta.url:", import.meta.url);
|
|
234
|
+
console.error("process.argv:", process.argv);
|
|
235
|
+
// Check if running as main module
|
|
236
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}` ||
|
|
237
|
+
import.meta.url.endsWith(process.argv[1]) ||
|
|
238
|
+
process.argv[1].endsWith("index.js");
|
|
239
|
+
console.error("isMainModule:", isMainModule);
|
|
240
|
+
if (isMainModule) {
|
|
241
|
+
console.error("Running as main module, starting server...");
|
|
242
|
+
main().catch((error) => {
|
|
243
|
+
console.error("Server failed to start:", error);
|
|
244
|
+
process.exit(1);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
console.error("Not running as main module, skipping server start");
|
|
249
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// Remove zodToJsonSchema import - using Zod schemas directly
|
|
2
2
|
import { DatalabSearchSchema, DatalabShoppingSchema, DatalabShoppingDeviceSchema, DatalabShoppingGenderSchema, DatalabShoppingAgeSchema, DatalabShoppingKeywordsSchema, DatalabShoppingKeywordDeviceSchema, DatalabShoppingKeywordGenderSchema, DatalabShoppingKeywordAgeSchema } from "../schemas/datalab.schemas.js";
|
|
3
3
|
/**
|
|
4
4
|
* 데이터랩 관련 도구 정의
|
|
@@ -7,64 +7,64 @@ export const datalabTools = [
|
|
|
7
7
|
{
|
|
8
8
|
name: "datalab_search",
|
|
9
9
|
description: "Perform a trend analysis on Naver search keywords. (네이버 검색어 트렌드 분석)",
|
|
10
|
-
inputSchema:
|
|
10
|
+
inputSchema: DatalabSearchSchema.shape,
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
name: "datalab_shopping_category",
|
|
14
14
|
description: "Perform a trend analysis on Naver Shopping category. (네이버 쇼핑 카테고리별 트렌드 분석)",
|
|
15
|
-
inputSchema:
|
|
15
|
+
inputSchema: DatalabShoppingSchema.shape,
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
name: "datalab_shopping_by_device",
|
|
19
19
|
description: "Perform a trend analysis on Naver Shopping by device. (네이버 쇼핑 기기별 트렌드 분석)",
|
|
20
|
-
inputSchema:
|
|
20
|
+
inputSchema: DatalabShoppingDeviceSchema.pick({
|
|
21
21
|
startDate: true,
|
|
22
22
|
endDate: true,
|
|
23
23
|
timeUnit: true,
|
|
24
24
|
category: true,
|
|
25
25
|
device: true,
|
|
26
|
-
})
|
|
26
|
+
}).shape,
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
name: "datalab_shopping_by_gender",
|
|
30
30
|
description: "Perform a trend analysis on Naver Shopping by gender. (네이버 쇼핑 성별 트렌드 분석)",
|
|
31
|
-
inputSchema:
|
|
31
|
+
inputSchema: DatalabShoppingGenderSchema.pick({
|
|
32
32
|
startDate: true,
|
|
33
33
|
endDate: true,
|
|
34
34
|
timeUnit: true,
|
|
35
35
|
category: true,
|
|
36
36
|
gender: true,
|
|
37
|
-
})
|
|
37
|
+
}).shape,
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
name: "datalab_shopping_by_age",
|
|
41
41
|
description: "Perform a trend analysis on Naver Shopping by age. (네이버 쇼핑 연령별 트렌드 분석)",
|
|
42
|
-
inputSchema:
|
|
42
|
+
inputSchema: DatalabShoppingAgeSchema.pick({
|
|
43
43
|
startDate: true,
|
|
44
44
|
endDate: true,
|
|
45
45
|
timeUnit: true,
|
|
46
46
|
category: true,
|
|
47
47
|
ages: true,
|
|
48
|
-
})
|
|
48
|
+
}).shape,
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
name: "datalab_shopping_keywords",
|
|
52
52
|
description: "Perform a trend analysis on Naver Shopping keywords. (네이버 쇼핑 키워드별 트렌드 분석)",
|
|
53
|
-
inputSchema:
|
|
53
|
+
inputSchema: DatalabShoppingKeywordsSchema.shape,
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
56
|
name: "datalab_shopping_keyword_by_device",
|
|
57
57
|
description: "Perform a trend analysis on Naver Shopping keywords by device. (네이버 쇼핑 키워드 기기별 트렌드 분석)",
|
|
58
|
-
inputSchema:
|
|
58
|
+
inputSchema: DatalabShoppingKeywordDeviceSchema.shape,
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
name: "datalab_shopping_keyword_by_gender",
|
|
62
62
|
description: "Perform a trend analysis on Naver Shopping keywords by gender. (네이버 쇼핑 키워드 성별 트렌드 분석)",
|
|
63
|
-
inputSchema:
|
|
63
|
+
inputSchema: DatalabShoppingKeywordGenderSchema.shape,
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
name: "datalab_shopping_keyword_by_age",
|
|
67
67
|
description: "Perform a trend analysis on Naver Shopping keywords by age. (네이버 쇼핑 키워드 연령별 트렌드 분석)",
|
|
68
|
-
inputSchema:
|
|
68
|
+
inputSchema: DatalabShoppingKeywordAgeSchema.shape,
|
|
69
69
|
},
|
|
70
70
|
];
|