my-mcp-server-20250925

su-myeong/my-mcp-server-20250925

3.2

If you are the rightful owner of my-mcp-server-20250925 and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.

This project is a boilerplate for quickly developing a Model Context Protocol (MCP) server using the TypeScript MCP SDK.

Tools
3
Resources
0
Prompts
0

TypeScript MCP Server λ³΄μΌλŸ¬ν”Œλ ˆμ΄νŠΈ

TypeScript MCP SDKλ₯Ό ν™œμš©ν•˜μ—¬ Model Context Protocol (MCP) μ„œλ²„λ₯Ό λΉ λ₯΄κ²Œ κ°œλ°œν•  수 μžˆλŠ” λ³΄μΌλŸ¬ν”Œλ ˆμ΄νŠΈ ν”„λ‘œμ νŠΈμž…λ‹ˆλ‹€.

πŸ“ ν”„λ‘œμ νŠΈ ꡬ쑰

typescript-mcp-server-boilerplate/
β”œβ”€β”€ src/
β”‚   └── index.ts          # MCP μ„œλ²„ 메인 μ§„μž…μ 
β”œβ”€β”€ build/                # 컴파일된 JavaScript 파일 (λΉŒλ“œ ν›„ 생성)
β”œβ”€β”€ package.json          # ν”„λ‘œμ νŠΈ μ˜μ‘΄μ„± 및 슀크립트
β”œβ”€β”€ tsconfig.json         # TypeScript μ„€μ •
└── README.md            # ν”„λ‘œμ νŠΈ λ¬Έμ„œ

πŸš€ μ‹œμž‘ν•˜κΈ°

1. μ˜μ‘΄μ„± μ„€μΉ˜

npm install

2. μ„œλ²„ 이름 μ„€μ •

src/index.ts νŒŒμΌμ—μ„œ μ„œλ²„ 이름을 μˆ˜μ •ν•˜μ„Έμš”:

const server = new McpServer({
    name: 'typescript-mcp-server', // μ—¬κΈ°λ₯Ό μ›ν•˜λŠ” μ„œλ²„ μ΄λ¦„μœΌλ‘œ λ³€κ²½
    version: '1.0.0',
    // ν™œμ„±ν™” ν•˜κ³ μž ν•˜λŠ” κΈ°λŠ₯ μ„€μ •
    capabilities: {
        tools: {},
        resources: {}
    }
})

πŸ’‘ 팁: ν˜„μž¬ λ³΄μΌλŸ¬ν”Œλ ˆμ΄νŠΈμ—λŠ” 이미 계산기와 인사 도ꡬ, 그리고 μ„œλ²„ 정보 λ¦¬μ†ŒμŠ€κ°€ μ˜ˆμ‹œλ‘œ κ΅¬ν˜„λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

3. λΉŒλ“œ

npm run build

4. μ‹€ν–‰

node build/index.js

λΉŒλ“œκ°€ μ„±κ³΅ν•˜λ©΄ build/ 디렉토리에 컴파일된 JavaScript 파일이 μƒμ„±λ˜κ³ , μ„œλ²„κ°€ MCP ν΄λΌμ΄μ–ΈνŠΈμ˜ 연결을 λŒ€κΈ°ν•©λ‹ˆλ‹€.

πŸ› οΈ 개발 κ°€μ΄λ“œ

MCP 도ꡬ(Tool) μΆ”κ°€ν•˜κΈ°

MCP μ„œλ²„μ— μƒˆλ‘œμš΄ 도ꡬλ₯Ό μΆ”κ°€ν•˜λ €λ©΄ server.tool() λ©”μ„œλ“œμ— Zod μŠ€ν‚€λ§ˆλ₯Ό 직접 μ •μ˜ν•˜μ—¬ λ“±λ‘ν•©λ‹ˆλ‹€:

import { z } from 'zod'

// 계산기 도ꡬ μΆ”κ°€
server.tool(
    'calculator',
    {
        operation: z
            .enum(['add', 'subtract', 'multiply', 'divide'])
            .describe('μˆ˜ν–‰ν•  μ—°μ‚° (add, subtract, multiply, divide)'),
        a: z.number().describe('첫 번째 숫자'),
        b: z.number().describe('두 번째 숫자')
    },
    async ({ operation, a, b }) => {
        // μ—°μ‚° μˆ˜ν–‰
        let result: number
        switch (operation) {
            case 'add':
                result = a + b
                break
            case 'subtract':
                result = a - b
                break
            case 'multiply':
                result = a * b
                break
            case 'divide':
                if (b === 0) throw new Error('0으둜 λ‚˜λˆŒ 수 μ—†μŠ΅λ‹ˆλ‹€')
                result = a / b
                break
            default:
                throw new Error('μ§€μ›ν•˜μ§€ μ•ŠλŠ” μ—°μ‚°μž…λ‹ˆλ‹€')
        }

        const operationSymbols = {
            add: '+',
            subtract: '-',
            multiply: 'Γ—',
            divide: 'Γ·'
        } as const

        const operationSymbol =
            operationSymbols[operation as keyof typeof operationSymbols]

        return {
            content: [
                {
                    type: 'text',
                    text: `${a} ${operationSymbol} ${b} = ${result}`
                }
            ]
        }
    }
)
더 λ³΅μž‘ν•œ 도ꡬ μ˜ˆμ‹œ
// 날씨 정보 쑰회 도ꡬ
server.tool(
    'get_weather',
    {
        city: z.string().describe('날씨λ₯Ό μ‘°νšŒν•  λ„μ‹œλͺ…'),
        unit: z
            .enum(['celsius', 'fahrenheit'])
            .optional()
            .default('celsius')
            .describe('μ˜¨λ„ λ‹¨μœ„ (κΈ°λ³Έκ°’: celsius)')
    },
    async ({ city, unit }) => {
        try {
            // μ‹€μ œ 날씨 API 호좜 둜직 (μ˜ˆμ‹œ)
            const weatherData = await fetchWeatherData(city, unit)

            return {
                content: [
                    {
                        type: 'text',
                        text: `${city}의 ν˜„μž¬ 날씨:
μ˜¨λ„: ${weatherData.temperature}Β°${unit === 'celsius' ? 'C' : 'F'}
날씨: ${weatherData.condition}
μŠ΅λ„: ${weatherData.humidity}%
풍속: ${weatherData.windSpeed}km/h`
                    }
                ]
            }
        } catch (error) {
            throw new Error(
                `날씨 정보λ₯Ό κ°€μ Έμ˜¬ 수 μ—†μŠ΅λ‹ˆλ‹€: ${(error as Error).message}`
            )
        }
    }
)

// λ„μš°λ―Έ ν•¨μˆ˜
async function fetchWeatherData(city: string, unit: string) {
    // μ‹€μ œ 날씨 API 호좜 κ΅¬ν˜„
    // μ—¬κΈ°μ„œλŠ” μ˜ˆμ‹œ 데이터 λ°˜ν™˜
    return {
        temperature: unit === 'celsius' ? 22 : 72,
        condition: 'λ§‘μŒ',
        humidity: 65,
        windSpeed: 12
    }
}

λ¦¬μ†ŒμŠ€ μΆ”κ°€ν•˜κΈ°

MCP μ„œλ²„μ— λ¦¬μ†ŒμŠ€λ₯Ό μΆ”κ°€ν•˜μ—¬ μ™ΈλΆ€ λ°μ΄ν„°λ‚˜ νŒŒμΌμ— λŒ€ν•œ 접근을 μ œκ³΅ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

// λ¦¬μ†ŒμŠ€ 등둝
server.resource(
    'example-file',
    'file://example.txt',
    {
        name: 'μ˜ˆμ‹œ ν…μŠ€νŠΈ 파일',
        description: 'μ˜ˆμ‹œ ν…μŠ€νŠΈ 파일 μ„€λͺ…',
        mimeType: 'text/plain'
    },
    async () => {
        return {
            contents: [
                {
                    uri: 'file://example.txt',
                    mimeType: 'text/plain',
                    text: 'μ˜ˆμ‹œ 파일 λ‚΄μš©μž…λ‹ˆλ‹€.'
                }
            ]
        }
    }
)

// 동적 λ¦¬μ†ŒμŠ€ μ˜ˆμ‹œ
server.resource(
    'app-settings',
    'config://settings',
    {
        name: 'μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„€μ •',
        description: 'μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ ν˜„μž¬ μ„€μ • 정보',
        mimeType: 'application/json'
    },
    async () => {
        const settings = {
            theme: 'dark',
            language: 'ko-KR',
            notifications: true,
            lastUpdated: new Date().toISOString()
        }

        return {
            contents: [
                {
                    uri: 'config://settings',
                    mimeType: 'application/json',
                    text: JSON.stringify(settings, null, 2)
                }
            ]
        }
    }
)

πŸ“¦ μ£Όμš” μ˜μ‘΄μ„±

  • @modelcontextprotocol/sdk: MCP ν”„λ‘œν† μ½œ κ΅¬ν˜„μ„ μœ„ν•œ 곡식 SDK
  • zod: TypeScript μš°μ„  μŠ€ν‚€λ§ˆ 검증 라이브러리
  • typescript: TypeScript 컴파일러

πŸ”§ 슀크립트

  • npm run build: TypeScriptλ₯Ό JavaScript둜 μ»΄νŒŒμΌν•˜κ³  μ‹€ν–‰ κΆŒν•œ μ„€μ •

πŸ“‹ μ‚¬μš© μ˜ˆμ‹œ

μ™„μ „ν•œ μ„œλ²„ μ˜ˆμ‹œ

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { z } from 'zod'

// μ„œλ²„ 생성
const server = new McpServer({
    name: 'my-mcp-server',
    version: '1.0.0',
    capabilities: {
        tools: {},
        resources: {}
    }
})

// κ°„λ‹¨ν•œ 인사 도ꡬ
server.tool(
    'greet',
    {
        name: z.string().describe('인사할 μ‚¬λžŒμ˜ 이름'),
        language: z
            .enum(['ko', 'en'])
            .optional()
            .default('ko')
            .describe('인사 μ–Έμ–΄ (κΈ°λ³Έκ°’: ko)')
    },
    async ({ name, language }) => {
        const greeting =
            language === 'ko' ? `μ•ˆλ…•ν•˜μ„Έμš”, ${name}λ‹˜!` : `Hello, ${name}!`

        return {
            content: [
                {
                    type: 'text',
                    text: greeting
                }
            ]
        }
    }
)

// μ‹œμŠ€ν…œ 정보 λ¦¬μ†ŒμŠ€
server.resource(
    'system-info',
    'system://info',
    {
        name: 'μ‹œμŠ€ν…œ 정보',
        description: 'μ„œλ²„μ˜ ν˜„μž¬ μƒνƒœ 및 μ‹œμŠ€ν…œ 정보',
        mimeType: 'application/json'
    },
    async () => {
        const systemInfo = {
            server: 'my-mcp-server',
            version: '1.0.0',
            timestamp: new Date().toISOString(),
            uptime: process.uptime()
        }

        return {
            contents: [
                {
                    uri: 'system://info',
                    mimeType: 'application/json',
                    text: JSON.stringify(systemInfo, null, 2)
                }
            ]
        }
    }
)

// μ„œλ²„ μ‹œμž‘
async function main() {
    const transport = new StdioServerTransport()
    await server.connect(transport)
    console.error('MCP μ„œλ²„κ°€ μ‹œμž‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€')
}

main().catch(console.error)

πŸ”§ Cursor MCP μ—°κ²°

κ°œλ°œν•œ MCP μ„œλ²„λ₯Ό Cursorμ—μ„œ ν…ŒμŠ€νŠΈν•  수 μžˆμŠ΅λ‹ˆλ‹€:

μ„€μ • 파일 μˆ˜μ •

./.cursor/mcp.json νŒŒμΌμ„ νŽΈμ§‘ν•©λ‹ˆλ‹€:

{
    "mcpServers": {
        "typescript-mcp-server": {
            "command": "node",
            "args": ["/ABSOLUTE/PATH/TO/YOUR/PROJECT/build/index.js"]
        }
    }
}

주의: μ ˆλŒ€ 경둜λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€. pwd λͺ…λ Ήμ–΄λ‘œ ν˜„μž¬ 경둜λ₯Ό ν™•μΈν•˜μ„Έμš”.

ν…ŒμŠ€νŠΈ λͺ…λ Ήμ–΄

Cursor MCPμ—μ„œ λ‹€μŒκ³Ό 같이 ν…ŒμŠ€νŠΈν•΄λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€:

  • "5 λ”ν•˜κΈ° 3은 μ–Όλ§ˆμ•Ό?" (계산기 도ꡬ ν…ŒμŠ€νŠΈ)
  • "μ•ˆλ…•ν•˜μ„Έμš” 라고 μΈμ‚¬ν•΄μ€˜" (인사 도ꡬ ν…ŒμŠ€νŠΈ)
  • μ„œλ²„ 정보 λ¦¬μ†ŒμŠ€ 쑰회

πŸ”— μ°Έκ³  자료

πŸ“„ λΌμ΄μ„ μŠ€

MIT