Skip to main content
Glama
gittgi
by gittgi
README.md
# ytm-runlist-mcp

Codex, Claude Code 같은 MCP 클라이언트에서 YouTube Music 플레이리스트를 러닝용으로 재배치하기 위한 로컬 MCP 서버입니다.

LLM이 곡 제목, 아티스트, 길이, 기존 순서를 보고 러닝 흐름을 판단하고, 이 서버는 YouTube Data API를 통해 실제 플레이리스트 조회/검증/생성을 담당합니다.

## 할 수 있는 일

- Google OAuth 로컬 로그인
- YouTube / YouTube Music 플레이리스트 목록 조회
- 선택한 플레이리스트 곡 목록 조회
- 러닝 페이스 전략 객관식 옵션 제공
- LLM이 만든 재배치 순서 검증
- 원본 플레이리스트 순서 변경
- 더 안전한 새 플레이리스트 복사본 생성

## 안전 원칙

- YouTube Music 비공식 스크래핑을 하지 않습니다.
- 음원을 다운로드하거나 스트리밍 오디오를 분석하지 않습니다.
- 캐시는 없습니다.
- 저장되는 개인 파일은 Google OAuth client secret과 token뿐입니다.
- 원본 플레이리스트 변경 tool은 기본값이 `dry_run=true`입니다.
- 실제 원본 변경은 `dry_run=false`와 `confirm_modify_original=true`가 모두 필요합니다.
- 기본 추천 흐름은 원본 수정이 아니라 새 비공개 플레이리스트 복사본 생성입니다.

## 프로젝트 구조

```text
src/ytm_runlist_mcp/     MCP 서버와 YouTube API 코드
skills/                  선택형 Agent Skill 문서
tests/                   단위 테스트
.runlist/                로컬 OAuth 파일, git ignore 대상
```

## 준비물

- Python 3.11 이상
- YouTube / YouTube Music 플레이리스트가 있는 Google 계정
- Google Cloud 프로젝트
- YouTube Data API v3
- Codex, Claude Code, 또는 MCP 호환 클라이언트

## 1. Google Cloud Console 설정

### 1.1 프로젝트 만들기

1. Google Cloud Console을 엽니다: https://console.cloud.google.com/
2. 상단 프로젝트 선택 드롭다운을 클릭합니다.
3. `New Project`를 클릭합니다.
4. 프로젝트 이름을 입력합니다.

예시:

```text
YTM Runlist MCP
```

생성 후 해당 프로젝트가 선택되어 있는지 확인합니다.

### 1.2 YouTube Data API v3 활성화

1. `APIs & Services` -> `Library`로 이동합니다.
2. 검색창에 입력합니다.

```text
YouTube Data API v3
```

3. `Enable`을 클릭합니다.

YouTube Data API는 비공개 사용자 데이터 접근에 OAuth 2.0을 사용합니다. 또한 YouTube 계정에는 service account 방식이 맞지 않으므로, 이 프로젝트는 desktop installed app OAuth 흐름을 사용합니다.

### 1.3 OAuth 동의 화면 설정

Google Cloud UI에 따라 메뉴 이름이 조금 다를 수 있습니다.

새 UI:

```text
Google Auth platform
```

예전 UI:

```text
APIs & Services -> OAuth consent screen
```

설정:

```text
App name: YTM Runlist MCP
User support email: 본인 이메일
Developer contact email: 본인 이메일
Audience / User type: External
```

개인용으로 쓸 때는 테스트 모드로 두면 됩니다.

### 1.4 Test user 추가

테스트 모드라면 YouTube Music을 쓰는 본인 Google 계정을 test user에 추가합니다.

```text
Google Auth platform -> Audience -> Test users
```

### 1.5 Scope 추가

`Data Access`에서 아래 scope를 추가합니다.

```text
https://www.googleapis.com/auth/youtube.force-ssl
```

이 scope는 플레이리스트 조회, 생성, 항목 추가, 순서 변경을 위해 사용합니다.

### 1.6 Desktop OAuth Client 생성

```text
Google Auth platform -> Clients -> Create client
```

또는:

```text
APIs & Services -> Credentials -> Create Credentials -> OAuth client ID
```

설정:

```text
Application type: Desktop app
Name: YTM Runlist MCP Desktop
```

생성 후 JSON 파일을 다운로드합니다.

파일 이름은 보통 이런 형태입니다.

```text
client_secret_1234567890-abcdef.apps.googleusercontent.com.json
```

## 2. macOS 설치

저장소를 받습니다.

```bash
git clone https://github.com/YOUR_USERNAME/ytm-runlist-mcp.git
cd ytm-runlist-mcp
```

가상환경을 만들고 설치합니다.

```bash
python3 -m venv .venv
. .venv/bin/activate
pip install -e ".[dev]"
```

Google Cloud에서 받은 OAuth JSON을 복사합니다.

```bash
mkdir -p .runlist
cp ~/Downloads/client_secret_*.json .runlist/client_secret.json
```

Google 계정 로그인을 실행합니다.

```bash
ytm-runlist-auth login
ytm-runlist-auth status
```

성공하면 대략 이렇게 보입니다.

```json
{
  "client_secrets_exists": true,
  "token_exists": true,
  "valid_or_refreshable": true
}
```

## 3. Windows PowerShell 설치

저장소를 받습니다.

```powershell
git clone https://github.com/YOUR_USERNAME/ytm-runlist-mcp.git
cd ytm-runlist-mcp
```

가상환경을 만들고 설치합니다.

```powershell
py -3 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]"
```

PowerShell이 스크립트 실행을 막으면 아래 명령을 한 번 실행합니다.

```powershell
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
```

다시 활성화합니다.

```powershell
.\.venv\Scripts\Activate.ps1
```

Google Cloud에서 받은 OAuth JSON을 복사합니다.

```powershell
New-Item -ItemType Directory -Force .runlist
Copy-Item "$env:USERPROFILE\Downloads\client_secret_*.json" ".runlist\client_secret.json"
```

Google 계정 로그인을 실행합니다.

```powershell
ytm-runlist-auth login
ytm-runlist-auth status
```

## 4. Codex에 MCP 등록

Codex 설정 파일에 MCP 서버를 추가합니다.

설정 파일:

```text
~/.codex/config.toml
```

macOS 예시:

```toml
[mcp_servers.ytm-runlist]
command = "/ABSOLUTE/PATH/TO/ytm-runlist-mcp/.venv/bin/ytm-runlist-mcp"

[mcp_servers.ytm-runlist.env]
YTM_RUNLIST_DATA_DIR = "/ABSOLUTE/PATH/TO/ytm-runlist-mcp/.runlist"
GOOGLE_CLIENT_SECRETS_FILE = "/ABSOLUTE/PATH/TO/ytm-runlist-mcp/.runlist/client_secret.json"
YTM_RUNLIST_GOOGLE_TOKEN_FILE = "/ABSOLUTE/PATH/TO/ytm-runlist-mcp/.runlist/google-token.json"
```

Windows 예시:

```toml
[mcp_servers.ytm-runlist]
command = "C:\\ABSOLUTE\\PATH\\TO\\ytm-runlist-mcp\\.venv\\Scripts\\ytm-runlist-mcp.exe"

[mcp_servers.ytm-runlist.env]
YTM_RUNLIST_DATA_DIR = "C:\\ABSOLUTE\\PATH\\TO\\ytm-runlist-mcp\\.runlist"
GOOGLE_CLIENT_SECRETS_FILE = "C:\\ABSOLUTE\\PATH\\TO\\ytm-runlist-mcp\\.runlist\\client_secret.json"
YTM_RUNLIST_GOOGLE_TOKEN_FILE = "C:\\ABSOLUTE\\PATH\\TO\\ytm-runlist-mcp\\.runlist\\google-token.json"
```

Codex를 새로 열거나 새 세션을 시작합니다.

확인:

```bash
codex mcp list
```

## 5. Claude Code에 MCP 등록

Claude Code도 같은 MCP 서버를 사용할 수 있습니다. 서버를 따로 만들 필요는 없습니다.

macOS:

```bash
claude mcp add ytm-runlist \
  --env YTM_RUNLIST_DATA_DIR=/ABSOLUTE/PATH/TO/ytm-runlist-mcp/.runlist \
  --env GOOGLE_CLIENT_SECRETS_FILE=/ABSOLUTE/PATH/TO/ytm-runlist-mcp/.runlist/client_secret.json \
  --env YTM_RUNLIST_GOOGLE_TOKEN_FILE=/ABSOLUTE/PATH/TO/ytm-runlist-mcp/.runlist/google-token.json \
  -- /ABSOLUTE/PATH/TO/ytm-runlist-mcp/.venv/bin/ytm-runlist-mcp
```

Windows PowerShell:

```powershell
claude mcp add ytm-runlist `
  --env YTM_RUNLIST_DATA_DIR="C:\ABSOLUTE\PATH\TO\ytm-runlist-mcp\.runlist" `
  --env GOOGLE_CLIENT_SECRETS_FILE="C:\ABSOLUTE\PATH\TO\ytm-runlist-mcp\.runlist\client_secret.json" `
  --env YTM_RUNLIST_GOOGLE_TOKEN_FILE="C:\ABSOLUTE\PATH\TO\ytm-runlist-mcp\.runlist\google-token.json" `
  -- "C:\ABSOLUTE\PATH\TO\ytm-runlist-mcp\.venv\Scripts\ytm-runlist-mcp.exe"
```

Claude Code는 MCP server scope를 지원합니다. 여러 프로젝트에서 쓰려면 `--scope user`, 팀과 공유하려면 project scope를 검토하세요.

## 6. 선택형 Skill

MCP 서버는 Skill 없이도 동작합니다.

다만 Skill을 쓰면 LLM이 더 일관된 순서로 작업합니다.

포함된 Skill:

```text
skills/runlist-youtube-music/SKILL.md
skills/claude-code/runlist-youtube-music/SKILL.md
```

Skill의 역할:

1. 플레이리스트 목록 조회
2. 사용자에게 대상 선택 요청
3. 곡 목록 조회
4. 러닝 전략과 거리/시간 질문
5. 재배치 순서 검증
6. 쓰기 전 미리보기
7. 원본 수정 전 명시 확인
8. 기본적으로 새 비공개 복사본 생성 권장

## 7. 추천 프롬프트

Codex 또는 Claude Code에 그대로 붙여넣을 수 있습니다.

```text
ytm-runlist MCP로 내 YouTube Music 플레이리스트를 러닝용으로 재배치해줘.

먼저 플레이리스트 목록을 보여주고, 내가 고르면 곡 목록을 확인해줘.
그다음 러닝 전략을 객관식으로 물어보고, 거리/목표 시간도 물어봐줘.

원본은 수정하지 말고, 재배치 미리보기 후 새 비공개 플레이리스트 복사본으로 만들어줘.
조회된 곡만 사용하고 playlist_item_id를 임의로 만들지 마.
```

## 8. MCP Tools

이 서버가 제공하는 tool:

```text
health
get_running_strategy_options_tool
list_youtube_music_playlists
get_playlist_tracks_tool
validate_reorder_plan
reorder_original_playlist
create_reordered_playlist_copy_tool
```

## 9. 개발과 테스트

테스트 실행:

```bash
pytest
```

MCP 서버 직접 실행:

```bash
python -m ytm_runlist_mcp.server
```

stdio MCP 서버라서 터미널이 가만히 대기하는 것이 정상입니다.

## 10. YouTube Data API quota

YouTube Data API quota는 돈이 아니라 하루 API 사용량 제한입니다.

Google 공식 문서 기준으로 YouTube Data API를 활성화한 프로젝트는 기본적으로 `search.list` 100회/일, `videos.insert` 100회/일, 그 외 endpoint 합산 `10,000 units/day`를 받습니다. 이 프로젝트는 검색이나 영상 업로드를 쓰지 않고, 플레이리스트 조회/생성/항목 추가/순서 변경을 씁니다.

관련 quota cost 예시:

```text
playlists.list       1 unit
playlistItems.list   1 unit
playlists.insert    50 units
playlistItems.insert 50 units
playlistItems.update 50 units
```

큰 플레이리스트를 자주 원본 재정렬하면 `playlistItems.update`가 곡 수만큼 호출되어 quota를 빨리 쓸 수 있습니다. quota를 다 쓰면 과금되는 것이 아니라 그날 더 이상 API 호출이 안 되고, 필요하면 YouTube API audit을 거쳐 quota 증설을 요청해야 합니다.

## 11. GitHub에 올리기 전 주의

아래 파일은 절대 커밋하지 마세요.

```text
.runlist/
client_secret*.json
google-token.json
.env
```

현재 `.gitignore`에 포함되어 있습니다.

확인:

```bash
git status --ignored
```

## 12. 현재 한계

- YouTube Music 전용 공개 API가 아니라 YouTube Data API를 사용합니다.
- YouTube Music 플레이리스트가 YouTube Data API에서 보이는지 각자 계정으로 확인해야 합니다.
- 원본 플레이리스트 순서 변경은 `playlistItems.update`를 사용합니다.
- 플레이리스트가 수동 정렬 상태가 아니면 YouTube API가 순서 변경을 거부할 수 있습니다.
- 큰 플레이리스트는 dry-run으로 update 수를 먼저 확인하는 것이 좋습니다.

## 공식 문서

- Google OAuth consent setup: https://developers.google.com/workspace/guides/configure-oauth-consent
- YouTube Data API OAuth for installed apps: https://developers.google.com/youtube/v3/guides/auth/installed-apps
- YouTube Data API authentication: https://developers.google.com/youtube/v3/guides/authentication
- YouTube playlist item update: https://developers.google.com/youtube/v3/docs/playlistItems/update
- Codex MCP: https://developers.openai.com/codex/mcp
- Claude Code MCP: https://code.claude.com/docs/en/mcp
- Claude Code MCP quickstart: https://code.claude.com/docs/en/mcp-quickstart
- Claude Code skills: https://code.claude.com/docs/en/skills

TDQS

A3.7/5.0

Scored across 7 tools

Disambiguation5/5

Each tool has a distinct purpose: creating a copy, fetching tracks, providing running strategy options, health check, listing playlists, reordering in-place, and validating a reorder plan. No two tools overlap in functionality.

Naming Consistency2/5

Tool names are inconsistent: some end with '_tool', some don't ('health' is a single word), and verb phrases vary ('list_youtube_music_playlists' vs 'reorder_original_playlist'). No uniform pattern.

Tool Count5/5

With 7 tools, the server is well-scoped for its domain of YouTube Music playlist reordering and running strategy integration. Each tool feels necessary and the count is within the ideal range.

Completeness5/5

The tool set covers key operations: list playlists, get tracks, get running strategy options, validate a plan, reorder a playlist, and create a copy. No obvious gaps for the runlist management purpose.

Maintenance

ActivitySlowing
ResponsivenessNo issues