find_competitors
Identify nearby competitors and analyze market conditions, including franchise density and entry opportunities for specific business types and locations.
Instructions
주변 경쟁업체를 검색하고 분석합니다. 프랜차이즈 비율, 시장 진입 여지 등을 분석합니다.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| location | Yes | 검색할 위치 (예: 강남역, 홍대입구) | |
| business_type | Yes | 검색할 업종 (예: 카페, 음식점) | |
| radius | No | 검색 반경 (m), 기본값: 300 | |
| limit | No | 결과 개수, 기본값: 10 |
Implementation Reference
- src/tools/competitors.ts:53-107 (handler)Main handler function implementing the core logic for the 'find_competitors' tool: fetches competitors via Kakao API, computes franchise ratio, performs market gap analysis, and formats the response.export async function findCompetitors( location: string, businessType: string, radius: number = 300, limit: number = 10 ): Promise<ApiResult<CompetitorAnalysis>> { try { // 경쟁업체 검색 const competitors = await kakaoApi.findCompetitors( businessType, location, radius, limit ); // 프랜차이즈 비율 계산 const franchiseCount = competitors.filter((c) => isFranchise(c.name)).length; const franchiseRatio = competitors.length > 0 ? Math.round((franchiseCount / competitors.length) * 100) / 100 : 0; // 시장 갭 분석 const marketGap = analyzeMarketGap(competitors, franchiseRatio, competitors.length); return { success: true, data: { query: businessType, location, radius, competitors, analysis: { totalCount: competitors.length, franchiseRatio, marketGap, }, }, meta: { source: DATA_SOURCES.kakaoLocal, timestamp: new Date().toISOString(), }, }; } catch (error) { console.error("경쟁업체 검색 실패:", error); return { success: false, error: { code: "COMPETITOR_SEARCH_FAILED", message: `경쟁업체 검색 중 오류가 발생했습니다: ${error instanceof Error ? error.message : "Unknown error"}`, suggestion: "위치명을 다시 확인하거나 잠시 후 시도해주세요.", }, }; } }
- src/index.ts:42-58 (registration)MCP server registration of the 'find_competitors' tool, defining name, description, input schema, and thin wrapper handler that calls the main findCompetitors function.server.tool( "find_competitors", "주변 경쟁업체를 검색하고 분석합니다. 프랜차이즈 비율, 시장 진입 여지 등을 분석합니다.", { location: z.string().describe("검색할 위치 (예: 강남역, 홍대입구)"), business_type: z.string().describe("검색할 업종 (예: 카페, 음식점)"), radius: z.number().optional().default(300).describe("검색 반경 (m), 기본값: 300"), limit: z.number().optional().default(10).describe("결과 개수, 기본값: 10"), }, async ({ location, business_type, radius, limit }) => { const result = await findCompetitors(location, business_type, radius, limit); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], isError: !result.success, }; } );
- src/index.ts:45-50 (schema)Zod schema defining input parameters for the 'find_competitors' tool: location, business_type, radius, limit.{ location: z.string().describe("검색할 위치 (예: 강남역, 홍대입구)"), business_type: z.string().describe("검색할 업종 (예: 카페, 음식점)"), radius: z.number().optional().default(300).describe("검색 반경 (m), 기본값: 300"), limit: z.number().optional().default(10).describe("결과 개수, 기본값: 10"), },
- src/api/kakao-api.ts:162-192 (helper)Kakao API client method that resolves location coordinates and searches for competitor places by keyword, transforming results into Competitor format.async findCompetitors( businessType: string, location: string, radius: number = 300, limit: number = 15 ): Promise<Competitor[]> { // 먼저 위치 좌표 얻기 const coords = await this.getCoordinates(location); if (!coords) { throw new Error(`위치를 찾을 수 없습니다: ${location}`); } // 업종으로 검색 const places = await this.searchByKeyword(`${location} ${businessType}`, { x: String(coords.lng), y: String(coords.lat), radius, size: limit, sort: "distance", }); return places.map((place) => ({ id: place.id, name: place.place_name, category: place.category_name, address: place.road_address_name || place.address_name, distance: place.distance ? parseInt(place.distance, 10) : 0, phone: place.phone || undefined, placeUrl: place.place_url, })); }
- src/tools/competitors.ts:25-51 (helper)Helper function that analyzes market gap based on competitor count and franchise ratio, providing strategic insights.function analyzeMarketGap( competitors: Competitor[], franchiseRatio: number, totalCount: number ): string { if (totalCount === 0) { return "해당 업종의 경쟁업체가 없습니다. 선점 기회가 있습니다."; } if (totalCount <= 3) { return "경쟁업체가 적어 진입하기 좋은 환경입니다."; } if (franchiseRatio >= 0.7) { return "프랜차이즈 비중이 높습니다. 개성있는 개인 매장으로 차별화 가능합니다."; } if (franchiseRatio <= 0.3) { return "개인 매장 비중이 높습니다. 브랜드 파워로 경쟁력 확보 가능합니다."; } if (totalCount >= 10) { return "경쟁이 치열합니다. 명확한 차별화 전략이 필요합니다."; } return "적절한 경쟁 환경입니다. 품질과 서비스로 승부하세요."; }