Skip to main content
Glama
Seojiyoung

TypeScript MCP Server Boilerplate

by Seojiyoung
index.ts14.7 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' import { z } from 'zod' import { HfInference } from '@huggingface/inference' import { Buffer } from 'buffer' export const configSchema = z.object({ HF_TOKEN: z.string().describe("Hugging Face API Token for image generation") }) export default function createServer({ config }: { config: z.infer<typeof configSchema> }) { // 언어별 인사말 매핑 const greetings: Record<string, string> = { korean: '안녕하세요', english: 'Hello', spanish: 'Hola', french: 'Bonjour', japanese: 'こんにちは', chinese: '你好', german: 'Guten Tag', italian: 'Ciao', russian: 'Привет', portuguese: 'Olá', } // Create server instance const server = new McpServer({ name: 'greeting-server', version: '1.0.0', capabilities: { tools: {}, resources: {}, prompts: {} } }) // Greeting 도구 추가 server.tool( 'greeting', '사용자의 이름과 원하는 언어를 받아서 해당 언어로 인사합니다', { name: z.string().describe('인사할 사용자의 이름'), language: z.enum([ 'korean', 'english', 'spanish', 'french', 'japanese', 'chinese', 'german', 'italian', 'russian', 'portuguese' ]).describe('인사할 언어 (korean, english, spanish, french, japanese, chinese, german, italian, russian, portuguese 중 선택)'), }, async ({ name, language }: { name: string; language: 'korean' | 'english' | 'spanish' | 'french' | 'japanese' | 'chinese' | 'german' | 'italian' | 'russian' | 'portuguese' }) => { const greeting = greetings[language] const message = `${greeting}, ${name}!` return { content: [ { type: 'text', text: message } ] } } ) // Calculator 도구 추가 server.tool( 'calculator', '두 개의 숫자를 입력받아 사칙연산(+, -, *, /)을 수행합니다', { num1: z.number().describe('첫 번째 숫자'), num2: z.number().describe('두 번째 숫자'), operator: z.enum(['+', '-', '*', '/']).describe('연산자 (+, -, *, / 중 선택)'), }, async ({ num1, num2, operator }: { num1: number; num2: number; operator: '+' | '-' | '*' | '/' }) => { let result: number let operationName: string switch (operator) { case '+': result = num1 + num2 operationName = '덧셈' break case '-': result = num1 - num2 operationName = '뺄셈' break case '*': result = num1 * num2 operationName = '곱셈' break case '/': if (num2 === 0) { return { content: [ { type: 'text', text: '오류: 0으로 나눌 수 없습니다!' } ], isError: true } } result = num1 / num2 operationName = '나눗셈' break } const message = `${operationName} 결과: ${num1} ${operator} ${num2} = ${result}` return { content: [ { type: 'text', text: message } ] } } ) // Current Time 도구 추가 server.tool( 'current-time', '지정된 타임존의 현재 시간을 반환합니다. 타임존을 지정하지 않으면 한국 시간을 반환합니다.', { timezone: z.string().optional().describe('IANA 타임존 형식 (예: Asia/Seoul, America/New_York, Europe/London). 지정하지 않으면 Asia/Seoul(한국 시간) 사용'), }, async ({ timezone }: { timezone?: string }) => { const targetTimezone = timezone || 'Asia/Seoul' try { const now = new Date() // 타임존에 맞는 현재 시간 포맷팅 const dateOptions: Intl.DateTimeFormatOptions = { timeZone: targetTimezone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false } const formattedTime = now.toLocaleString('ko-KR', dateOptions) // 타임존 이름 가져오기 const timezoneName = new Intl.DateTimeFormat('ko-KR', { timeZone: targetTimezone, timeZoneName: 'long' }).formatToParts(now).find(part => part.type === 'timeZoneName')?.value || targetTimezone const message = `${timezoneName}의 현재 시간: ${formattedTime}` return { content: [ { type: 'text', text: message } ] } } catch (error) { return { content: [ { type: 'text', text: `오류: 유효하지 않은 타임존입니다. (입력값: ${targetTimezone})\nIANA 타임존 형식을 사용해주세요 (예: Asia/Seoul, America/New_York)` } ], isError: true } } } ) // Image Generation 도구 추가 server.tool( 'generate-image', '텍스트 프롬프트를 입력받아 AI 이미지를 생성합니다', { prompt: z.string().describe('생성할 이미지를 설명하는 텍스트 프롬프트'), }, async ({ prompt }: { prompt: string }) => { try { const client = new HfInference(config.HF_TOKEN) const imageBlob = await client.textToImage({ model: 'black-forest-labs/FLUX.1-schnell', inputs: prompt, }) // Blob을 ArrayBuffer로 변환 const arrayBuffer = await imageBlob.arrayBuffer() // ArrayBuffer를 Buffer로 변환 후 base64 인코딩 const buffer = Buffer.from(arrayBuffer) const base64Data = buffer.toString('base64') return { content: [ { type: 'image', data: base64Data, mimeType: 'image/png' } ], annotations: { audience: ['user'], priority: 0.9 } } } catch (error) { return { content: [ { type: 'text', text: `이미지 생성 오류: ${error instanceof Error ? error.message : '알 수 없는 오류가 발생했습니다.'}\n\nHF_TOKEN 설정이 올바른지 확인해주세요.` } ], isError: true } } } ) // Server Info 리소스 추가 server.resource( 'server-info', 'server://info', { description: '현재 MCP 서버의 상세 정보를 반환합니다', mimeType: 'application/json' }, async () => { const serverInfo = { name: 'greeting-server', version: '1.0.0', description: '다국어 인사, 계산기, 현재 시간, 이미지 생성, 코드 리뷰를 제공하는 MCP 서버', capabilities: { tools: ['greeting', 'calculator', 'current-time', 'generate-image'], resources: ['server-info'], prompts: ['code_review'] }, supportedLanguages: Object.keys(greetings), features: [ { name: 'greeting', description: '10개 언어로 개인화된 인사말 제공', languages: Object.keys(greetings) }, { name: 'calculator', description: '기본 사칙연산 지원 (덧셈, 뺄셈, 곱셈, 나눗셈)', operations: ['+', '-', '*', '/'] }, { name: 'current-time', description: 'IANA 타임존 기반 현재 시간 조회', defaultTimezone: 'Asia/Seoul' }, { name: 'generate-image', description: 'AI 텍스트-이미지 생성 (FLUX.1-schnell 모델 사용)', parameters: ['prompt'] }, { name: 'code_review', description: '상세한 코드 리뷰 프롬프트 생성 (품질, 버그, 성능, 보안, 스타일 등 7가지 항목 분석)', parameters: ['code', 'language (optional)', 'focus (optional)'] } ], author: 'MCP Server', lastUpdated: new Date().toISOString() } return { contents: [ { uri: 'server://info', mimeType: 'application/json', text: JSON.stringify(serverInfo, null, 2) } ] } } ) // Code Review 프롬프트 추가 server.prompt( 'code_review', '사용자의 코드를 입력받아 상세한 코드 리뷰를 수행하는 프롬프트를 생성합니다', { code: z.string().describe('리뷰할 코드'), language: z.string().optional().describe('프로그래밍 언어 (예: TypeScript, Python, Java 등)'), focus: z.string().optional().describe('특정 리뷰 초점 (예: 성능, 보안, 가독성 등)') }, async ({ code, language, focus }: { code: string; language?: string; focus?: string }) => { const languageInfo = language ? `\n**프로그래밍 언어**: ${language}` : '' const focusInfo = focus ? `\n**리뷰 초점**: ${focus}` : '' const prompt = `다음 코드에 대한 상세한 코드 리뷰를 수행해주세요.${languageInfo}${focusInfo} ## 검토할 코드 \`\`\`${language || ''} ${code} \`\`\` ## 코드 리뷰 가이드라인 다음 항목들을 중심으로 상세하게 분석해주세요: ### 1. 코드 품질 분석 - 전체적인 코드 구조와 설계 패턴 평가 - 코드의 명확성과 의도 전달 여부 - 복잡도 분석 (순환 복잡도, 중첩 깊이 등) ### 2. 버그 및 잠재적 문제점 - 명백한 버그나 논리적 오류 발견 - Edge case 처리 누락 - Null/Undefined 체크 누락 - 타입 관련 문제 - 예외 처리 미흡 ### 3. 성능 최적화 - 불필요한 연산이나 반복 - 메모리 누수 가능성 - 비효율적인 알고리즘이나 자료구조 사용 - 캐싱 기회 - 비동기 처리 개선점 ### 4. 보안 취약점 - 입력 검증 부족 - SQL Injection, XSS 등 보안 위협 - 민감한 정보 노출 - 권한 검증 누락 - 안전하지 않은 의존성 사용 ### 5. 코드 스타일 및 가독성 - 네이밍 컨벤션 준수 여부 - 코드 포맷팅 및 일관성 - 주석의 적절성 (과다/부족) - 매직 넘버/스트링 사용 - 함수/클래스 크기의 적절성 ### 6. 모범 사례 준수 - 언어별 관용구(idiom) 활용 - SOLID 원칙 준수 - DRY (Don't Repeat Yourself) 원칙 - 적절한 디자인 패턴 적용 - 테스트 가능성 ### 7. 유지보수성 - 코드의 확장 가능성 - 의존성 관리 - 결합도와 응집도 - 리팩토링 필요성 ## 리뷰 형식 각 항목에 대해: - ✅ **잘된 점**: 긍정적인 부분 강조 - ⚠️ **개선 필요**: 문제점과 이유 설명 - 💡 **제안**: 구체적인 개선 코드 예시 제공 - 🔍 **추가 고려사항**: 장기적 관점의 제안 마지막에 **종합 평가**와 **우선순위별 개선 사항**을 정리해주세요.` return { messages: [ { role: 'user', content: { type: 'text', text: prompt } } ] } } ) // 서버 시작 // async function main() { // const transport = new StdioServerTransport() // await server.connect(transport) // console.error('Greeting MCP Server running on stdio') // } // main().catch((error) => { // console.error('Server error:', error) // process.exit(1) // }) return server.server }

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/Seojiyoung/my-mcp-server-251027'

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