Skip to main content
Glama

Persona MCP

by seanshin0214
TECHNICAL_SPEC.md19.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>

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/seanshin0214/persona-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server