Skip to main content
Glama
doy00

TOEIC Speaking MCP Server

by doy00
README.md
# 🎯 TOEIC Speaking MCP Server

토읡 μŠ€ν”Όν‚Ή 만λŠ₯λ¬Έμž₯ μ•”κΈ° ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ MCP μ„œλ²„μž…λ‹ˆλ‹€. Claude Desktop μ•±κ³Ό μ—°λ™ν•˜μ—¬ μŒμ„±μœΌλ‘œ 토읡 μŠ€ν”Όν‚Ή λ¬Έμž₯을 ν•™μŠ΅ν•˜κ³  μ¦‰μ‹œ ν”Όλ“œλ°±μ„ 받을 수 μžˆμŠ΅λ‹ˆλ‹€.

**좜처**: [유튜브 μ‹œκ³„ν† λΌμ œλ‹ˆμŒ€](https://youtu.be/A14nJjAGqbY?si=T-7GGcWc9rilQd0G)

---

## πŸ“– λͺ©μ°¨

- [μ£Όμš” νŠΉμ§•](#-μ£Όμš”-νŠΉμ§•)
- [기술 μŠ€νƒ](#️-기술-μŠ€νƒ)
- [μ„€μΉ˜ 및 μ„€μ •](#-μ„€μΉ˜-및-μ„€μ •)
- [MCP 도ꡬ](#️-mcp-도ꡬ)
- [μ‚¬μš© μ˜ˆμ‹œ](#-μ‚¬μš©-μ˜ˆμ‹œ)
- [ν”„λ‘œμ νŠΈ ꡬ쑰](#-ν”„λ‘œμ νŠΈ-ꡬ쑰)
- [νŠΈλŸ¬λΈ”μŠˆνŒ…](#-νŠΈλŸ¬λΈ”μŠˆνŒ…)

---

## ✨ μ£Όμš” νŠΉμ§•

- 🎀 **μŒμ„± ν•™μŠ΅**: Claude Desktop μŒμ„± μΈμ‹μœΌλ‘œ μžμ—°μŠ€λŸ¬μš΄ ν•™μŠ΅
- 🧠 **μ μ‘ν˜• 좜제**: mastery_score 기반 μ·¨μ•½ λ¬Έμž₯ μš°μ„  좜제
- ⚑ **μ¦‰μ‹œ ν”Όλ“œλ°±**: ν‚€μ›Œλ“œ λ§€μΉ­ λΆ„μ„μœΌλ‘œ μ‹€μ‹œκ°„ ν•™μŠ΅ 효과 확인
- πŸ“Š **μžλ™ 점수 관리**: λ‹΅λ³€ 정확도에 λ”°λ₯Έ μžλ™ 점수 μ—…λ°μ΄νŠΈ (0-100)
- πŸ”’ **νƒ€μž… μ•ˆμ •μ„±**: TypeScript strict λͺ¨λ“œ + Zod μŠ€ν‚€λ§ˆ 검증

## πŸ—οΈ 기술 μŠ€νƒ

- **Framework**: NestJS 11 + TypeScript 5 (strict mode)
- **Protocol**: Model Context Protocol (MCP) SDK
- **Database**: Supabase PostgreSQL
- **Validation**: Zod schema validation
- **Architecture**: Domain-driven layered architecture

## πŸš€ μ„€μΉ˜ 및 μ„€μ •

### 1. μ˜μ‘΄μ„± μ„€μΉ˜

```bash
npm install
```

### 2. ν™˜κ²½ λ³€μˆ˜ μ„€μ •

`.env` 파일 확인:

```env
SUPABASE_URL=your_supabase_url
SUPABASE_ANON_KEY=your_supabase_anon_key
```

### 3. λ°μ΄ν„°λ² μ΄μŠ€ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜

Supabase SQL Editorμ—μ„œ `migrate.sql` μ‹€ν–‰:

```sql
-- mastery_score, last_reviewed_at, review_count 컬럼 μΆ”κ°€
-- 인덱슀 생성
```

### 4. μƒ˜ν”Œ 데이터 μ‚½μž… (선택 사항)

```bash
node seed.js
```

### 5. λΉŒλ“œ

```bash
npm run build
```

### 6. Claude Desktop μ„€μ •

`~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "toeic-speaking": {
      "command": "node",
      "args": ["/μ ˆλŒ€/경둜/dist/main.js"],
      "env": {
        "SUPABASE_URL": "your_url",
        "SUPABASE_ANON_KEY": "your_key"
      }
    }
  }
}
```

⚠️ 경둜λ₯Ό μ‹€μ œ ν”„λ‘œμ νŠΈ 경둜둜 μˆ˜μ • ν›„ Claude Desktop μž¬μ‹œμž‘

---

## πŸ› οΈ MCP 도ꡬ

### 1. `get_quiz_sentence` - 문제 좜제

**νŒŒλΌλ―Έν„°**:
- `mode` (선택): `'weak_first'` | `'random'` (κΈ°λ³Έ: `'weak_first'`)
- `part` (선택): 파트 번호 ν•„ν„°

**응닡**:
```json
{
  "id": "uuid",
  "sentence_ko": "이 사진은 κ³΅μ›μ—μ„œ 찍힌 μ‚¬μ§„μž…λ‹ˆλ‹€.",
  "part": 2,
  "current_mastery": 0
}
```

### 2. `verify_answer` - λ‹΅λ³€ 검증

**νŒŒλΌλ―Έν„°** (ν•„μˆ˜):
- `sentence_id`: λ¬Έμž₯ ID
- `user_answer`: μ‚¬μš©μž λ‹΅λ³€ (μ˜μ–΄ λ¬Έμž₯)

**응닡**:
```json
{
  "success": true,
  "original_sentence": "This is a picture taken at a park.",
  "matched_keywords": ["picture", "taken", "park"],
  "missing_keywords": [],
  "match_rate": "100.0%",
  "score_change": 10,
  "feedback": "Perfect! All keywords matched. Score increased by 10 points."
}
```

**점수 κ·œμΉ™**:
| λ§€μΉ­λ₯  | 점수 λ³€ν™” |
|--------|-----------|
| 100% | +10 |
| 70-99% | +5 |
| 50-69% | 0 |
| 0-49% | -5 |

---

## πŸ’¬ μ‚¬μš© μ˜ˆμ‹œ

```
πŸ‘€ "토읡 μŠ€ν”Όν‚Ή μ—°μŠ΅ μ‹œμž‘ν• κ²Œμš”"

πŸ€– [get_quiz_sentence 호좜]
   문제: "이 사진은 κ³΅μ›μ—μ„œ 찍힌 μ‚¬μ§„μž…λ‹ˆλ‹€."
   (ν˜„μž¬ μˆ™λ ¨λ„: 0점)

πŸ‘€ [μŒμ„±] "This is a picture taken at a park"

πŸ€– [verify_answer 호좜]
   βœ… μ™„λ²½ν•©λ‹ˆλ‹€!
   - ν¬ν•¨λœ ν‚€μ›Œλ“œ: picture, taken, park (3/3)
   - λ§€μΉ­λ₯ : 100.0%
   - 점수 λ³€ν™”: +10점
```

---

## πŸ“ ν”„λ‘œμ νŠΈ ꡬ쑰

```
src/
β”œβ”€β”€ main.ts                    # MCP μ„œλ²„ μ—”νŠΈλ¦¬ν¬μΈνŠΈ
β”œβ”€β”€ app.module.ts              # 루트 λͺ¨λ“ˆ
β”œβ”€β”€ config/
β”‚   └── supabase.config.ts     # Supabase DI Provider
β”œβ”€β”€ types/
β”‚   └── sentence.interface.ts  # TypeScript μΈν„°νŽ˜μ΄μŠ€
β”œβ”€β”€ mcp/
β”‚   β”œβ”€β”€ mcp.module.ts
β”‚   └── mcp.service.ts         # MCP 도ꡬ μ •μ˜ + Zod 검증
β”œβ”€β”€ quiz/                      # Quiz 도메인
β”‚   β”œβ”€β”€ quiz.module.ts
β”‚   β”œβ”€β”€ quiz.service.ts        # 문제 좜제 둜직
β”‚   └── quiz.repository.ts     # DB 쿼리
└── answer/                    # Answer 도메인
    β”œβ”€β”€ answer.module.ts
    β”œβ”€β”€ answer.service.ts      # ν‚€μ›Œλ“œ λ§€μΉ­ μ•Œκ³ λ¦¬μ¦˜
    └── answer.repository.ts   # 점수 μ—…λ°μ΄νŠΈ
```

**μ•„ν‚€ν…μ²˜**:
```
Claude Desktop (stdio)
    ↓
MCP Layer (Zod 검증)
    ↓
Domain Layer (Quiz/Answer)
    ↓
Supabase PostgreSQL
```

---

## πŸ—„οΈ λ°μ΄ν„°λ² μ΄μŠ€ μŠ€ν‚€λ§ˆ

| 컬럼 | νƒ€μž… | μ„€λͺ… |
|------|------|------|
| `id` | uuid | PK |
| `part` | integer | TOEIC 파트 번호 |
| `sentence_en` | text | μ˜μ–΄ 원문 (μ •λ‹΅) |
| `sentence_ko` | text | ν•œκ΅­μ–΄ λ²ˆμ—­ (문제) |
| `keywords` | text[] | 핡심 ν‚€μ›Œλ“œ λ°°μ—΄ |
| `mastery_score` | integer | ν•™μŠ΅ μˆ™λ ¨λ„ (0-100) |
| `last_reviewed_at` | timestamptz | λ§ˆμ§€λ§‰ 볡슡 μ‹œκ° |
| `review_count` | integer | 총 볡슡 횟수 |

**인덱슀**:
- `idx_mastery_score`: mastery_score
- `idx_part_mastery`: (part, mastery_score)

---

## πŸ”§ νŠΈλŸ¬λΈ”μŠˆνŒ…

### MCP μ„œλ²„κ°€ 보이지 μ•ŠλŠ” 경우

1. λΉŒλ“œ 확인: `npm run build`
2. 파일 확인: `ls dist/main.js`
3. μˆ˜λ™ μ‹€ν–‰: `node dist/main.js`
4. Claude Desktop 둜그 확인: `View > Toggle Developer Tools > Console`
5. Claude Desktop μ™„μ „νžˆ μž¬μ‹œμž‘

### λ°μ΄ν„°λ² μ΄μŠ€ μ—°κ²° 였λ₯˜

1. `claude_desktop_config.json`의 `env` μ„Ήμ…˜ 확인
2. stdio ν™˜κ²½μ—μ„œλŠ” `.env` 파일 λŒ€μ‹  μ„€μ • νŒŒμΌμ— ν™˜κ²½ λ³€μˆ˜ ν•„μˆ˜
3. Supabase ν”„λ‘œμ νŠΈ ν™œμ„± μƒνƒœ 확인
4. `migrate.sql` μ‹€ν–‰ 확인

### νƒ€μž… μ—λŸ¬

```bash
rm -rf node_modules package-lock.json
npm install
npm run build
```

---

## πŸ› οΈ 개발 λͺ…λ Ήμ–΄

```bash
# λΉŒλ“œ
npm run build

# 개발 λͺ¨λ“œ
npm run start:dev

# μ‹€ν–‰
npm start

# μƒ˜ν”Œ 데이터
node seed.js

# νƒ€μž… 체크
npx tsc --noEmit
```

---

## πŸŽ“ ν•™μŠ΅ 팁

1. **맀일 10-15λΆ„** κΎΈμ€€νžˆ μ—°μŠ΅
2. **weak_first λͺ¨λ“œ** ν™œμš©μœΌλ‘œ μ·¨μ•½ λ¬Έμž₯ 집쀑 곡랡
3. **ν‚€μ›Œλ“œ 쀑심** ν•™μŠ΅ (전체 λ¬Έμž₯보닀 핡심 ν‚€μ›Œλ“œ λ¨Όμ € μ•”κΈ°)
4. **μŒμ„± μž…λ ₯** μ‚¬μš©μœΌλ‘œ 발음 μ—°μŠ΅ 병행
5. 점수 80점 이상 되면 μžλ™μœΌλ‘œ λ‹€λ₯Έ λ¬Έμž₯ 좜제

---

## πŸš€ ν–₯ν›„ κ³„νš

- [ ] 187개 전체 λ¬Έμž₯ 데이터 μΆ”κ°€
- [ ] Part 3, 4, 5 지원
- [ ] ν•™μŠ΅ 톡계 λŒ€μ‹œλ³΄λ“œ
- [ ] μ‚¬μš©μžλ³„ ν•™μŠ΅ 기둝
- [ ] 발음 평가 API 연동

---

## πŸ“š μ°Έκ³  자료

- [MCP 곡식 λ¬Έμ„œ](https://modelcontextprotocol.io/)
- [NestJS 곡식 λ¬Έμ„œ](https://docs.nestjs.com/)
- [Supabase λ¬Έμ„œ](https://supabase.com/docs)

---

## πŸ“„ λΌμ΄μ„ μŠ€

ISC

---

**Version**: 1.0.0 | **Last Updated**: 2026-03-15

TDQS

A3.7/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct roles: one generates a quiz question, the other validates the user's answer. There is no functional overlap between them.

Naming Consistency5/5

Both tool names follow a consistent verb_noun pattern: 'get_quiz_sentence' and 'verify_answer'. This predictable naming makes the tool set easy to navigate.

Tool Count3/5

With only 2 tools, the server is on the thin side, but the narrow quiz-taking purpose makes this count borderline acceptable. It covers the essential actions without being bloated.

Completeness4/5

The tools form a complete core workflow: retrieve a question and verify a response. Minor gaps exist, such as no explicit score retrieval or session management, but the primary quiz loop is fully covered.

Maintenance

ActivityInactive
ResponsivenessNo issues