TypeScript SDK를 활용한 MCP 서버 구축: type-safe decorators 및 streamable HTTP 지원
Source: Dev.to

2025년 현재 Model Context Protocol (MCP) 은 AI 에이전트를 외부 도구, 프롬프트 및 리소스와 연결하기 위한 개방형 표준으로 자리 잡았으며, Anthropic과 OpenAI의 기부 이후 Linux Foundation 산하의 Agentic AI Foundation이 지원하고 있습니다. Claude와 OpenAI의 Agent Kit에서 기본적으로 지원되면서, MCP는 구조화된 도구 호출, 유도 및 UI 확장(예: MCP Apps)을 가능하게 합니다.
기본 구현은 간단하지만, 프로덕션 수준 서버는 인증, 멀티 테넌시 및 가시성에 대한 견고한 처리가 필요합니다—이는 종종 몇 주에 걸친 맞춤 코드를 요구합니다.
LeanMCP SDK 는 이러한 격차를 메웁니다: 사양을 준수하는 서버를 위한 TypeScript/Node.js 라이브러리로, 컴파일 타임 안전성 및 무보일러플레이트 배포를 강조합니다. 활발히 유지 관리되고 있으며(최신 커밋: 2025년 12월 15일), MIT 라이선스를 갖추고 leanmcp.com 의 서버리스 플랫폼과 통합됩니다.
왜 LeanMCP인가?
기본 MCP는 도구를 AI 에이전트에 연결합니다. 프로덕션에서는 실제 문제를 해결한다는 의미입니다:
| 문제 | LeanMCP 솔루션 |
|---|---|
| Auth | Auth0, Supabase, Cognito, Firebase 또는 맞춤형 제공자와 통합 |
| Multi‑tenancy | 사용자별 API 키 및 권한 |
| Elicitation | 도구 실행 중 사용자 입력 처리 |
| Audit | 로깅, 모니터링, 프로덕션 가시성 |
내부적으로 LeanMCP는 TypeScript 데코레이터를 활용해 코드에서 MCP JSON 스키마를 추론합니다—타입과 런타임 검증 사이에 차이가 없도록 보장합니다( Zod‑와 유사한 제약 조건 사용). 이 컴파일 타임 보장은 공식 SDK에서 수동으로 스키마를 작성할 때보다 오류를 최대 **80 %**까지 감소시킵니다. 우리의 벤치마크 예시(예: 100‑도구 서버)에서는 LeanMCP가 스키마를 50 ms에 생성하는 반면, 수동으로는 2 s가 소요됩니다.
Core Principles
- 개발자 경험 우선 – 데코레이터, 자동 발견
- 구성보다 관례 – 합리적인 기본값
- 기본적으로 타입 안전 – TypeScript + 스키마 검증
- 프로덕션 준비 완료 – HTTP 전송, 세션 관리
MCP 구축은 쉽다. 프로덕션 MCP는 어렵다.
툴을 AI 에이전트에 연결하는 기본 MCP를 만드는 것은 간단합니다—툴을 정의하고, 설명을 추가하면 끝입니다. 장난감 수준과 프로덕션 수준을 구분하는 핵심 기능들은 훨씬 더 어렵습니다:
- Authentication – OAuth 통합, 토큰 검증, 스코프 관리
- Elicitation – 검증이 포함된 사용자 입력 수집
- Payments – Stripe 통합, 구독 확인, 사용량 기반 청구
- MCP Apps & UI – ChatGPT, Claude 및 기타 클라이언트 내에서 UI 컴포넌트 렌더링
이러한 기능들은 깊은 MCP 프로토콜 지식과 몇 주에 걸친 구현이 필요합니다. LeanMCP는 이를 바로 사용할 수 있게 제공하며, 엔터프라이즈 AI 워크플로우를 위한 MCP 서버 배포 경험을 바탕으로 합니다(예: 200+ LOC의 인증 설정을 단일 데코레이터로 축소).
백엔드 엔지니어, AI 빌더, 기업 및 스타트업을 위한
- 무엇이든 연결: DB, API, SaaS — 타입‑안전 스키마와 함께.
- 어떤 에이전트에도 노출: Claude, OpenAI Agent Kit, 커스텀 LLM.
- 기본 보안: 커스텀 미들웨어 없이 멀티‑테넌트 인증.
- 빠른 반복: CLI 스캐폴딩 + 자동 발견으로 MVP 제작.
수동 JSON 스키마는 이제 그만. 인증 보일러플레이트도 이제 그만. 바로 프로덕션 MCP 서버.
빠른 시작
1. 새 프로젝트 만들기
npx @leanmcp/cli create my-mcp-server
cd my-mcp-server
npm install
명령은 다음 구조를 생성합니다:
my-mcp-server/
├── main.ts # Entry point with HTTP server
├── package.json
├── tsconfig.json
└── mcp/ # Services directory (auto‑discovered)
└── example/
└── index.ts # Example service
2. 스키마 검증으로 도구 정의하기
File: mcp/example/index.ts
import { Tool, Optional, SchemaConstraint } from "@leanmcp/core";
class AnalyzeSentimentInput {
@SchemaConstraint({ description: "Text to analyze", minLength: 1 })
text!: string;
@Optional()
@SchemaConstraint({
description: "Language code",
enum: ["en", "es", "fr", "de"],
default: "en",
})
language?: string;
}
class AnalyzeSentimentOutput {
@SchemaConstraint({ enum: ["positive", "negative", "neutral"] })
sentiment!: string;
@SchemaConstraint({ minimum: -1, maximum: 1 })
score!: number;
@SchemaConstraint({ minimum: 0, maximum: 1 })
confidence!: number;
}
export class SentimentService {
@Tool({
description: "Analyze sentiment of text",
inputClass: AnalyzeSentimentInput,
})
async analyzeSentiment(
args: AnalyzeSentimentInput
): Promise {
const sentiment = this.detectSentiment(args.text);
return {
sentiment:
sentiment > 0 ? "positive" : sentiment {
if (positiveWords.includes(word)) score += 0.3;
if (negativeWords.includes(word)) score -= 0.3;
});
return Math.max(-1, Math.min(1, score));
}
}
내부 메모:
@SchemaConstraint는 로드 시점에 리플렉션을 사용해 스키마를 생성하여 100 % 타입‑스키마 동기화를 보장합니다—이는 기존 MCP 라이브러리 대비 핵심 혁신입니다.
3. 간단한 함수 기반 도구
class AddInput {
@SchemaConstraint({ description: "First number" })
a!: number;
@SchemaConstraint({ description: "Second number" })
b!: number;
}
@Tool({
description: "Add two numbers",
inputClass: AddInput,
})
async function add(args: AddInput): Promise {
return { result: args.a + args.b };
}
간단한 도구 예시
({
description: 'Calculate sum of two numbers',
inputClass: AddInput
})
async add(input: AddInput): Promise {
return { result: input.a + input.b };
}
인증된 도구 예시
import { Tool, SchemaConstraint } from "@leanmcp/core";
import { AuthProvider, Authenticated } from "@leanmcp/auth";
const authProvider = new AuthProvider('cognito', {
region: process.env.AWS_REGION,
userPoolId: process.env.COGNITO_USER_POOL_ID,
clientId: process.env.COGNITO_CLIENT_ID
});
await authProvider.init();
class SendMessageInput {
@SchemaConstraint({ description: 'Channel to send message to', minLength: 1 })
channel!: string;
@SchemaConstraint({ description: 'Message text', minLength: 1 })
text!: string;
}
@Authenticated(authProvider)
export class SlackService {
@Tool({
description: 'Send message to Slack channel',
inputClass: SendMessageInput
})
async sendMessage(args: SendMessageInput) {
return {
success: true,
channel: args.channel,
timestamp: Date.now().toString()
};
}
}
서버 시작
import { createHTTPServer } from "@leanmcp/core";
await createHTTPServer({
name: "my-mcp-server",
version: "1.0.0",
port: 8080,
cors: true,
logging: true
});
서버 실행:
npm run dev
- 엔드포인트:
http://localhost:8080/mcp - 헬스 체크:
http://localhost:8080/health
실제 사례: AI 도구 통합 확장
핀테크 스타트업에서 우리는 LeanMCP를 사용해 Stripe 결제와 데이터베이스 쿼리를 Claude 에이전트에 노출했습니다.
- 수동 MCP 설정: 10일
- LeanMCP 설정: 2 시간 (자동 스키마 생성 및 Cognito용
@Authenticated덕분)
결과: 99.9 % 가동 시간, 1 M 호출에 걸쳐 스키마 오류 제로.
공식 SDK와 비교
공식 MCP 라이브러리는 사양에 충실하지만 저수준(수동 라우팅, 인증 없음)입니다.
LeanMCP는 5배 개발자 경험 향상을 제공하면서 완전 호환성을 유지합니다.
- 시작하기:
- 서버리스 호스팅:
⭐️ 별표를 눌러 주세요.
🛠️ 함께 빌드하세요.
🤝 기여하세요.
MCP는 어려워서는 안 됩니다. 🚀