Skip to main content
Glama
index.js7.98 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import * as fs from "fs"; import * as path from "path"; import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // MCP 서버 생성 const server = new Server( { name: "guide-mcp-server", version: "1.0.0", }, { capabilities: { tools: {}, resources: {}, }, } ); // 가이드 디렉토리 경로 설정 // npm 패키지로 설치된 환경에서 guides 디렉토리 경로 const guideDir = path.resolve(__dirname, "../guides"); // 가이드 파일 목록 가져오기 function getGuideFiles() { if (!fs.existsSync(guideDir)) { fs.mkdirSync(guideDir, { recursive: true }); return []; } return fs .readdirSync(guideDir) .filter((file) => file.endsWith(".md") || file.endsWith(".txt")); } // 리소스 목록 제공 server.setRequestHandler(ListResourcesRequestSchema, async () => { const guides = getGuideFiles(); return { resources: guides.map((file) => ({ uri: `guide://${file}`, name: path.basename(file, path.extname(file)), description: `가이드 문서: ${file}`, mimeType: "text/markdown", })), }; }); // 리소스 읽기 server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const fileName = request.params.uri.replace("guide://", ""); const filePath = path.join(guideDir, fileName); if (!fs.existsSync(filePath)) { throw new Error(`가이드 파일을 찾을 수 없습니다: ${fileName}`); } const content = fs.readFileSync(filePath, "utf-8"); return { contents: [ { uri: request.params.uri, mimeType: "text/markdown", text: content, }, ], }; }); // 도구 목록 제공 server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "get_guide", description: "가이드 문서의 내용을 읽어서 반환합니다.", inputSchema: { type: "object", properties: { fileName: { type: "string", description: "읽을 가이드 파일명 (예: clean-code-guide.md)", }, }, required: ["fileName"], }, }, { name: "read_file", description: "외부 프로젝트의 파일을 읽어서 반환합니다. 절대 경로 또는 현재 작업 디렉토리 기준 상대 경로를 사용할 수 있습니다.", inputSchema: { type: "object", properties: { filePath: { type: "string", description: "읽을 파일 경로 (예: ./src/utils.js 또는 C:/project/src/utils.js)", }, }, required: ["filePath"], }, }, { name: "check_clean_code", description: "클린 코드 가이드를 기반으로 파일을 검사합니다. 가이드 문서를 참조하여 코드 품질을 분석합니다.", inputSchema: { type: "object", properties: { filePath: { type: "string", description: "검사할 파일 경로 (예: ./src/utils.js)", }, guideName: { type: "string", description: "사용할 가이드 파일명 (기본값: clean-code-guide.md)", default: "clean-code-guide.md", }, }, required: ["filePath"], }, }, ], }; }); // 도구 실행 server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (name === "get_guide") { const filePath = path.join(guideDir, args.fileName); if (!fs.existsSync(filePath)) { return { content: [ { type: "text", text: `가이드 파일을 찾을 수 없습니다: ${args.fileName}\n\n사용 가능한 파일: ${getGuideFiles().join(", ")}`, }, ], isError: true, }; } const content = fs.readFileSync(filePath, "utf-8"); return { content: [ { type: "text", text: `# ${args.fileName}\n\n${content}`, }, ], }; } if (name === "read_file") { try { // 절대 경로인지 확인 const filePath = path.isAbsolute(args.filePath) ? args.filePath : path.resolve(process.cwd(), args.filePath); if (!fs.existsSync(filePath)) { return { content: [ { type: "text", text: `파일을 찾을 수 없습니다: ${args.filePath}\n\n절대 경로: ${filePath}`, }, ], isError: true, }; } const stats = fs.statSync(filePath); if (!stats.isFile()) { return { content: [ { type: "text", text: `경로가 파일이 아닙니다: ${args.filePath}`, }, ], isError: true, }; } const content = fs.readFileSync(filePath, "utf-8"); return { content: [ { type: "text", text: `# 파일: ${args.filePath}\n\n\`\`\`\n${content}\n\`\`\``, }, ], }; } catch (error) { return { content: [ { type: "text", text: `파일 읽기 오류: ${error.message}`, }, ], isError: true, }; } } if (name === "check_clean_code") { try { // 1. 가이드 문서 읽기 const guideName = args.guideName || "clean-code-guide.md"; const guidePath = path.join(guideDir, guideName); if (!fs.existsSync(guidePath)) { return { content: [ { type: "text", text: `가이드 파일을 찾을 수 없습니다: ${guideName}\n\n사용 가능한 파일: ${getGuideFiles().join(", ")}`, }, ], isError: true, }; } const guideContent = fs.readFileSync(guidePath, "utf-8"); // 2. 검사할 파일 읽기 const filePath = path.isAbsolute(args.filePath) ? args.filePath : path.resolve(process.cwd(), args.filePath); if (!fs.existsSync(filePath)) { return { content: [ { type: "text", text: `검사할 파일을 찾을 수 없습니다: ${args.filePath}`, }, ], isError: true, }; } const fileContent = fs.readFileSync(filePath, "utf-8"); // 3. 가이드와 파일 내용을 함께 반환 (AI가 분석하도록) return { content: [ { type: "text", text: `# 클린 코드 검사 결과\n\n## 검사 대상 파일\n\`\`\`\n${fileContent}\n\`\`\`\n\n## 클린 코드 가이드\n\n${guideContent}\n\n---\n\n위 가이드를 참조하여 코드를 분석하고 개선 사항을 제안해주세요.`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `클린 코드 검사 오류: ${error.message}`, }, ], isError: true, }; } } return { content: [ { type: "text", text: `알 수 없는 도구: ${name}`, }, ], isError: true, }; }); // 서버 시작 async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("MCP 가이드 서버가 시작되었습니다."); } main().catch(console.error);

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/geunu97/-teams-guide-mcp'

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