Skip to main content
Glama
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>

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