실습 가이드를 따라했는데… 문제가 생겼어요 😅
지난 포스팅에서 MCP 실습 가이드를 작성했어요. 이론적으로는 완벽해 보였지만, 실제로 따라 해보니 예상치 못한 문제들이 하나씩 나타났어요.
오늘은 실습 과정에서 겪은 4가지 트러블슈팅과 해결 과정을 정리할 거예요. 가이드만 봐서는 알 수 없는 실제 경험을 공유해요!
실습 환경 정보
하드웨어 & OS
- CPU: Apple Silicon (aarch64-apple-darwin)
- OS: macOS
- Shell: zsh (Mac 기본)
소프트웨어 버전
- Python: 3.14.2 (Homebrew)
- UV: 0.9.17 (2b5d65e61 2025-12-09)
- SQLite: 3.39.4 (2022-09-07)
- Claude Desktop: 최신 버전
Issue 1: UV 설치는 됐는데 명령어를 못 찾아요 🚨
문제 상황
UV 설치 스크립트를 실행했어요:
1
2
3
4
5
6
7
8
9
10
$ curl -LsSf https://astral.sh/uv/install.sh | sh
downloading uv 0.9.17 aarch64-apple-darwin
no checksums to verify
installing to /Users/username/.local/bin
uv
uvx
everything's installed!
sh: line 1463: /Users/username/.bash_profile: Permission denied
sh: line 1464: /Users/username/.bash_profile: Permission denied
설치는 성공했지만, uvx 명령어를 실행하면:
1
2
$ uvx --version
zsh: command not found: uvx
개발자 비유:
1
2
3
4
5
6
7
8
// 라이브러리는 설치됐지만 (UV 바이너리 설치 완료)
jar installed: ✅
// 클래스패스에 등록 안 됨 (PATH 미등록)
CLASSPATH not configured: ❌
// 결과: import 불가
import com.uv.tool; // ❌ Cannot find symbol
원인 분석
- UV 설치 자체는 성공:
uv,uvx가/Users/username/.local/bin에 정상 설치됨 - PATH 자동 등록 실패:
.bash_profile파일에 대한 쓰기 권한이 없어서 설치 스크립트가 PATH를 자동으로 추가하지 못함 - Mac은 zsh가 기본:
.bash_profile이 아니라.zshrc를 수정해야 해요
해결 방법
방법 1: 수동으로 PATH 추가 (임시)
1
2
3
4
5
6
# zsh 사용자 (Mac 기본 쉘)
source $HOME/.local/bin/env
# 확인
uvx --version
# uvx 0.9.17 (2b5d65e61 2025-12-09)
방법 2: 쉘 설정 파일에 영구 등록 (권장)
1
2
3
4
5
6
7
8
# .zshrc에 PATH 추가
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
# 설정 적용
source ~/.zshrc
# 확인
uvx --version
방법 3: .bash_profile 권한 문제 해결 (근본 원인 해결)
1
2
3
4
5
6
7
8
9
10
11
12
# 1. 현재 권한 확인
ls -la ~/.bash_profile
# -r--r--r-- (읽기 전용) ← 문제!
# 2. 권한 수정
chmod 644 ~/.bash_profile
# 또는
chmod u+w ~/.bash_profile
# 3. 권한 확인
ls -la ~/.bash_profile
# -rw-r--r-- (쓰기 가능) ← 해결!
적용한 해결책
방법 2를 선택했어요:
1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. PATH 영구 등록
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
# 2. 즉시 적용
source ~/.zshrc
# 3. 정상 동작 확인
uvx --version
# ✅ uvx 0.9.17 (2b5d65e61 2025-12-09)
# 4. MCP Server 실행 테스트
uvx mcp-server-sqlite --help
# ✅ 정상 실행됨
교훈
- UV는 설치됐지만 PATH가 없으면 사용 불가
- Java 개발자 관점: JAR는 있지만 CLASSPATH 미설정
- Mac은 zsh가 기본 쉘
.bash_profile이 아니라.zshrc수정 필요
- 권한 문제는
chmod로 해결chmod 644= 소유자 읽기/쓰기, 그룹/기타 읽기만
- 환경 변수 추가 후 반드시
source- 새 터미널 열거나
source명령어로 즉시 적용
- 새 터미널 열거나
Issue 2: 파일을 찾을 수 없어요 📁
문제 상황
Python 스크립트를 실행하려고 했어요:
1
2
3
4
$ python3 create_dummy_db.py
/opt/homebrew/Cellar/python@3.14/3.14.2/Frameworks/Python.framework/Versions/3.14/Resources/Python.app/Contents/MacOS/Python:
can't open file '/Users/username/create_dummy_db.py': [Errno 2] No such file or directory
개발자 비유:
1
2
3
4
5
6
7
8
9
// Java 클래스 파일이 없는데 실행하려는 상황
public class Main {
public static void main(String[] args) {
Class.forName("CreateDummyDB"); // ❌ ClassNotFoundException
}
}
// Python 스크립트가 없는데 실행하려는 상황
python3 create_dummy_db.py // ❌ FileNotFoundError
원인 분석
- 파일이 실제로 존재하지 않음:
create_dummy_db.py스크립트 파일을 아직 생성하지 않음 - 현재 위치 문제: 홈 디렉토리(
~)에서 실행했지만, 파일이 없는 상태
해결 방법
Step 1: 프로젝트 디렉토리 생성 및 이동
1
2
3
4
5
6
7
# MCP 실습용 디렉토리 생성
mkdir -p ~/projects/mcp-practice
cd ~/projects/mcp-practice
# 현재 위치 확인
pwd
# /Users/username/projects/mcp-practice
Step 2: Python 스크립트 파일 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
cat > create_dummy_db.py << 'EOF'
import sqlite3
from datetime import datetime
# 1. DB 파일 생성 및 연결
conn = sqlite3.connect('products.db')
cursor = conn.cursor()
# 2. 테이블 생성
cursor.execute('''
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price INTEGER NOT NULL,
category TEXT NOT NULL,
stock INTEGER NOT NULL,
created_at TEXT NOT NULL)
''')
# 3. 더미 데이터 삽입
dummy_products = [
('MacBook Pro M3', 2590000, 'Laptop', 15, '2024-01-15'),
('iPhone 15 Pro', 1550000, 'Phone', 30, '2024-02-20'),
('AirPods Pro', 359000, 'Audio', 50, '2024-03-10'),
('iPad Air', 929000, 'Tablet', 20, '2024-04-05'),
('Apple Watch Ultra', 1149000, 'Wearable', 10, '2024-05-12'),
('Magic Keyboard', 149000, 'Accessory', 40, '2024-06-01'),
('Mac Mini M2', 799000, 'Desktop', 12, '2024-07-20'),
('Studio Display', 2090000, 'Monitor', 8, '2024-08-15'),
('HomePod Mini', 129000, 'Audio', 25, '2024-09-30'),
('AirTag 4pack', 149000, 'Accessory', 100, '2024-10-10'),
]
cursor.executemany('''
INSERT INTO products (name, price, category, stock, created_at)
VALUES (?, ?, ?, ?, ?)
''', dummy_products)
# 4. 커밋 및 종료
conn.commit()
conn.close()
print("✅ products.db 생성 완료!")
print(f"총 {len(dummy_products)}개의 상품이 등록되었습니다.")
EOF
Step 3: 스크립트 실행
1
2
3
4
5
python3 create_dummy_db.py
# 출력:
# ✅ products.db 생성 완료!
# 총 10개의 상품이 등록되었습니다.
Step 4: DB 파일 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
# DB 파일 생성 확인
ls -lh products.db
# -rw-r--r-- 1 user staff 20K Dec 13 20:00 products.db ✅
# 데이터 확인
sqlite3 products.db "SELECT COUNT(*) FROM products;"
# 10
# 가장 비싼 상품 3개 조회
sqlite3 products.db "SELECT name, price FROM products ORDER BY price DESC LIMIT 3;"
# MacBook Pro M3|2590000
# Studio Display|2090000
# iPhone 15 Pro|1550000
교훈
- 파일을 먼저 만들어야 실행 가능
- Java 개발자 관점:
.java파일 없이javac실행 불가
- Java 개발자 관점:
- 프로젝트 디렉토리를 먼저 만들자
- 홈 디렉토리(
~)에 파일 흩어지는 것 방지 - 체계적인 파일 관리
- 홈 디렉토리(
- 작업 디렉토리 확인 습관
pwd명령어로 현재 위치 확인ls명령어로 파일 존재 확인
Issue 3: MCP Server가 vi 명령어를 JSON으로 파싱하려고 해요 🤯
문제 상황
MCP Server를 실행했어요:
1
2
3
4
5
6
7
$ uvx mcp-server-sqlite --db-path ./products.db
Installed 36 packages in 45ms
vi ~/Library/Application\ Support/Claude/claude_desktop_config.json
Received exception from stream: 1 validation error for JSONRPCMessage
Invalid JSON: expected value at line 1 column 1
[type=json_invalid, input_value='vi ~/Library/Application...e_desktop_config.json\n', input_type=str]
개발자 비유:
1
2
3
4
5
6
7
8
9
10
11
12
// REST API 서버가 JSON을 기다리는데 HTML을 보낸 상황
@PostMapping("/api")
public Response handleRequest(@RequestBody String json) {
// 기대: {"action": "query"}
// 실제: "vi ~/Library/..."
// 결과: JSON 파싱 에러 ❌
}
// MCP Server도 동일
// 기대: {"jsonrpc":"2.0", "method":"initialize", ...}
// 실제: "vi ~/Library/..."
// 결과: Invalid JSON ❌
원인 분석
- MCP Server가 정상 실행됨 (패키지 36개 설치 완료)
- 잘못된 입력: MCP Server가 실행 중인 상태에서
vi명령어를 입력함 - JSON-RPC 프로토콜 위반: MCP Server는
stdin으로 JSON-RPC 메시지를 기다리는데,vi명령어가 입력되어 JSON 파싱 실패
MCP Server의 동작 방식:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// MCP Server는 stdio(표준 입출력)로 통신
public class MCPServer {
public void run() {
while (true) {
// stdin에서 JSON-RPC 메시지 대기
String input = readFromStdin();
// JSON으로 파싱 시도
JSONRPCMessage message = parseJSON(input);
// 처리
handleMessage(message);
}
}
}
// vi 명령어가 입력되면
// parseJSON("vi ~/Library/...") → ❌ JSON 파싱 실패!
해결 방법
핵심 이해: MCP Server는 “백그라운드 서비스”
MCP Server는 터미널에서 직접 실행하는 게 아니라, Claude Desktop이 자동으로 실행하는 백그라운드 프로세스예요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 잘못된 이해
// "MCP Server를 내가 직접 실행하고, Claude에 연결한다" ❌
// 올바른 이해
// "Claude Desktop이 MCP Server를 자동으로 실행한다" ✅
public class ClaudeDesktop {
public void start() {
// 설정 파일 읽기
Config config = readConfig("claude_desktop_config.json");
// MCP Server 자동 실행
for (ServerConfig server : config.getMcpServers()) {
Process process = Runtime.exec(server.getCommand());
// MCP Server가 백그라운드에서 실행됨
}
}
}
올바른 실습 순서
Step 1: MCP Server 수동 테스트 (선택 사항)
1
2
3
4
5
6
7
8
9
10
11
12
# 프로젝트 디렉토리에서
cd ~/projects/mcp-practice
# MCP Server 실행 (테스트만)
uvx mcp-server-sqlite --db-path ./products.db
# 출력:
# Installed 36 packages in 45ms
# [서버가 대기 중... 여기서 멈춤]
# 테스트 완료! Ctrl+C로 종료
# ^C (Ctrl+C 입력)
⚠️ 주의:
- 이 상태에서는 아무것도 입력하지 마세요!
- MCP Server는 JSON-RPC 메시지만 이해해요
- 일반 명령어(
vi,ls등)를 입력하면 JSON 파싱 에러 발생
Step 2: Claude Desktop 설정 (핵심)
1
2
3
4
5
6
7
# 새 터미널 열기 (Cmd+T) 또는 MCP Server 종료 후
# 설정 파일 수정
vi ~/Library/Application\ Support/Claude/claude_desktop_config.json
# 또는 VS Code로
open -a "Visual Studio Code" ~/Library/Application\ Support/Claude/claude_desktop_config.json
설정 파일 내용:
1
2
3
4
5
6
7
8
9
10
11
12
{
"mcpServers": {
"sqlite": {
"command": "uvx",
"args": [
"mcp-server-sqlite",
"--db-path",
"/Users/username/projects/mcp-practice/products.db"
]
}
}
}
⚠️ 중요: 절대 경로 사용
1
2
3
4
5
6
7
8
# 절대 경로 확인
cd ~/projects/mcp-practice
realpath products.db
# 출력 예시:
# /Users/username/projects/mcp-practice/products.db
# 이 경로를 설정 파일에 사용!
Step 3: Claude Desktop 재시작
1
2
3
4
5
6
7
8
# 1. Claude Desktop 완전 종료
# Cmd + Q (강제 종료)
# 2. 다시 실행
open -a "Claude"
# 3. Claude Desktop이 자동으로 MCP Server 실행
# → 이제 백그라운드에서 동작 중!
교훈
- MCP Server는 백그라운드 서비스
- 직접 실행하는 게 아니라 Claude Desktop이 실행
- Java 비유: Tomcat 서버 (직접 명령 입력 안 함)
- stdio는 JSON-RPC 전용
- 일반 명령어 입력하면 안 됨
- REST API처럼 정해진 프로토콜만 사용
- 수동 테스트는 선택 사항
- MCP Server가 잘 동작하는지만 확인
- 확인 후 바로 Ctrl+C로 종료
- 절대 경로 필수
./products.db(상대 경로) ❌/Users/username/projects/mcp-practice/products.db(절대 경로) ✅- Claude Desktop은 다른 디렉토리에서 실행되므로
- 설정 파일 수정 시 새 터미널 사용
- MCP Server 실행 중인 터미널에서는 명령어 입력 금지
- 새 터미널 탭 열기 (Cmd+T)
Issue 4: Claude가 DB에 접근할 수 없다고 답변해요 😢
문제 상황
Claude Desktop에서 “내 DB에 있는 상품 개수를 세어줘”라고 요청했을 때:
1
2
3
4
5
6
7
안녕하세요! 데이터베이스에 있는 상품 개수를 세어드리고 싶지만,
제가 직접 데이터베이스에 접근할 수 있는 권한은 없습니다.
하지만 다음과 같은 방법으로 도움을 드릴 수 있습니다:
1. SQL 쿼리 작성
2. 파일 기반 데이터 확인
3. 스크립트 작성
...
기대한 동작:
- Claude가 MCP를 통해
products.db를 직접 조회 - 상품 개수(10개)를 바로 답변
실제 동작:
- Claude가 MCP Server를 인식하지 못함
- DB 접근 불가능하다고 답변
원인 분석
- Claude Desktop 설정 파일은 정상:
claude_desktop_config.json에 MCP Server 설정이 올바르게 되어 있음 uvx명령어를 찾을 수 없음: Claude Desktop이 실행될 때 PATH에~/.local/bin이 포함되지 않음- 결과: Claude Desktop이 MCP Server를 실행하려고 시도하지만
uvx명령어를 찾지 못해 실패
개발자 비유:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// application.yml에 설정은 있지만
spring:
datasource:
driver-class-name: org.sqlite.JDBC // ✅ 설정 있음
// 실제로는 JDBC Driver JAR가 CLASSPATH에 없음
// → ClassNotFoundException 발생 ❌
// MCP도 동일
// claude_desktop_config.json에 설정은 있지만
{
"command": "uvx" // ✅ 설정 있음
}
// 실제로는 uvx가 PATH에 없음
// → Command not found 발생 ❌
Claude Desktop의 실행 환경:
1
2
3
4
5
6
7
8
9
// Claude Desktop은 GUI 애플리케이션
// 쉘의 PATH 설정을 따르지 않음!
// 터미널에서 실행 (PATH 포함)
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/Users/me/.local/bin // ✅ uvx 경로 포함
// Claude Desktop에서 실행 (시스템 기본 PATH만)
PATH=/usr/bin:/bin:/usr/sbin:/sbin // ❌ ~/.local/bin 없음
해결 방법
방법 1: 전체 경로 사용 (권장)
Claude Desktop 설정 파일에서 uvx 대신 전체 경로를 사용해요.
Step 1: uvx 전체 경로 확인
1
2
3
4
5
6
7
# uvx 위치 확인
ls -la ~/.local/bin/uvx
# -rwxr-xr-x 1 user staff 336672 Dec 10 07:50 /Users/username/.local/bin/uvx
# 또는
which uvx
# /Users/username/.local/bin/uvx
Step 2: 설정 파일 수정
1
2
# 설정 파일 열기
vi ~/Library/Application\ Support/Claude/claude_desktop_config.json
수정 전:
1
2
3
4
5
6
7
8
9
10
11
12
{
"mcpServers": {
"sqlite": {
"command": "uvx", // ❌ PATH에 없으면 실행 실패
"args": [
"mcp-server-sqlite",
"--db-path",
"/Users/username/projects/mcp-practice/products.db"
]
}
}
}
수정 후:
1
2
3
4
5
6
7
8
9
10
11
12
{
"mcpServers": {
"sqlite": {
"command": "/Users/username/.local/bin/uvx", // ✅ 전체 경로 사용
"args": [
"mcp-server-sqlite",
"--db-path",
"/Users/username/projects/mcp-practice/products.db"
]
}
}
}
⚠️ 중요: username을 실제 사용자명으로 변경!
1
2
3
4
5
6
7
# 현재 사용자명 확인
whoami
# username
# 또는
echo $USER
# username
Step 3: Claude Desktop 재시작
1
2
3
4
5
6
7
8
# 1. Claude Desktop 완전 종료
# Cmd + Q (강제 종료)
# 2. 다시 실행
open -a "Claude"
# 3. MCP 연결 확인
# 하단에 🔌 아이콘 확인
방법 2: 시스템 PATH에 추가 (고급)
GUI 애플리케이션도 인식할 수 있도록 시스템 레벨 PATH 설정:
1
2
3
4
5
6
7
8
# /etc/paths.d/ 디렉토리 확인
ls -la /etc/paths.d/
# 새 파일 생성 (sudo 필요)
sudo sh -c 'echo "/Users/username/.local/bin" > /etc/paths.d/uvx'
# 또는 launchd 설정 (더 복잡)
# ~/.MacOSX/environment.plist 파일 생성
⚠️ 주의:
- 시스템 레벨 설정은 권한이 필요하고 복잡해요
- 방법 1(전체 경로)이 더 간단하고 안전해요
적용한 해결책
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 1. uvx 전체 경로 확인
ls -la ~/.local/bin/uvx
# -rwxr-xr-x 1 username staff 336672 Dec 10 07:50 /Users/username/.local/bin/uvx
# 2. 설정 파일 수정
vi ~/Library/Application\ Support/Claude/claude_desktop_config.json
# 수정 내용:
{
"mcpServers": {
"sqlite": {
"command": "/Users/username/.local/bin/uvx", // 전체 경로로 변경
"args": [
"mcp-server-sqlite",
"--db-path",
"/Users/username/projects/mcp-practice/products.db"
]
}
}
}
# 3. Claude Desktop 재시작
# Cmd+Q → 종료
# open -a "Claude" → 실행
# 4. 테스트
# "내 DB에 있는 상품 개수를 세어줘"
# → ✅ "products 테이블에 총 10개의 상품이 있습니다"
교훈
- GUI 애플리케이션은 쉘 PATH를 따르지 않음
- 터미널에서
uvx가 동작해도 Claude Desktop은 못 찾을 수 있음 - Java 비유: IDE에서 실행할 때와 터미널에서 실행할 때 CLASSPATH가 다를 수 있음
- 터미널에서
- 전체 경로 사용이 안전함
- 상대 경로나 PATH 의존성 제거
- 명확하고 예측 가능한 동작
- 설정 파일 수정 후 반드시 재시작
- Claude Desktop은 시작 시에만 설정 파일을 읽음
- 재시작하지 않으면 변경사항 적용 안 됨
- MCP 연결 확인 방법
- Claude Desktop 하단의 🔌 아이콘 확인
- 클릭해서 “Connected MCP Servers” 목록 확인
최종 성공! 🎉
모든 트러블슈팅을 해결한 후, Claude Desktop에서 테스트해봤어요:
1
2
3
4
5
6
7
8
9
10
사용자: "내 DB에 있는 상품 개수를 세어줘"
Claude:
[MCP를 통해 products.db 조회]
"products 테이블에 총 10개의 상품이 등록되어 있습니다:
1. MacBook Pro M3 - 2,590,000원 (Laptop)
2. iPhone 15 Pro - 1,550,000원 (Phone)
3. AirPods Pro - 359,000원 (Audio)
..."
드디어 성공했어요! 🎊
전체 트러블슈팅 요약
| Issue | 문제 | 원인 | 해결 방법 |
|---|---|---|---|
| Issue 1 | uvx 명령어를 찾을 수 없음 | PATH에 ~/.local/bin 미등록 | .zshrc에 PATH 추가 |
| Issue 2 | create_dummy_db.py 파일을 찾을 수 없음 | 파일 미생성 | 프로젝트 디렉토리 생성 후 스크립트 작성 |
| Issue 3 | MCP Server가 vi 명령어를 JSON으로 파싱 시도 | MCP Server 실행 중 일반 명령어 입력 | MCP Server는 백그라운드 서비스로 이해 |
| Issue 4 | Claude가 DB에 접근할 수 없다고 답변 | GUI 앱은 쉘 PATH를 따르지 않음 | 설정 파일에서 전체 경로 사용 |
실습 후기 및 교훈
1. 이론과 실습의 차이
가이드를 읽을 때는 “이렇게 하면 되겠지”라고 생각했지만, 실제로 해보니 예상치 못한 문제들이 생겼어요. 특히:
- PATH 문제: 터미널에서는 동작하는데 GUI 앱에서는 안 되는 경우
- 프로토콜 이해: MCP Server가 JSON-RPC만 이해한다는 걸 몰라서 일반 명령어를 입력한 실수
- 경로 문제: 상대 경로와 절대 경로의 차이, GUI 앱의 실행 환경 차이
2. 개발자 비유의 힘
각 문제를 Java 개발자 관점으로 비유하면서 이해가 훨씬 쉬웠어요:
- PATH 문제 = CLASSPATH 문제
- MCP Server = 백그라운드 서비스 (Tomcat처럼)
- JSON-RPC = REST API 프로토콜
이런 비유가 문제 해결에 큰 도움이 됐어요.
3. 단계별 디버깅의 중요성
각 문제를 단계별로 분석하고 해결하면서:
- 증상 파악: 무엇이 잘못되었는지
- 원인 분석: 왜 이런 문제가 생겼는지
- 해결 방법: 어떻게 고칠 수 있는지
- 교훈 정리: 다음에 같은 실수를 하지 않기 위해
이런 과정을 거치면서 문제 해결 능력이 향상됐어요.
4. 문서화의 가치
트러블슈팅 로그를 작성하면서 나중에 같은 문제를 겪을 때 빠르게 해결할 수 있게 됐어요. 또한 다른 사람들도 같은 문제를 겪을 수 있으니 공유하는 게 좋겠다고 생각했어요.
마무리
MCP 실습을 통해 이론만으로는 알 수 없었던 실제 경험을 얻었어요. 특히:
- ✅ PATH 설정의 중요성
- ✅ GUI 앱과 터미널의 실행 환경 차이
- ✅ MCP Server의 동작 방식 이해
- ✅ 절대 경로 사용의 필요성
이런 경험들이 다음 프로젝트에서 큰 도움이 될 거예요.
혹시 같은 문제를 겪고 계신 분들이 있다면, 이 포스팅이 도움이 되길 바라요! 🚀
참고 자료
- MCP 실습 가이드
- MCP 기초 이론
- UV 공식 문서: https://docs.astral.sh/uv/
- PATH 개념: https://linuxize.com/post/how-to-add-directory-to-path-in-linux/