Skip to main content
Glama
document-search.tools.ts8.62 kB
import {CallToolResult} from "@modelcontextprotocol/sdk/types.js"; import {BaaSDocsRepository} from "../repository/baas-docs.repository.js"; import {SearchMode} from "../constants/search-mode.js"; import {GetDocumentByIdParams, SearchDocumentsParams} from "../schema/tool-schemas.js"; export function createSearchDocumentsTool(repository: BaaSDocsRepository, projectId?: string | null) { return { handler: async (params: SearchDocumentsParams): Promise<CallToolResult> => { try { const { keywords, query, searchMode = SearchMode.BALANCED, limit = 5 } = params; let finalSearchQuery = ''; let finalKeywords: string[] = []; // keywords 배열이 있으면 우선 사용 if (keywords && keywords.length > 0) { finalKeywords = keywords.filter(k => k.trim().length > 0); finalSearchQuery = finalKeywords.join(' '); } // 폴백: query 문자열 사용 else if (query && query.trim().length > 0) { finalSearchQuery = query.trim(); // query를 간단히 키워드로 분할 finalKeywords = query.toLowerCase() .replace(/[^\w\s가-힣]/g, ' ') .split(/\s+/) .filter(term => term.length > 1); } // 둘 다 없으면 에러 else { return { content: [ { type: "text", text: `검색 키워드가 필요합니다. 다음과 같이 사용해주세요:\n\n키워드 배열 사용 (권장):\n- keywords: ['로그인', 'React']\n- keywords: ['JWT', '토큰']\n- keywords: ['쿠키', '설정']\n\n문장 사용 (폴백):\n- query: "React 로그인 컴포넌트"\n- query: "JWT 토큰 설정"\n\n사용 가능한 검색 키워드:\n- API 관련: login, signup, authentication, jwt, token\n- 프레임워크: react, nextjs, javascript\n- 보안: security, cors, cookie, validation\n- 에러: error, troubleshooting, debugging` } ] }; } // 새로운 고급 검색 기능을 기본으로 사용 const results = repository.searchDocumentsAdvanced({ query: finalSearchQuery, limit: Math.min(limit, 10), searchMode: searchMode, useWeights: true, useSynonyms: true, // minScore 제거: BM25Calculator의 상대적 필터링만 사용 }); if (results.length === 0) { const searchTerm = finalKeywords.length > 0 ? finalKeywords.join(', ') : finalSearchQuery; return { content: [ { type: "text", text: `검색어 "${searchTerm}"에 대한 관련 문서를 찾을 수 없습니다.\n\n**AIApp BaaS 인증 시스템 문서는 다음 주제로 제한됩니다:**\n\n📚 **사용 가능한 문서 주제:**\n• **로그인 구현**: React/JavaScript 완전 구현 가이드\n• **회원가입 구현**: React/JavaScript 완전 구현 가이드\n• **로그아웃 구현**: React/JavaScript 완전 구현 가이드\n• **사용자 정보**: React/JavaScript 완전 구현 가이드\n• **에러 처리**: 모든 ServiceException과 클라이언트 처리 패턴\n• **보안**: 쿠키, CORS, XSS 방지 설정\n• **통합 가이드**: 빠른 시작 및 인증 플로우\n\n🔍 **권장 검색 키워드:**\n• 로그인: ['로그인', 'React'], ['login', 'javascript']\n• 회원가입: ['회원가입', 'signup'], ['validation', 'form']\n• JWT 토큰: ['JWT', '토큰'], ['authentication', 'token']\n• 에러 처리: ['에러', 'error'], ['ServiceException', 'validation']\n• 보안 설정: ['쿠키', '보안'], ['cors', 'security']\n\n💡 **Tip**: 구체적인 기능과 구현 방식을 함께 검색하면 더 정확한 결과를 얻을 수 있습니다.` } ] }; } const searchTerm = finalKeywords.length > 0 ? finalKeywords.join(', ') : finalSearchQuery; let responseText = `"${searchTerm}" 검색 결과 (${results.length}개 문서):\n\n`; results.forEach((result, index) => { const doc = result.document; responseText += `## ${index + 1}. ${doc.getTitle()}\n`; responseText += `**문서 ID**: ${doc.getId()}\n`; responseText += `**URL**: ${doc.getUrl()}\n`; responseText += `**설명**: ${doc.getDescription()}\n`; responseText += `**관련도 점수**: ${result.score.toFixed(2)}\n\n`; if (result.relevantChunks.length > 0) { responseText += `**관련 내용**:\n`; result.relevantChunks.forEach((chunk, chunkIndex) => { responseText += `${chunkIndex + 1}. ${chunk.substring(0, 200)}${chunk.length > 200 ? '...' : ''}\n\n`; }); } responseText += `---\n\n`; }); responseText += `💡 **Tip**: 더 자세한 내용은 \`get-document-by-id\` 도구에 위에 표시된 **문서 ID**를 사용하여 전체 문서를 조회하세요.\n예: get-document-by-id를 사용할 때 id 파라미터에 위 검색 결과의 문서 ID 값을 입력하세요.`; return { content: [ { type: "text", text: responseText } ] }; } catch (error) { return { content: [ { type: "text", text: `문서 검색 중 오류가 발생했습니다: ${error instanceof Error ? error.message : String(error)}` } ], isError: true }; } } }; } export function createGetDocumentByIdTool(repository: BaaSDocsRepository, projectId?: string | null) { return { handler: async (params: GetDocumentByIdParams): Promise<CallToolResult> => { try { const { id, includeMetadata = false } = params; const document = repository.getDocumentById(id); if (!document) { return { content: [ { type: "text", text: `ID ${id}에 해당하는 문서를 찾을 수 없습니다. search-documents를 사용하여 먼저 문서를 검색해보세요.` } ] }; } let responseText = `# ${document.getTitle()}\n\n`; if (includeMetadata) { responseText += `**문서 정보**:\n`; responseText += `- ID: ${document.getId()}\n`; responseText += `- URL: ${document.getUrl()}\n`; responseText += `- 설명: ${document.getDescription()}\n`; responseText += `- 키워드: ${Array.from(document.getKeywords()).slice(0, 10).join(', ')}\n\n`; responseText += `---\n\n`; } let contentText = document.getContent(); // Project ID 플레이스홀더 교체 if (projectId) { // [PROJECT_ID] 플레이스홀더를 실제 값으로 교체 contentText = contentText.replace(/\[PROJECT_ID\]/g, projectId); // 문서 상단에 설정 정보 추가 responseText += `> 📌 **현재 Project ID**: \`${projectId}\`\n> 아래 코드에서 [PROJECT_ID]가 자동으로 교체되었습니다.\n\n`; } else { // Project ID가 설정되지 않은 경우 안내 responseText += `> ⚠️ **Project ID 미설정**: Claude Desktop 설정에서 --project-id를 추가하세요.\n> 아래 코드의 [PROJECT_ID]를 실제 값으로 교체해야 합니다.\n\n`; } responseText += contentText; // Suggest similar documents const similarDocs = repository.getSimilarDocuments(document, 3); if (similarDocs.length > 0) { responseText += `\n\n## 관련 문서\n\n`; similarDocs.forEach((similarDoc, index) => { responseText += `${index + 1}. **${similarDoc.getTitle()}** (ID: ${similarDoc.getId()})\n`; responseText += ` - ${similarDoc.getDescription()}\n`; responseText += ` - ${similarDoc.getUrl()}\n\n`; }); } return { content: [ { type: "text", text: responseText } ] }; } catch (error) { return { content: [ { type: "text", text: `문서 조회 중 오류가 발생했습니다: ${error instanceof Error ? error.message : String(error)}` } ], isError: true }; } } }; }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mbaas-inc/BaaS-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server