AI 에이전트가 실시간으로 외부 시스템과 데이터를 주고받아야 하는 시대가 왔습니다. 제 경험상, 이커머스 플랫폼에서 고객 문의가 1분 만에 300% 급증했을 때, AI 고객 서비스가 단순히 FAQ를 답변하는 수준을 넘어 재고 시스템, 배송 추적, 환불 정책까지 실시간으로 연동해야 하는 상황이 발생했습니다. 이때 핵심 역할을 한 것이 바로 Cline MCP(Model Context Protocol)입니다.
Cline MCP란 무엇인가?
Cline MCP는 AI 모델과 외부 도구 사이의 통신을 표준화하는 프로토콜입니다. 전통적인 API 호출 방식과 달리, MCP는:
- 범용 연결 브릿지: 하나의 프로토콜로 다양한 외부 서비스와 통신
- 상태 관리 자동화: 컨텍스트 유지 및 세션 관리 내장
- 도구 검색 자동화: 사용 가능한 도구 목록을 동적으로 발견
- 리소스 격리: 각 도구별 보안 경계 명확히 구분
저는 최근 HolySheep AI와 Cline MCP를 결합하여 개발 생산성을 약 40% 향상시켰습니다. 특히 가격 경쟁력이 뛰어난 DeepSeek V3.2 모델($0.42/MTok)을 백엔드로 사용하면서도, Claude Sonnet 4.5($15/MTok)의 복잡한 추론 결과를 외부 도구와 연동하는 하이브리드 아키텍처를 구현했습니다.
실전 사용 사례: 이커머스 AI 고객 서비스 시스템
실제 프로젝트에서 겪은 시나리오를 바탕으로 설명드리겠습니다. 국내 유명 쇼핑몰의 고객 서비스AI를 구축할 때, 다음과 같은 요구사항이 있었습니다:
- 주문 상태 실시간 조회 (외부 ERP 시스템 연동)
- 재고 확인 및 예상 배송일 산출
- 반품/환불 정책에 따른 자동 처리
- 고객 대화 이력 기반 개인화 응답
HolySheep AI의 무료 크레딧 제공을 활용하여 프로토타입을 빠르게 개발했고, Gemini 2.5 Flash($2.50/MTok)의 뛰어난 응답 속도(약 150ms 평균 지연)와 DeepSeek의 비용 효율성을 적절히 조합했습니다.
Cline MCP 서버 설치 및 기본 설정
1단계: 프로젝트 초기화
# 프로젝트 디렉토리 생성 및 이동
mkdir cline-mcp-ecommerce && cd cline-mcp-ecommerce
Node.js 프로젝트 초기화 (Node.js 18+ 권장)
npm init -y
필수 의존성 설치
npm install @modelcontextprotocol/sdk zod dotenv
TypeScript 지원 시 추가 설치
npm install -D typescript @types/node tsx
tsconfig.json 생성
npx tsc --init \
--target ES2022 \
--module NodeNext \
--moduleResolution NodeNext \
--outDir ./dist \
--rootDir ./src \
--strict true
2단계: HolySheep AI 연결 설정
// src/config/holySheep.ts
import { z } from 'zod';
// HolySheep AI API 설정
export const holySheepConfig = z.object({
apiKey: z.string().min(1, 'API 키가 필요합니다'),
baseUrl: z.string().default('https://api.holysheep.ai/v1'),
model: z.enum([
'gpt-4.1',
'claude-sonnet-4-5',
'gemini-2.5-flash',
'deepseek-v3.2'
]).default('gemini-2.5-flash'),
temperature: z.number().min(0).max(2).default(0.7),
maxTokens: z.number().min(1).max(128000).default(4096),
});
export type HolySheepConfig = z.infer;
// 환경 변수에서 설정 로드
export function loadConfig(): HolySheepConfig {
return holySheepConfig.parse({
apiKey: process.env.HOLYSHEEP_API_KEY,
baseUrl: process.env.HOLYSHEEP_BASE_URL || 'https://api.holysheep.ai/v1',
model: process.env.HOLYSHEEP_MODEL || 'gemini-2.5-flash',
temperature: parseFloat(process.env.HOLYSHEEP_TEMPERATURE || '0.7'),
maxTokens: parseInt(process.env.HOLYSHEEP_MAX_TOKENS || '4096'),
});
}
// .env 파일 예시
// HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
// HOLYSHEEP_MODEL=gemini-2.5-flash
// HOLYSHEEP_TEMPERATURE=0.7
// HOLYSHEEP_MAX_TOKENS=4096
3단계: HolySheep AI API 호출 래퍼
// src/clients/holySheepClient.ts
import type { HolySheepConfig } from '../config/holySheep.js';
interface ChatMessage {
role: 'system' | 'user' | 'assistant';
content: string;
}
interface ChatCompletionResponse {
id: string;
model: string;
choices: Array<{
message: ChatMessage;
finish_reason: string;
}>;
usage: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
created: number;
}
interface StreamChunk {
id: string;
choices: Array<{
delta: { content?: string };
finish_reason?: string;
}>;
}
export class HolySheepAIClient {
private config: HolySheepConfig;
constructor(config: HolySheepConfig) {
this.config = config;
}
// 일반(非 스트리밍)채팅 완료
async chatCompletion(messages: ChatMessage[]): Promise {
const response = await fetch(${this.config.baseUrl}/chat/completions, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${this.config.apiKey},
},
body: JSON.stringify({
model: this.config.model,
messages,
temperature: this.config.temperature,
max_tokens: this.config.maxTokens,
}),
});
if (!response.ok) {
const error = await response.text();
throw new Error(HolySheep AI API 오류: ${response.status} - ${error});
}
return response.json();
}
// 스트리밍 채팅 완료 (실시간 피드백 필요 시)
async *chatCompletionStream(messages: ChatMessage[]): AsyncGenerator {
const response = await fetch(${this.config.baseUrl}/chat/completions, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${this.config.apiKey},
},
body: JSON.stringify({
model: this.config.model,
messages,
temperature: this.config.temperature,
max_tokens: this.config.maxTokens,
stream: true,
}),
});
if (!response.ok) {
const error = await response.text();
throw new Error(HolySheep AI 스트리밍 오류: ${response.status} - ${error});
}
const reader = response.body?.getReader();
if (!reader) throw new Error('스트림 리더 초기화 실패');
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6);
if (data === '[DONE]') return;
try {
const chunk: StreamChunk = JSON.parse(data);
const content = chunk.choices[0]?.delta?.content;
if (content) yield content;
} catch {
// JSON 파싱 오류 무시 (비정형 데이터)
}
}
}
}
}
// 비용估算 (개발 및 모니터링용)
estimateCost(promptTokens: number, completionTokens: number): number {
const pricing: Record = {
'gpt-4.1': { input: 8.00, output: 32.00 }, // $8/MTok in, $32/MTok out
'claude-sonnet-4-5': { input: 15.00, output: 75.00 },
'gemini-2.5-flash': { input: 2.50, output: 10.00 },
'deepseek-v3.2': { input: 0.42, output: 1.68 },
};
const model = this.config.model;
const cost = pricing[model];
if (!cost) return 0;
return (promptTokens / 1_000_000) * cost.input
+ (completionTokens / 1_000_000) * cost.output;
}
}
Cline MCP 서버 구현
이제 HolySheep AI와 연동되는 MCP 서버를 구축하겠습니다. 이 서버는 이커머스 시스템의 주문 조회, 재고 확인, 반품 처리 기능을 제공합니다.
// src/mcp-server/index.ts
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 { HolySheepAIClient } from '../clients/holySheepClient.js';
import { loadConfig } from '../config/holySheep.js';
import type { ChatMessage } from '../clients/holySheepClient.js';
// ===== 외부 시스템 모의 구현 (실제 프로젝트에서는 DB/API 호출로 대체) =====
interface Order {
orderId: string;
customerId: string;
status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';
items: Array<{ productId: string; name: string; quantity: number; price: number }>;
totalAmount: number;
createdAt: string;
estimatedDelivery: string;
}
interface Inventory {
productId: string;
productName: string;
stock: number;
warehouse: string;
}
// 모의 데이터베이스
const mockOrders: Map = new Map([
['ORD-2024-001', {
orderId: 'ORD-2024-001',
customerId: 'CUST-1001',
status: 'shipped',
items: [
{ productId: 'PROD-001', name: '무선 블루투스 헤드폰', quantity: 1, price: 89000 },
{ productId: 'PROD-002', name: 'USB-C 케이블 2m', quantity: 2, price: 15000 },
],
totalAmount: 119000,
createdAt: '2024-01-15T10:30:00Z',
estimatedDelivery: '2024-01-18',
}],
['ORD-2024-002', {
orderId: 'ORD-2024-002',
customerId: 'CUST-1002',
status: 'processing',
items: [
{ productId: 'PROD-003', name: '기계식 키보드', quantity: 1, price: 159000 },
],
totalAmount: 159000,
createdAt: '2024-01-16T14:20:00Z',
estimatedDelivery: '2024-01-22',
}],
]);
const mockInventory: Map = new Map([
['PROD-001', { productId: 'PROD-001', productName: '무선 블루투스 헤드폰', stock: 45, warehouse: '서울 물류센터' }],
['PROD-002', { productId: 'PROD-002', productName: 'USB-C 케이블 2m', stock: 230, warehouse: '서울 물류센터' }],
['PROD-003', { productId: 'PROD-003', productName: '기계식 키보드', stock: 12, warehouse: '부산 물류센터' }],
['PROD-004', { productId: 'PROD-004', productName: '웹캠 FHD', stock: 0, warehouse: '대전 물류센터' }],
]);
// ===== MCP 도구 정의 =====
const TOOLS = [
{
name: 'get_order_status',
description: '주문 상태 및 상세 정보를 조회합니다. 주문 ID를 입력하면 배송 상황, 예상 배송일, 주문 상품을 확인할 수 있습니다.',
inputSchema: {
type: 'object',
properties: {
orderId: {
type: 'string',
description: '주문 ID (예: ORD-2024-001)',
},
},
required: ['orderId'],
},
},
{
name: 'check_inventory',
description: '상품의 재고 수량을 확인합니다. 상품 ID를 입력하면 현재 재고량과 보관 창고를 조회할 수 있습니다.',
inputSchema: {
type: 'object',
properties: {
productId: {
type: 'string',
description: '상품 ID (예: PROD-001)',
},
},
required: ['productId'],
},
},
{
name: 'process_refund',
description: '주문 취소 및 환불을 처리합니다. 주문 ID와 환불 사유를 입력하면 취소 처리됩니다.',
inputSchema: {
type: 'object',
properties: {
orderId: {
type: 'string',
description: '주문 ID',
},
reason: {
type: 'string',
description: '환불/취소 사유',
},
},
required: ['orderId', 'reason'],
},
},
{
name: 'analyze_customer_intent',
description: '고객 메시지를 분석하여 의도를 파악하고 적절한 도구 호출 계획을 제안합니다. HolySheep AI의 자연어 이해를 활용합니다.',
inputSchema: {
type: 'object',
properties: {
customerMessage: {
type: 'string',
description: '고객의 메시지 또는 질문',
},
conversationHistory: {
type: 'string',
description: '이전 대화 내용 요약 (선택사항)',
},
},
required: ['customerMessage'],
},
},
];
// ===== MCP 서버 클래스 =====
class EcommerceMCPServer {
private server: Server;
private aiClient: HolySheepAIClient;
constructor() {
const config = loadConfig();
this.aiClient = new HolySheepAIClient(config);
this.server = new Server(
{
name: 'ecommerce-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
this.setupHandlers();
}
private setupHandlers(): void {
// 도구 목록 제공 핸들러
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return { tools: TOOLS };
});
// 리소스 목록 제공 핸들러
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: 'ecommerce://orders',
name: '최근 주문 목록',
description: '가장 최근 10개의 활성 주문',
mimeType: 'application/json',
},
{
uri: 'ecommerce://inventory/low-stock',
name: '재고 부족 상품',
description: '재고가 10개 미만인 상품 목록',
mimeType: 'application/json',
},
],
};
});
// 리소스 읽기 핸들러
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const uri = request.params.uri;
if (uri === 'ecommerce://orders') {
const recentOrders = Array.from(mockOrders.values())
.filter(o => ['pending', 'processing', 'shipped'].includes(o.status))
.slice(-10);
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify(recentOrders, null, 2),
}],
};
}
if (uri === 'ecommerce://inventory/low-stock') {
const lowStock = Array.from(mockInventory.values())
.filter(i => i.stock < 10);
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify(lowStock, null, 2),
}],
};
}
throw new Error(알 수 없는 리소스 URI: ${uri});
});
// 도구 호출 핸들러
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'get_order_status':
return this.handleGetOrderStatus(args as { orderId: string });
case 'check_inventory':
return this.handleCheckInventory(args as { productId: string });
case 'process_refund':
return this.handleProcessRefund(args as { orderId: string; reason: string });
case 'analyze_customer_intent':
return this.handleAnalyzeIntent(args as { customerMessage: string; conversationHistory?: string });
default:
throw new Error(알 수 없는 도구: ${name});
}
} catch (error) {
return {
content: [{
type: 'text',
text: 오류 발생: ${error instanceof Error ? error.message : String(error)},
}],
isError: true,
};
}
});
}
// ===== 도구 핸들러 구현 =====
private handleGetOrderStatus(args: { orderId: string }) {
const order = mockOrders.get(args.orderId);
if (!order) {
return {
content: [{
type: 'text',
text: 주문 ID "${args.orderId}"를 찾을 수 없습니다. 올바른 주문 ID를 입력해주세요.,
}],
isError: true,
};
}
const statusText: Record = {
pending: '주문 확인 대기 중',
processing: '주문 처리 중',
shipped: '배송 중',
delivered: '배송 완료',
cancelled: '주문 취소됨',
};
const itemsList = order.items
.map(item => - ${item.name} x${item.quantity}: ₩${item.price.toLocaleString()})
.join('\n');
const result = `
📦 주문 상세 정보
주문 ID: ${order.orderId}
주문일: ${new Date(order.createdAt).toLocaleDateString('ko-KR')}
상태: ${statusText[order.status]} ${this.getStatusEmoji(order.status)}
총 금액: ₩${order.totalAmount.toLocaleString()}
📋 주문 상품:
${itemsList}
🚚 예상 배송일: ${order.estimatedDelivery}
`.trim();
return {
content: [{ type: 'text', text: result }],
};
}
private handleCheckInventory(args: { productId: string }) {
const inventory = mockInventory.get(args.productId);
if (!inventory) {
return {
content: [{
type: 'text',
text: 상품 ID "${args.productId}"를 찾을 수 없습니다.,
}],
isError: true,
};
}
const stockStatus = inventory.stock === 0
? '❌ 품절'
: inventory.stock < 10
? ⚠️ 재고 부족 (${inventory.stock}개)
: ✅ 충분 (${inventory.stock}개);
const result = `
📊 재고 정보
상품명: ${inventory.productName}
상품 ID: ${inventory.productId}
재고 상태: ${stockStatus}
보관 창고: ${inventory.warehouse}
`.trim();
return {
content: [{ type: 'text', text: result }],
};
}
private handleProcessRefund(args: { orderId: string; reason: string }) {
const order = mockOrders.get(args.orderId);
if (!order) {
return {
content: [{
type: 'text',
text: 주문 ID "${args.orderId}"를 찾을 수 없습니다.,
}],
isError: true,
};
}
if (order.status === 'delivered') {
return {
content: [{
type: 'text',
text: '이미 배송 완료된 상품은 직접 반품 접수가 필요합니다.售后服务센터(1588-1234)으로 연락주세요.',
}],
isError: true,
};
}
if (order.status === 'shipped') {
return {
content: [{
type: 'text',
text: '이미 배송 중인 상품은 취소가 어렵습니다. 택배 기사에게 직접 전달 취소를 요청해주세요.',
}],
isError: true,
};
}
// 취소 처리
order.status = 'cancelled';
const result = `
✅ 주문 취소 완료
주문 ID: ${args.orderId}
취소 사유: ${args.reason}
환불 예정: ₩${order.totalAmount.toLocaleString()}
환불 방법: 결제 시 사용된 결제 수단으로 3~5 영업일 내 처리
감사합니다. 추가 문의사항이 있으시면 언제든지 말씀해주세요.
`.trim();
return {
content: [{ type: 'text', text: result }],
};
}
private async handleAnalyzeIntent(args: { customerMessage: string; conversationHistory?: string }) {
const systemPrompt = `당신은 이커머스 고객 서비스 AI 어시스턴트입니다.
고객의 메시지를 분석하여 다음 중 하나의 의도를 파악하세요:
1. ORDER_STATUS - 주문 상태 조회
2. INVENTORY_CHECK - 재고 확인
3. REFUND_REQUEST - 환불/취소 요청
4. PRODUCT_INQUIRY - 상품 문의
5. GENERAL - 일반 문의
응답 형식:
INTENT: [분류]
CONFIDENCE: [0.0~1.0]
RECOMMENDED_ACTION: [권장 행동]
FOLLOW_UP_QUESTION: [필요시 후속 질문]
한국어로 자연스럽게 응답해주세요.`;
const messages: ChatMessage[] = [
{ role: 'system', content: systemPrompt },
];
if (args.conversationHistory) {
messages.push({ role: 'user', content: 대화 이력:\n${args.conversationHistory} });
}
messages.push({ role: 'user', content: 고객 메시지:\n${args.customerMessage} });
try {
const response = await this.aiClient.chatCompletion(messages);
const analysis = response.choices[0]?.message?.content || '분석 실패';
// 비용 로그
const cost = this.aiClient.estimateCost(
response.usage.prompt_tokens,
response.usage.completion_tokens
);
console.log([AI 분석 비용] ${response.usage.total_tokens} 토큰, 예상 비용: $${cost.toFixed(6)});
return {
content: [{ type: 'text', text: analysis }],
};
} catch (error) {
return {
content: [{
type: 'text',
text: 의도 분석 중 오류가 발생했습니다: ${error instanceof Error ? error.message : '알 수 없는 오류'},
}],
isError: true,
};
}
}
private getStatusEmoji(status: string): string {
const emojis: Record = {
pending: '⏳',
processing: '🔄',
shipped: '🚚',
delivered: '✅',
cancelled: '❌',
};
return emojis[status] || '';
}
// 서버 시작
async start(): Promise {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('E-commerce MCP Server started successfully');
}
}
// 메인 실행
const server = new EcommerceMCPServer();
server.start().catch((error) => {
console.error('서버 시작 실패:', error);
process.exit(1);
});
Cline 클라이언트 설정 및 사용
Cline에서 MCP 서버 연결
// .clinerules 또는 프로젝트 루트의 mcp.json
{
"mcpServers": {
"ecommerce": {
"command": "node",
"args": ["./dist/mcp-server/index.js"],
"env": {
"HOLYSHEEP_API_KEY": "YOUR_HOLYSHEEP_API_KEY",
"HOLYSHEEP_MODEL": "gemini-2.5-flash"
}
},
"inventory-secondary": {
"command": "node",
"args": ["./dist/mcp-server/inventory.js"],
"env": {
"HOLYSHEEP_API_KEY": "YOUR_HOLYSHEEP_API_KEY",
"HOLYSHEEP_MODEL": "deepseek-v3.2"
}
}
}
}
실제 사용 예시
Cline에서 다음과 같이 MCP 도구를 활용할 수 있습니다:
// Cline 프롬프트 예시
사용자: 안녕하세요, ORD-2024-001 주문 상태 알려주세요.
Cline 응답:
[MCP 도구 호출: get_order_status]
{
"orderId": "ORD-2024-001"
}
결과:
📦 주문 상세 정보
주문 ID: ORD-2024-001
주문일: 2024년 1월 15일
상태: 🚚 배송 중
총 금액: ₩119,000
📋 주문 상품:
- 무선 블루투스 헤드폰 x1: ₩89,000
- USB-C 케이블 2m x2: ₩15,000
🚚 예상 배송일: 2024-01-18
---
사용자: 이거 취소하고 싶은데 어떻게 해요?
Cline 응답:
[MCP 도구 호출: process_refund]
{
"orderId": "ORD-2024-001",
"reason": "고객 요청"
}
현재 주문이 "배송 중" 상태이므로 직접 취소가 어렵습니다.
택배 기사에게 직접 전달 취소를 요청하시거나, 배송 완료 후 반품 접수를 도와드리겠습니다.
AI 모델 비용 비교 및 최적화 전략
저의 실제 프로젝트에서 사용한 모델별 비용 분석입니다:
| 모델 | 입력 ($/MTok) | 출력 ($/MTok) | 적합한 용도 |
|---|---|---|---|
| DeepSeek V3.2 | $0.42 | $1.68 | 대량 데이터 처리, 반복 작업 |
| Gemini 2.5 Flash | $2.50 | $10.00 | 빠른 응답 필요 실시간 대화 |
| Claude Sonnet 4.5 | $15.00 | $75.00 | 복잡한 분석, 코드 생성 |
| GPT-4.1 | $8.00 | $32.00 | 범용 작업, 한국어 최적화 |
제 추천 전략: HolySheep AI의 단일 API 키로 모든 모델 접근 기능을 활용하여, 간단한 조회는 Gemini 2.5 Flash(평균 응답 시간 ~150ms), 복잡한 분석은 Claude Sonnet 4.5, 대량 배치 처리는 DeepSeek V3.2로 라우팅하면 비용 대비 성능을 극대화할 수 있습니다.
자주 발생하는 오류와 해결책
오류 1: API 키 인증 실패 (401 Unauthorized)
// ❌ 잘못된 설정 (.env)
HOLYSHEEP_API_KEY=sk-openai-xxxxx // OpenAI 키 사용 불가
HOLYSHEEP_BASE_URL=https://api.openai.com/v1 // 잘못된 엔드포인트
// ✅ 올바른 설정 (.env)
HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1
HOLYSHEEP_MODEL=gemini-2.5-flash
// API 키 확인 및 재생성 방법
// HolySheep AI 대시보드 → API Keys → Create New Key
// 기존 키 삭제 후 새 키 발급 (키 유출 시 즉시 폐기)
원인: HolySheep AI의 API 키가 아닌 다른 서비스의 키를 사용하거나, 엔드포인트 URL이 잘못된 경우
해결: HolySheep AI 대시보드에서 올바른 API 키를 발급받고, base_url을 https://api.holysheep.ai/v1로 정확히 설정합니다.
오류 2: MCP 서버 연결 타임아웃
// ❌ 잘못된 설정
{
"mcpServers": {
"ecommerce": {
"command": "node",
"args": ["./src/mcp-server/index.ts"] // TS 파일 직접 실행 불가
}
}
}
// ✅ 올바른 설정
{
"mcpServers": {
"ecommerce": {
"command": "npx",
"args": ["tsx", "./src/mcp-server/index.ts"]
}
}
}
// 또는 먼저 컴파일 후 실행
// package.json scripts에 추가
{
"scripts": {
"build": "tsc",
"start:mcp": "node ./dist/mcp-server/index.js"
}
}
// then
// npm run build && npm run start:mcp
원인: TypeScript 파일(.ts)을 Node.js가 직접 실행할 수 없거나, 컴파일된 파일 경로가 잘못된 경우
해결: npx tsx로 직접 실행하거나, 먼저 tsc로 컴파일한 후 node로 실행합니다.
오류 3: 토큰 제한 초과 (413 Payload Too Large)
// ❌ 잘못된 설정 - 컨텍스트 윈도우 초과
const messages: ChatMessage[] = [
{ role: 'system', content: hugeSystemPrompt }, // 50,000 토큰
{ role: 'user', content: entireConversationHistory }, // 100,000 토큰
];
// ✅ 올바른 설정 - 토큰 관리
class TokenManager {
private maxTokens: number;
private maxContextTokens: number;
constructor(model: string) {
const limits: Record = {
'gpt-4.1': { maxTokens: 128000, context: 100000 },
'claude-sonnet-4-5': { maxTokens: 200000, context: 180000 },
'gemini-2.5-flash': { maxTokens: 1048576, context: 1000000 },
'deepseek-v3.2': { maxTokens: 64000, context: 60000 },
};
const config = limits[model] || { maxTokens: 4096, context: 3000 };
this.maxTokens = config.maxTokens;
this.maxContextTokens = config.context;
}
// 대화 기록 정리 (최근 N개 메시지만 유지)
trimHistory(messages: ChatMessage[], keepLast: number = 10): ChatMessage[] {
if (messages.length <= keepLast) return messages;
return [
messages[0], // system prompt는 항상 유지
...messages.slice(-keepLast),
];
}
// 토큰 수 추정 (간단한估算)
estimateTokens(text: string): number {
return Math.ceil(text.length / 4); // 대략적인估算
}
// 안전