import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { z } from 'zod'
// Create server instance
const server = new McpServer({
name: 'greeting-mcp-server',
version: '1.0.0',
capabilities: {
tools: {},
resources: {},
prompts: {}
}
})
// Add greeting tool
server.tool('greeting', 'Say hello or goodbye to someone', {
name: z.string().describe('The name of the person to greet'),
type: z.enum(['hello', 'goodbye']).describe('Type of greeting - hello or goodbye'),
language: z.enum(['korean', 'english']).optional().describe('Language for greeting (optional, defaults to korean)')
}, async (args) => {
const { name, type, language = 'korean' } = args
let greeting: string
if (language === 'english') {
greeting = type === 'hello' ? `Hello, ${name}! Nice to meet you!` : `Goodbye, ${name}! See you later!`
} else {
greeting = type === 'hello' ? `안녕하세요, ${name}님! 만나서 반갑습니다!` : `안녕히 가세요, ${name}님! 또 만나요!`
}
return {
content: [{ type: 'text', text: greeting }]
}
})
// Add calculator tool
server.tool('calculator', 'Perform basic mathematical calculations', {
operation: z.enum(['add', 'subtract', 'multiply', 'divide']).describe('The mathematical operation to perform'),
a: z.number().describe('The first number'),
b: z.number().describe('The second number')
}, async (args) => {
const { operation, a, b } = args
let result: number
let operationSymbol: string
switch (operation) {
case 'add':
result = a + b
operationSymbol = '+'
break
case 'subtract':
result = a - b
operationSymbol = '-'
break
case 'multiply':
result = a * b
operationSymbol = '×'
break
case 'divide':
if (b === 0) {
return {
content: [{
type: 'text',
text: '오류: 0으로 나눌 수 없습니다. (Error: Cannot divide by zero)'
}]
}
}
result = a / b
operationSymbol = '÷'
break
default:
return {
content: [{
type: 'text',
text: '오류: 지원되지 않는 연산입니다. (Error: Unsupported operation)'
}]
}
}
const calculation = `${a} ${operationSymbol} ${b} = ${result}`
return {
content: [{ type: 'text', text: calculation }]
}
})
// Add time tool
server.tool('time', 'Get current date and time', {
timezone: z.string().optional().describe('Timezone (optional, defaults to Asia/Seoul)'),
format: z.enum(['full', 'date', 'time', 'iso']).optional().describe('Time format (optional, defaults to full)')
}, async (args) => {
const { timezone = 'Asia/Seoul', format = 'full' } = args
try {
const now = new Date()
let timeString: string
switch (format) {
case 'date':
timeString = now.toLocaleDateString('ko-KR', {
timeZone: timezone,
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
})
break
case 'time':
timeString = now.toLocaleTimeString('ko-KR', {
timeZone: timezone,
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
break
case 'iso':
timeString = now.toISOString()
break
case 'full':
default:
const dateStr = now.toLocaleDateString('ko-KR', {
timeZone: timezone,
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
})
const timeStr = now.toLocaleTimeString('ko-KR', {
timeZone: timezone,
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
timeString = `${dateStr} ${timeStr} (${timezone})`
break
}
return {
content: [{ type: 'text', text: `현재 시간: ${timeString}` }]
}
} catch (error) {
return {
content: [{
type: 'text',
text: `시간 조회 오류: ${error instanceof Error ? error.message : '알 수 없는 오류'}`
}]
}
}
})
// Add code review prompt
server.prompt('code-review', 'Code review prompt template', {
code: z.string().describe('The code to be reviewed')
}, async (args) => {
const { code } = args
// Auto-detect language
let detectedLanguage = '코드'
if (code.includes('function') && code.includes('{')) {
if (code.includes('const') || code.includes('let') || code.includes('=>')) {
detectedLanguage = 'JavaScript/TypeScript'
} else {
detectedLanguage = 'JavaScript'
}
} else if (code.includes('def ') && code.includes(':')) {
detectedLanguage = 'Python'
} else if (code.includes('public class') || code.includes('private ')) {
detectedLanguage = 'Java'
} else if (code.includes('#include') || code.includes('int main')) {
detectedLanguage = 'C/C++'
} else if (code.includes('func ') && code.includes('package ')) {
detectedLanguage = 'Go'
} else if (code.includes('fn ') && code.includes('->')) {
detectedLanguage = 'Rust'
}
const systemPrompt = `당신은 경험이 풍부한 시니어 개발자이자 코드 리뷰어입니다. 다음 코드를 전반적으로 검토해주세요.
## 리뷰 가이드라인
다음 관점에서 코드를 검토해주세요:
### 1. 코드 품질
- 코드 구조와 로직의 명확성
- 변수 및 함수명의 적절성
- 가독성과 유지보수성
### 2. 기능적 측면
- 오류 처리 및 예외 상황 대응
- 성능 최적화 가능성
- 보안 고려사항
### 3. 모범 사례
- 디자인 패턴 및 코딩 컨벤션
- 업계 표준 준수
- 테스트 가능성
### 4. 개선 사항
- 구체적인 문제점과 개선 방안
- 더 나은 구현 방법 제안
- 코드 예시 (필요시)
### 5. 긍정적 요소
- 잘 작성된 부분
- 좋은 접근 방식
### 6. 종합 평가
- 전체적인 코드 품질 점수 (1-10점)
- 우선순위별 개선 권장사항
한국어로 상세하고 건설적인 피드백을 제공해주세요.`
const userMessage = `다음 ${detectedLanguage} 코드를 리뷰해주세요:
\`\`\`
${code}
\`\`\``
return {
messages: [
{
role: 'user',
content: {
type: 'text',
text: `${systemPrompt}
${userMessage}`
}
}
]
}
})
// Add server info resource
server.resource('server-info', 'server://info', {
name: 'Server Information',
description: 'Server information and status',
mimeType: 'application/json'
}, async () => {
const serverInfo = {
name: 'greeting-mcp-server',
version: '1.0.0',
description: 'TypeScript MCP 서버 - 인사, 계산기, 시간 도구를 제공합니다',
capabilities: {
tools: ['greeting', 'calculator', 'time'],
resources: ['server://info', 'server://stats'],
prompts: ['code-review']
},
status: 'running',
uptime: process.uptime(),
memory: process.memoryUsage(),
platform: process.platform,
nodeVersion: process.version,
timestamp: new Date().toISOString(),
timezone: 'Asia/Seoul'
}
return {
contents: [{
uri: 'server://info',
text: JSON.stringify(serverInfo, null, 2),
mimeType: 'application/json'
}]
}
})
// Add server stats resource
server.resource('server-stats', 'server://stats', {
name: 'Server Statistics',
description: 'Server runtime statistics',
mimeType: 'application/json'
}, async () => {
const stats = {
uptime: {
seconds: Math.floor(process.uptime()),
formatted: `${Math.floor(process.uptime() / 3600)}시간 ${Math.floor((process.uptime() % 3600) / 60)}분 ${Math.floor(process.uptime() % 60)}초`
},
memory: {
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024 * 100) / 100,
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024 * 100) / 100,
external: Math.round(process.memoryUsage().external / 1024 / 1024 * 100) / 100,
unit: 'MB'
},
system: {
platform: process.platform,
arch: process.arch,
nodeVersion: process.version,
pid: process.pid
},
timestamp: new Date().toISOString()
}
return {
contents: [{
uri: 'server://stats',
text: JSON.stringify(stats, null, 2),
mimeType: 'application/json'
}]
}
})
// Start the server
async function main() {
const transport = new StdioServerTransport()
await server.connect(transport)
}
main().catch((error) => {
console.error('Server error:', error)
process.exit(1)
})