@sophia-vibelog/mcp-server 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -6
- package/dist/index.js +97 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -22,11 +22,13 @@ Sophia 웹 대시보드 → 설정 → API 키 관리에서 새 키를 생성합
|
|
|
22
22
|
```json
|
|
23
23
|
{
|
|
24
24
|
"mcpServers": {
|
|
25
|
-
"
|
|
26
|
-
"command": "
|
|
25
|
+
"sophia": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": ["@sophia-vibelog/mcp-server"],
|
|
27
28
|
"env": {
|
|
28
|
-
"
|
|
29
|
-
"
|
|
29
|
+
"SOPHIA_API_KEY": "your-api-key-here",
|
|
30
|
+
"SOPHIA_API_URL": "https://sophia-vibelog.site",
|
|
31
|
+
"ANTHROPIC_API_KEY": "your-anthropic-api-key"
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
}
|
|
@@ -37,8 +39,9 @@ Sophia 웹 대시보드 → 설정 → API 키 관리에서 새 키를 생성합
|
|
|
37
39
|
|
|
38
40
|
| 변수 | 필수 | 기본값 | 설명 |
|
|
39
41
|
|------|------|--------|------|
|
|
40
|
-
| `
|
|
41
|
-
| `
|
|
42
|
+
| `SOPHIA_API_KEY` | O | - | Sophia에서 발급받은 API 키 |
|
|
43
|
+
| `SOPHIA_API_URL` | X | `http://localhost:3000` | Sophia 서버 URL |
|
|
44
|
+
| `ANTHROPIC_API_KEY` | △ | - | Claude API 키 (rate-prompt 사용 시 필요) |
|
|
42
45
|
|
|
43
46
|
## 사용법
|
|
44
47
|
|
|
@@ -60,6 +63,44 @@ AI 코딩 세션 로그를 Sophia에 발행합니다.
|
|
|
60
63
|
- `title` (선택) — 로그 제목
|
|
61
64
|
- `projectId` (선택) — 프로젝트 ID
|
|
62
65
|
|
|
66
|
+
#### `rate-prompt`
|
|
67
|
+
|
|
68
|
+
사용자 질문의 품질을 평가하고 개선 방향을 제안합니다.
|
|
69
|
+
|
|
70
|
+
**사용법:**
|
|
71
|
+
|
|
72
|
+
질문 끝에 `@@`를 붙이면 소피아가 질문 코칭을 제공합니다:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
사용자: "에러가 난다@@"
|
|
76
|
+
|
|
77
|
+
→ Claude의 답변
|
|
78
|
+
...
|
|
79
|
+
━━━━━━━━━━━━━━━━━━━━━━━
|
|
80
|
+
💬 소피아의 질문 코칭
|
|
81
|
+
|
|
82
|
+
좀 더 구체적으로 말씀해주시면
|
|
83
|
+
훨씬 정확한 답변을 드릴 수 있어요!
|
|
84
|
+
|
|
85
|
+
🎯 이 정보가 있으면 완벽해요
|
|
86
|
+
• 어느 페이지/기능에서 발생했나요?
|
|
87
|
+
• 어떤 에러 메시지가 보이나요?
|
|
88
|
+
|
|
89
|
+
✨ 예를 들면 이렇게요
|
|
90
|
+
"○○ 페이지에서 △△ 버튼을 눌렀을 때
|
|
91
|
+
'Type error: ...' 에러가 발생해요"
|
|
92
|
+
━━━━━━━━━━━━━━━━━━━━━━━
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**매개변수:**
|
|
96
|
+
- `userMessage` (필수) — 평가할 사용자 메시지 (`@@`는 제거된 상태)
|
|
97
|
+
- `conversationContext` (선택) — 대화 맥락
|
|
98
|
+
|
|
99
|
+
**특징:**
|
|
100
|
+
- 👓 `@@` = 안경 쓰고 자세히 보기
|
|
101
|
+
- 💬 격려 중심 코칭 (점수/비판 없음)
|
|
102
|
+
- 📍 답변 맨 마지막에 표시 (긴 스크롤 고려)
|
|
103
|
+
|
|
63
104
|
## 개발
|
|
64
105
|
|
|
65
106
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
5
6
|
const SOPHIA_API_URL = process.env.SOPHIA_API_URL || "http://localhost:3000";
|
|
6
7
|
const SOPHIA_API_KEY = process.env.SOPHIA_API_KEY || "";
|
|
8
|
+
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || "";
|
|
9
|
+
const anthropic = ANTHROPIC_API_KEY
|
|
10
|
+
? new Anthropic({ apiKey: ANTHROPIC_API_KEY })
|
|
11
|
+
: null;
|
|
7
12
|
const server = new McpServer({
|
|
8
13
|
name: "sophia-mcp",
|
|
9
14
|
version: "0.1.0",
|
|
@@ -74,6 +79,98 @@ server.tool("publish-log", "VibeLog에 AI 코딩 세션 로그를 발행합니
|
|
|
74
79
|
};
|
|
75
80
|
}
|
|
76
81
|
});
|
|
82
|
+
server.tool("rate-prompt", "사용자의 질문 품질을 평가하고 개선 제안을 제공합니다. 질문 끝에 @@가 붙어있을 때만 사용하세요.", {
|
|
83
|
+
userMessage: z.string().describe("평가할 사용자 메시지 (@@는 제거된 상태)"),
|
|
84
|
+
conversationContext: z
|
|
85
|
+
.string()
|
|
86
|
+
.optional()
|
|
87
|
+
.describe("대화 맥락 (선택사항)"),
|
|
88
|
+
}, async ({ userMessage, conversationContext }) => {
|
|
89
|
+
if (!anthropic) {
|
|
90
|
+
return {
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: "text",
|
|
94
|
+
text: "ANTHROPIC_API_KEY가 설정되지 않았습니다. 환경변수에 API 키를 설정해주세요.",
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
isError: true,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const prompt = `당신은 '소피아'로, 사용자의 질문을 더 나아지도록 돕는 친절한 코치입니다.
|
|
102
|
+
|
|
103
|
+
사용자의 질문을 분석하고, 격려하면서 개선 포인트를 제안해주세요.
|
|
104
|
+
절대 점수를 매기거나 비판하지 마세요. 파트너처럼 함께 더 나은 질문을 만들어가는 느낌으로.
|
|
105
|
+
|
|
106
|
+
평가 기준:
|
|
107
|
+
- 위치: 어디서 발생했는지 명확한가?
|
|
108
|
+
- 동작: 무엇을 했는지 명확한가?
|
|
109
|
+
- 증상: 무슨 일이 일어났는지 명확한가?
|
|
110
|
+
- 에러 메시지: 구체적인 에러가 있는가?
|
|
111
|
+
- 예상 vs 실제: 원래 어떻게 되어야 하는지 설명했는가?
|
|
112
|
+
|
|
113
|
+
사용자 질문:
|
|
114
|
+
"${userMessage}"
|
|
115
|
+
|
|
116
|
+
${conversationContext ? `대화 맥락:\n${conversationContext}` : ""}
|
|
117
|
+
|
|
118
|
+
출력 형식 (반드시 JSON):
|
|
119
|
+
{
|
|
120
|
+
"encouragement": "격려 메시지 (예: '좀 더 구체적으로 말씀해주시면 훨씬 정확한 답변을 드릴 수 있어요!')",
|
|
121
|
+
"strengths": ["이미 좋은 점1", "이미 좋은 점2"] (없으면 빈 배열),
|
|
122
|
+
"improvements": ["필요한 정보1", "필요한 정보2"] (예: "어느 페이지/기능에서 발생했나요?"),
|
|
123
|
+
"example": "구체적인 질문 예시 (한 문장)"
|
|
124
|
+
}`;
|
|
125
|
+
const response = await anthropic.messages.create({
|
|
126
|
+
model: "claude-3-5-sonnet-20241022",
|
|
127
|
+
max_tokens: 1024,
|
|
128
|
+
messages: [{ role: "user", content: prompt }],
|
|
129
|
+
});
|
|
130
|
+
const textContent = response.content.find((c) => c.type === "text");
|
|
131
|
+
if (!textContent || textContent.type !== "text") {
|
|
132
|
+
throw new Error("No text content in response");
|
|
133
|
+
}
|
|
134
|
+
const result = JSON.parse(textContent.text);
|
|
135
|
+
// 피드백 포맷팅
|
|
136
|
+
let feedback = `\n━━━━━━━━━━━━━━━━━━━━━━━\n`;
|
|
137
|
+
feedback += `💬 소피아의 질문 코칭\n\n`;
|
|
138
|
+
feedback += `${result.encouragement}\n`;
|
|
139
|
+
if (result.strengths.length > 0) {
|
|
140
|
+
feedback += `\n✨ 이미 좋은 점 / 이 질문이 좋은 이유\n`;
|
|
141
|
+
result.strengths.forEach((s) => {
|
|
142
|
+
feedback += ` • ${s}\n`;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
if (result.improvements.length > 0) {
|
|
146
|
+
const header = result.strengths.length > 0
|
|
147
|
+
? `\n💡 한 가지만 더하면 완벽\n`
|
|
148
|
+
: `\n🎯 이것만 더 알려주세요\n`;
|
|
149
|
+
feedback += header;
|
|
150
|
+
result.improvements.forEach((i) => {
|
|
151
|
+
feedback += ` • ${i}\n`;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (result.example) {
|
|
155
|
+
feedback += `\n✨ 예를 들면 이렇게요\n "${result.example}"\n`;
|
|
156
|
+
}
|
|
157
|
+
feedback += `\n━━━━━━━━━━━━━━━━━━━━━━━\n`;
|
|
158
|
+
return {
|
|
159
|
+
content: [{ type: "text", text: feedback }],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
return {
|
|
164
|
+
content: [
|
|
165
|
+
{
|
|
166
|
+
type: "text",
|
|
167
|
+
text: `프롬프트 평가 실패: ${e instanceof Error ? e.message : "알 수 없는 오류"}`,
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
isError: true,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
});
|
|
77
174
|
async function main() {
|
|
78
175
|
const transport = new StdioServerTransport();
|
|
79
176
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sophia-vibelog/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Sophia (VibeLog) MCP Server — Claude Code에서 AI 코딩 세션 로그를 자동 발행합니다",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"lint": "echo 'no lint configured'"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@anthropic-ai/sdk": "^0.74.0",
|
|
33
34
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
34
35
|
"zod": "^4.3.6"
|
|
35
36
|
},
|