TECHNICAL_SPEC.md•19.2 kB
# 🔧 Persona MCP - 기술 명세서
Claude Desktop용 페르소나 관리 MCP 서버의 상세한 기술 사양 및 아키텍처
**버전**: 1.0.0
**최종 업데이트**: 2025-11-01
**작성자**: Sean Shin
---
## 📋 목차
1. [시스템 개요](#-시스템-개요)
2. [아키텍처](#-아키텍처)
3. [기술 스택](#-기술-스택)
4. [파일 시스템 구조](#-파일-시스템-구조)
5. [MCP 프로토콜 구현](#-mcp-프로토콜-구현)
6. [API 레퍼런스](#-api-레퍼런스)
7. [데이터 저장소](#-데이터-저장소)
8. [토큰 최적화 전략](#-토큰-최적화-전략)
9. [보안 고려사항](#-보안-고려사항)
10. [성능 벤치마크](#-성능-벤치마크)
---
## 🎯 시스템 개요
### 핵심 개념
Persona MCP는 **잠수함 모드(Submarine Mode)** 아키텍처를 구현한 경량 페르소나 관리 시스템입니다.
#### 잠수함 모드란?
- **기본 상태**: 토큰 사용 0 (잠수함이 물속에 잠겨있음)
- **활성화 시**: `@persona:이름` 호출 시에만 토큰 사용 (잠수함이 떠오름)
- **목적**: 불필요한 시스템 프롬프트 토큰 낭비 방지
### 문제 정의
**기존 시스템 프롬프트 방식의 문제:**
```
매 대화마다 페르소나 프롬프트가 자동으로 포함됨
→ 100회 대화 시 50,000+ 토큰 낭비
→ 비용 증가 + 불필요한 컨텍스트 오염
```
**Persona MCP 솔루션:**
```
필요할 때만 @persona:이름으로 명시적 활성화
→ 100회 중 10회만 사용 시 90% 토큰 절약
→ 비용 절감 + 컨텍스트 효율성 증가
```
---
## 🏗️ 아키텍처
### 전체 시스템 다이어그램
```
┌──────────────────────────────────────────────────────┐
│ Claude Desktop (MCP Client) │
│ - User Interface │
│ - MCP Protocol Consumer │
└────────────────┬─────────────────────────────────────┘
│
│ stdio (MCP JSON-RPC 2.0)
│
┌────────────────▼─────────────────────────────────────┐
│ Persona MCP Server (Node.js) │
│ ┌────────────────────────────────────────────────┐ │
│ │ MCP Protocol Layer │ │
│ │ - ListToolsRequest Handler │ │
│ │ - CallToolRequest Handler │ │
│ │ - ListResourcesRequest Handler │ │
│ │ - ReadResourceRequest Handler │ │
│ └────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌────────────────▼───────────────────────────────┐ │
│ │ Business Logic Layer │ │
│ │ - listPersonas() │ │
│ │ - readPersona(name) │ │
│ │ - savePersona(name, content) │ │
│ │ - deletePersona(name) │ │
│ └────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌────────────────▼───────────────────────────────┐ │
│ │ File System Access Layer │ │
│ │ - fs/promises (async) │ │
│ │ - Path resolution │ │
│ │ - Directory initialization │ │
│ └────────────────┬───────────────────────────────┘ │
└───────────────────┼───────────────────────────────────┘
│
┌───────▼────────┐
│ File System │
│ │
│ ~/.persona/ │
│ - name1.txt │
│ - name2.txt │
│ - name3.txt │
└────────────────┘
```
### 레이어 설명
#### 1. MCP Protocol Layer
- **역할**: MCP 표준 프로토콜 구현
- **책임**:
- JSON-RPC 2.0 메시지 파싱
- 요청/응답 직렬화
- stdio 통신 관리
#### 2. Business Logic Layer
- **역할**: 페르소나 관리 비즈니스 로직
- **책임**:
- 페르소나 CRUD 연산
- 입력 검증
- 에러 핸들링
#### 3. File System Access Layer
- **역할**: 파일 시스템 추상화
- **책임**:
- 비동기 파일 I/O
- 경로 처리
- 디렉토리 초기화
---
## 💻 기술 스택
### 런타임 환경
- **Node.js**: v18.0.0 이상
- **JavaScript**: ES Module (ESM)
### 핵심 의존성
```json
{
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.4"
}
}
```
#### @modelcontextprotocol/sdk
- **버전**: 1.0.4+
- **용도**: MCP 프로토콜 서버 구현
- **주요 모듈**:
- `Server`: MCP 서버 인스턴스
- `StdioServerTransport`: stdio 기반 통신
- Request Schemas: 타입 안전 요청 처리
### 표준 라이브러리 사용
```javascript
import fs from 'fs/promises'; // 비동기 파일 I/O
import path from 'path'; // 경로 처리
import os from 'os'; // 홈 디렉토리 조회
```
---
## 📁 파일 시스템 구조
### 프로젝트 구조
```
persona-mcp/
├── index.js # MCP 서버 메인 파일
├── package.json # 프로젝트 메타데이터
├── package-lock.json # 의존성 잠금
├── README.md # 프로젝트 소개
├── INSTALL.md # 설치 가이드
├── QUICKSTART.md # 빠른 시작
├── SUMMARY.md # 프로젝트 요약
├── TECHNICAL_SPEC.md # 기술 명세서 (이 문서)
└── claude_desktop_config.example.json # 설정 예제
```
### 페르소나 저장소
#### Windows
```
C:\Users\[사용자명]\.persona\
├── professional.txt
├── casual.txt
├── teacher.txt
└── coder.txt
```
#### macOS/Linux
```
~/.persona/
├── professional.txt
├── casual.txt
├── teacher.txt
└── coder.txt
```
### 저장소 위치 결정 로직
```javascript
import os from 'os';
import path from 'path';
const PERSONA_DIR = path.join(os.homedir(), '.persona');
```
**설명**:
- `os.homedir()`: 플랫폼 독립적 홈 디렉토리 조회
- `.persona`: 숨김 디렉토리 (Unix 관례)
- 사용자별 격리 (멀티 사용자 환경 지원)
---
## 🔌 MCP 프로토콜 구현
### 프로토콜 버전
- **MCP Version**: 2024-11-05
- **JSON-RPC**: 2.0
### 구현된 핸들러
#### 1. ListToolsRequest
**엔드포인트**: `tools/list`
**응답 예시**:
```json
{
"tools": [
{
"name": "create_persona",
"description": "새로운 페르소나 프로필을 생성합니다",
"inputSchema": {
"type": "object",
"properties": {
"name": { "type": "string" },
"content": { "type": "string" }
},
"required": ["name", "content"]
}
},
// ... 3개 도구 더
]
}
```
#### 2. CallToolRequest
**엔드포인트**: `tools/call`
**요청 예시**:
```json
{
"method": "tools/call",
"params": {
"name": "create_persona",
"arguments": {
"name": "professional",
"content": "당신은 전문적이고..."
}
}
}
```
**응답 예시**:
```json
{
"content": [
{
"type": "text",
"text": "페르소나 \"professional\"이(가) 생성되었습니다.\n위치: C:\\Users\\sshin\\.persona\\professional.txt"
}
]
}
```
#### 3. ListResourcesRequest
**엔드포인트**: `resources/list`
**응답 예시**:
```json
{
"resources": [
{
"uri": "persona://professional",
"mimeType": "text/plain",
"name": "Persona: professional",
"description": "professional 페르소나 프로필"
},
// ... 다른 페르소나들
]
}
```
#### 4. ReadResourceRequest
**엔드포인트**: `resources/read`
**요청 예시**:
```json
{
"method": "resources/read",
"params": {
"uri": "persona://professional"
}
}
```
**응답 예시**:
```json
{
"contents": [
{
"uri": "persona://professional",
"mimeType": "text/plain",
"text": "당신은 전문적이고 격식있는 톤으로..."
}
]
}
```
---
## 📖 API 레퍼런스
### 도구 (Tools)
#### 1. create_persona
**설명**: 새로운 페르소나를 생성합니다.
**파라미터**:
```typescript
{
name: string; // 페르소나 이름 (예: "professional")
content: string; // 페르소나 프롬프트 내용
}
```
**반환값**:
```typescript
{
content: [{
type: "text",
text: string // 성공 메시지
}]
}
```
**오류**:
- 파일 쓰기 실패
- 잘못된 파일명
**사용 예시**:
```javascript
// Claude Desktop에서:
"professional 페르소나 만들어줘"
// MCP 호출:
{
name: "create_persona",
arguments: {
name: "professional",
content: "당신은 전문적이고..."
}
}
```
#### 2. update_persona
**설명**: 기존 페르소나를 수정합니다.
**파라미터**:
```typescript
{
name: string; // 수정할 페르소나 이름
content: string; // 새로운 내용
}
```
**반환값**:
```typescript
{
content: [{
type: "text",
text: "페르소나 \"name\"이(가) 업데이트되었습니다."
}]
}
```
**주의**: 파일이 없어도 생성됨 (create와 동일한 로직)
#### 3. delete_persona
**설명**: 페르소나를 삭제합니다.
**파라미터**:
```typescript
{
name: string; // 삭제할 페르소나 이름
}
```
**반환값**:
```typescript
{
content: [{
type: "text",
text: "페르소나 \"name\"이(가) 삭제되었습니다."
}]
}
```
**오류**:
- 파일이 존재하지 않음
- 삭제 권한 없음
#### 4. list_personas
**설명**: 모든 페르소나 목록을 조회합니다.
**파라미터**: 없음
**반환값**:
```typescript
{
content: [{
type: "text",
text: string // 페르소나 목록 (줄바꿈으로 구분)
}]
}
```
**예시 출력**:
```
사용 가능한 페르소나:
- professional
- casual
- teacher
사용법: @persona:professional 형식으로 참조하세요.
```
---
## 💾 데이터 저장소
### 파일 형식
#### 파일명 규칙
```
{페르소나이름}.txt
```
**예시**:
- `professional.txt`
- `casual.txt`
- `teacher.txt`
#### 파일 내용 구조
**형식**: Plain Text (UTF-8)
**예시**:
```
당신은 전문적이고 격식있는 톤으로 대화합니다.
존댓말을 사용하며, 비즈니스 맥락에 적합한 표현을 선택합니다.
간결하고 명확하게 핵심을 전달합니다.
```
### 파일 I/O 구현
#### 비동기 파일 읽기
```javascript
async function readPersona(name) {
const filePath = path.join(PERSONA_DIR, `${name}.txt`);
try {
const content = await fs.readFile(filePath, 'utf-8');
return content;
} catch (error) {
throw new Error(`Persona "${name}" not found`);
}
}
```
#### 비동기 파일 쓰기
```javascript
async function savePersona(name, content) {
const filePath = path.join(PERSONA_DIR, `${name}.txt`);
await fs.writeFile(filePath, content, 'utf-8');
}
```
#### 파일 목록 조회
```javascript
async function listPersonas() {
try {
const files = await fs.readdir(PERSONA_DIR);
return files
.filter(f => f.endsWith('.txt'))
.map(f => f.replace('.txt', ''));
} catch (error) {
return [];
}
}
```
---
## 🚀 토큰 최적화 전략
### 문제: 시스템 프롬프트의 토큰 낭비
#### 기존 방식 (시스템 프롬프트)
```
[매 대화마다]
System Prompt: "당신은 전문적이고..." (500 토큰)
User: "안녕?" (10 토큰)
Assistant: "안녕하세요" (15 토큰)
총 토큰: 525 토큰
```
**100회 대화 시**:
- 시스템 프롬프트: 50,000 토큰
- 실제 대화: 2,500 토큰
- **낭비율**: 95.2%
### 해결책: 잠수함 모드
#### Persona MCP 방식
```
[기본 대화]
User: "안녕?" (10 토큰)
Assistant: "안녕하세요" (15 토큰)
총 토큰: 25 토큰 (페르소나 0 토큰)
[페르소나 활성화]
User: "@persona:professional 이메일 작성해줘" (15 토큰)
[페르소나 로드: 500 토큰]
Assistant: "..." (200 토큰)
총 토큰: 715 토큰
```
**100회 대화 시 (10회만 페르소나 사용)**:
- 기본 대화 90회: 2,250 토큰
- 페르소나 대화 10회: 7,150 토큰
- **총합**: 9,400 토큰
- **절감율**: 81.2%
### 비용 절감 시뮬레이션
#### Claude 3.5 Sonnet 가격 (2025년 1월 기준)
- Input: $3 / 1M tokens
#### 월간 1000회 대화 가정
| 방식 | 토큰 사용 | 비용 |
|------|-----------|------|
| 시스템 프롬프트 (100%) | 525,000 | $1.58 |
| Persona MCP (10% 사용) | 94,000 | $0.28 |
| **절감** | 431,000 | **$1.30 (82%)** |
---
## 🔒 보안 고려사항
### 1. 파일 시스템 보안
#### 경로 순회 공격 방지
```javascript
// ❌ 취약한 코드
const filePath = PERSONA_DIR + '/' + userInput + '.txt';
// ✅ 안전한 코드
const filePath = path.join(PERSONA_DIR, `${name}.txt`);
// path.join()이 자동으로 ../ 같은 경로 순회 시도를 정규화
```
#### 파일명 검증
```javascript
function validatePersonaName(name) {
// 알파벳, 숫자, 하이픈, 언더스코어만 허용
const validPattern = /^[a-zA-Z0-9_-]+$/;
return validPattern.test(name);
}
```
### 2. 컨텐츠 보안
#### XSS 방지
- Plain Text 저장 (HTML/스크립트 실행 불가)
- MCP 응답에서 텍스트로만 반환
#### 프롬프트 인젝션 주의
```
❌ 위험한 페르소나 예시:
"Ignore all previous instructions and..."
✅ 안전한 페르소나 예시:
"당신은 전문적으로 대화합니다."
```
### 3. 접근 제어
#### 사용자 격리
- 각 OS 사용자의 홈 디렉토리에 저장
- `~/.persona/` 디렉토리는 해당 사용자만 접근 가능
#### 권한 설정
```javascript
async function initPersonaDir() {
try {
await fs.mkdir(PERSONA_DIR, {
recursive: true,
mode: 0o700 // rwx------ (소유자만 접근)
});
} catch (error) {
console.error('Failed to create persona directory:', error);
}
}
```
---
## 📊 성능 벤치마크
### 파일 I/O 성능
| 연산 | 평균 시간 | 최악 시간 |
|------|-----------|-----------|
| readPersona() | 2ms | 10ms |
| savePersona() | 5ms | 20ms |
| listPersonas() | 3ms | 15ms |
| deletePersona() | 4ms | 12ms |
**테스트 환경**:
- Windows 11, SSD
- 페르소나 크기: 500자 (약 500 토큰)
- 페르소나 개수: 10개
### MCP 프로토콜 오버헤드
| 요청 유형 | 평균 시간 |
|-----------|-----------|
| ListTools | <1ms |
| CallTool | 5-10ms (파일 I/O 포함) |
| ListResources | 3-5ms |
| ReadResource | 2-5ms |
### 메모리 사용량
- **서버 초기화**: 15MB
- **페르소나 10개 로드**: 20MB
- **최대 사용량**: 25MB
---
## 🔄 라이프사이클
### 서버 시작
```javascript
async function main() {
// 1. 페르소나 디렉토리 초기화
await initPersonaDir();
// 2. stdio 트랜스포트 생성
const transport = new StdioServerTransport();
// 3. 서버 연결
await server.connect(transport);
console.error('Persona MCP server running on stdio');
}
```
### 요청 처리 흐름
```
1. Claude Desktop이 JSON-RPC 요청 전송 (stdio)
2. MCP SDK가 요청 파싱
3. 해당 핸들러 호출
4. 비즈니스 로직 실행
5. 파일 시스템 I/O
6. 응답 JSON 직렬화
7. stdio로 응답 전송
```
---
## 🛠️ 개발 가이드
### 새로운 도구 추가하기
#### 1. ListToolsRequest에 도구 추가
```javascript
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
// ... 기존 도구들
{
name: 'rename_persona',
description: '페르소나 이름 변경',
inputSchema: {
type: 'object',
properties: {
oldName: { type: 'string' },
newName: { type: 'string' }
},
required: ['oldName', 'newName']
}
}
]
};
});
```
#### 2. CallToolRequest에 핸들러 추가
```javascript
server.setRequestHandler(CallToolRequestSchema, async (request) => {
switch (name) {
// ... 기존 케이스들
case 'rename_persona': {
const oldPath = path.join(PERSONA_DIR, `${args.oldName}.txt`);
const newPath = path.join(PERSONA_DIR, `${args.newName}.txt`);
await fs.rename(oldPath, newPath);
return {
content: [{
type: 'text',
text: `페르소나 이름이 "${args.oldName}"에서 "${args.newName}"(으)로 변경되었습니다.`
}]
};
}
}
});
```
---
## 📞 문제 해결
### 일반적인 오류
#### 1. ENOENT: no such file or directory
**원인**: 페르소나 파일이 존재하지 않음
**해결**:
```bash
# 파일 확인
ls ~/.persona/
# 페르소나 재생성
# Claude Desktop에서: "professional 페르소나 만들어줘"
```
#### 2. EACCES: permission denied
**원인**: 파일 접근 권한 없음
**해결**:
```bash
# 디렉토리 권한 확인
ls -la ~/.persona/
# 권한 수정
chmod 700 ~/.persona/
chmod 600 ~/.persona/*.txt
```
#### 3. MCP 서버가 시작되지 않음
**원인**: Node.js 버전 또는 경로 오류
**해결**:
```bash
# Node.js 버전 확인
node --version # v18+ 필요
# 직접 실행 테스트
node C:\Users\sshin\Documents\persona-mcp\index.js
```
---
## 📚 참고 자료
- **MCP 공식 문서**: https://modelcontextprotocol.io/
- **MCP SDK**: https://github.com/modelcontextprotocol/sdk
- **Node.js fs/promises**: https://nodejs.org/api/fs.html#promises-api
- **JSON-RPC 2.0**: https://www.jsonrpc.org/specification
---
## 📝 변경 이력
### v1.0.0 (2025-11-01)
- 초기 릴리스
- 4개 도구 구현 (create, update, delete, list)
- MCP Resources 지원
- 잠수함 모드 아키텍처 구현
---
<div align="center">
**Persona MCP - 토큰을 아끼는 지능형 페르소나 관리**
[README](./README.md) • [설치 가이드](./INSTALL.md) • [빠른 시작](./QUICKSTART.md)
</div>