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>