@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 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) => handleSearchTrend(args), // 검색어 트렌드 분석
11
- datalab_shopping_category: (args) => handleShoppingCategoryTrend(args), // 쇼핑 카테고리별 트렌드
12
- datalab_shopping_by_device: (args) => handleShoppingByDeviceTrend(args), // 쇼핑 기기별 트렌드
13
- datalab_shopping_by_gender: (args) => handleShoppingByGenderTrend(args), // 쇼핑 성별 트렌드
14
- datalab_shopping_by_age: (args) => handleShoppingByAgeTrend(args), // 쇼핑 연령별 트렌드
15
- datalab_shopping_keywords: (args) => handleShoppingKeywordsTrend(args), // 쇼핑 키워드 그룹 트렌드
16
- datalab_shopping_keyword_by_device: (args) => handleShoppingKeywordByDeviceTrend(args), // 쇼핑 키워드 기기별 트렌드
17
- datalab_shopping_keyword_by_gender: (args) => handleShoppingKeywordByGenderTrend(args), // 쇼핑 키워드 성별 트렌드
18
- datalab_shopping_keyword_by_age: (args) => handleShoppingKeywordByAgeTrend(args), // 쇼핑 키워드 연령별 트렌드
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) => handleWebKrSearch(SearchArgsSchema.parse(args)),
7
- search_news: (args) => handleNewsSearch(SearchArgsSchema.parse(args)),
8
- search_blog: (args) => handleBlogSearch(SearchArgsSchema.parse(args)),
9
- search_shop: (args) => handleShopSearch(SearchArgsSchema.parse(args)),
10
- search_image: (args) => handleImageSearch(SearchArgsSchema.parse(args)),
11
- search_kin: (args) => handleKinSearch(SearchArgsSchema.parse(args)),
12
- search_book: (args) => handleBookSearch(SearchArgsSchema.parse(args)),
13
- search_encyc: (args) => handleEncycSearch(SearchArgsSchema.parse(args)),
14
- search_academic: (args) => handleAcademicSearch(SearchArgsSchema.parse(args)),
15
- search_local: (args) => handleLocalSearch(args),
16
- search_cafearticle: (args) => handleCafeArticleSearch(args),
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
- #!/usr/bin/env node
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 { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
3
+ import { z } from "zod";
8
4
  import { NaverSearchClient } from "./clients/naver-search.client.js";
9
- import { unifiedSearchTools } from "./tools/unified-search.tools.js";
10
- import { unifiedSearchToolHandlers } from "./handlers/unified-search.handlers.js";
11
- dotenv.config();
12
- console.error("[MCP] dotenv.config() 실행됨");
13
- // 환경 변수 유효성 검사
14
- const NAVER_CLIENT_ID = process.env.NAVER_CLIENT_ID;
15
- const NAVER_CLIENT_SECRET = process.env.NAVER_CLIENT_SECRET;
16
- console.error("[MCP] 환경변수 읽음", { NAVER_CLIENT_ID, NAVER_CLIENT_SECRET });
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
- console.error("[MCP] Server 인스턴스 생성 완료");
38
- // 도구 목록을 반환하는 핸들러 등록
39
- server.setRequestHandler(ListToolsRequestSchema, async () => {
40
- console.error("[MCP] ListToolsRequestSchema 핸들러 호출됨");
41
- return {
42
- tools: [
43
- //...searchTools,
44
- // // ...datalabTools,
45
- ...unifiedSearchTools
46
- ],
47
- };
48
- });
49
- const toolHandlers = {
50
- // ...searchToolHandlers,
51
- // ...datalabToolHandlers,
52
- ...unifiedSearchToolHandlers,
53
- };
54
- // 에러 응답 헬퍼 함수
55
- function createErrorResponse(error) {
56
- const errorMessage = error instanceof Error ? error.message : String(error);
57
- console.error("[MCP] API Error:", errorMessage);
58
- return {
59
- content: [{ type: "text", text: `Error: ${errorMessage}` }],
60
- isError: true,
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
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
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
- const { name, arguments: args } = request.params;
67
- console.error(`[MCP] Executing tool: ${name} with args:`, args);
68
- if (!args) {
69
- throw new Error("Arguments are required");
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 handler = toolHandlers[name];
72
- if (!handler)
73
- throw new Error(`Unknown tool: ${name}`);
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
- catch (error) {
81
- return createErrorResponse(error);
82
- }
83
- });
84
- // 서버 시작 함수
85
- async function runServer() {
86
- try {
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
- process.on("uncaughtException", (error) => {
91
- console.error("[MCP] Uncaught Exception:", error);
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("[MCP] Fatal error running server:", error);
101
- process.exit(1);
226
+ console.error("Error in main function:", error);
227
+ throw error;
102
228
  }
103
229
  }
104
- // 서버 시작
105
- console.error("[MCP] runServer 호출 직전");
106
- runServer().catch((error) => {
107
- console.error("[MCP] Fatal error running server (catch):", error);
108
- process.exit(1);
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
- import { zodToJsonSchema } from "zod-to-json-schema";
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: zodToJsonSchema(DatalabSearchSchema),
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: zodToJsonSchema(DatalabShoppingSchema),
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: zodToJsonSchema(DatalabShoppingDeviceSchema.pick({
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: zodToJsonSchema(DatalabShoppingGenderSchema.pick({
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: zodToJsonSchema(DatalabShoppingAgeSchema.pick({
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: zodToJsonSchema(DatalabShoppingKeywordsSchema),
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: zodToJsonSchema(DatalabShoppingKeywordDeviceSchema),
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: zodToJsonSchema(DatalabShoppingKeywordGenderSchema),
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: zodToJsonSchema(DatalabShoppingKeywordAgeSchema),
68
+ inputSchema: DatalabShoppingKeywordAgeSchema.shape,
69
69
  },
70
70
  ];