소개
시도하고자 했던 것:
Claude Code 작업 완료 시 Telegram으로 100% 확실하게 알림을 받고, 양방향 통신하는 시스템 구축
근본적인 문제 - MCP의 한계:
MCP 방식의 치명적 문제
MCP = Claude가 "선택적으로" 호출하는 도구
Claude가 telegram_send 호출 → ✅ 알림 감
Claude가 telegram_send 깜빡함 → ❌ 알림 안 감
→ Claude의 "의지"에 의존 = 신뢰할 수 없음
안 보내지는 경우를 대비해서 PreToolUse Hook을 사용하기는 했는데, 이마저도 Claude 의존적이었습니다.
실제 겪은 상황:
Claude에게 "작업 끝나면 텔레그램으로 알려줘"라고 했지만 종종 깜빡함
PreToolUse Hook으로 "AskUserQuestion 전에 telegram_send 먼저!" 경고해도 무시하는 경우 발생
CLAUDE.md에 굵은 글씨로 강조해도 100% 준수 불가능
해결책 - Telegram MCP 제거, 완전 Hook 기반 전환 및 Stop Hook방식으로 변경
Hook 방식의 핵심
Hook = Claude 턴 종료 시 "무조건" 실행되는 스크립트
Claude 턴 종료 → Hook 자동 실행 → 알림 100% 보장
→ 시스템 이벤트 기반 = Claude 의지와 무관
방식
실행 주체
신뢰도
MCP
Claude가 호출해야 함
80~90% (깜빡할 수 있음)
Hook
시스템이 자동 실행
100% (무조건 실행)
PreToolUse vs Stop Hook 비교
구분
PreToolUse Hook
Stop Hook
실행 시점
특정 도구 호출 전
턴 종료 후
역할
Claude에게 "경고" 메시지 전달
Hook이 직접 작업 수행
Claude 의존
⚠️ 경고를 무시할 수 있음
✅ Claude 의지와 무관
신뢰도
90% (경고해도 무시 가능)
100% (무조건 실행)
턴 종료가 발생하는 6가지 상황
Stop Hook은 아래 모든 상황에서 자동 실행됩니다:
#
상황
설명
예시
1
명시적 작업 완료
사용자가 요청한 작업을 모두 수행한 후
코드 수정, 파일 생성, 커밋 등 완료
2
사용자 입력 대기
AskUserQuestion 도구 호출 시
"A와 B 중 어떤 방식으로 진행할까요?"
3
정보 제공 후 대기
코드 분석 결과 설명 후
"더 볼 것 있나요?"
4
에러/블로커 발생
진행 불가능한 상황 발생
빌드 실패, 권한 문제
5
도구 사용 후 응답 대기
외부 작업 완료 보고 후
API 호출 결과 전달
6
Idle 상태
다음 지시를 기다리는 순간
응답 완료 후 대기
진행 방법
전체 아키텍처
1. 발송 흐름 (Claude → Telegram)
[Claude Code]
│
│ 턴 종료
▼
[Stop Hook] ──── POST /send ────▶ [Bridge Daemon]
(Python) (Node.js)
│
│ Telegram Bot API
▼
[Telegram Bot]
│
▼
[사용자 수신] 📱
2. 수신 흐름 (Telegram → Claude)
[사용자 Reply] 📱
│
▼
[Telegram Bot]
│
│ Long Polling
▼
[Bridge Daemon] ◀─── 메시지 감지 + 세션 매칭
│
│ 응답 저장
▼
[Stop Hook] ◀─────── GET /poll ─────────┘
(Python) 응답 수신
│
│ block 반환
▼
[Claude Code] ◀───── 다음 지시 전달
Bridge Daemon 역할
Hook과 Telegram 사이의 중계 서버 역할을 합니다:
1. HTTP API 서버 (포트 9876)
POST /send- 메시지 전송GET /poll- 응답 대기GET /health- 상태 확인
2. Telegram Long Polling
Bot API로 새 메시지 수신
Reply 메시지 감지 및 세션 매칭
3. 세션 관리
질문-응답 매핑
타임아웃 처리 (5분)
자동 정리 (60분 후 만료)
Bridge를 사용하는 이유:
직접 호출
Bridge 경유
매번 Bot Token 노출
Token은 Bridge에만 저장
응답 수신 불가 (단방향)
Long Polling으로 양방향 통신
세션 관리 불가
질문-응답 매핑 가능
MCP 방식 vs Hook 방식 비교
MCP 방식 - Claude 의존
Claude 작업 완료
↓
Claude가 telegram_send 호출? ─── NO ──→ ❌ 알림 없음
│
YES
↓
MCP Server → Bridge → Telegram
Hook 방식 - 시스템 자동
Claude 작업 완료 (턴 종료)
↓
Stop Hook 자동 실행 (100%)
↓
Python urllib → Bridge HTTP API → Telegram ✅
Hook에서 MCP 사용 불가 (Telegram MCP를 제거한 또 하나의 이유)
핵심 포인트
Hook = Claude Code와 별개의 Python 프로세스
MCP는 Claude Code 내부에서만 사용 가능
Hook(외부 프로세스)에서는 MCP 호출 불가능
→ Hook이 Telegram 보내려면 직접 HTTP 호출 필요
구분
Claude Code 내부
Hook (외부 프로세스)
MCP 사용
✅ 가능
❌ 불가능
HTTP API
✅ 가능
✅ 가능
결론: Hook에서 MCP를 못 쓰니까, 어차피 HTTP API로 Bridge 직접 호출해야 함 → MCP 존재 이유 없음 → 제거
마찬가지로 curl로 Telegram API를 직접 호출하던 /task 명령어(task.md)도 삭제함. Hook이 자동으로 알림을 보내므로 불필요해짐.
핵심 구현
Stop Hook --> Python 호출
#!/usr/bin/env python3
"""
Stop Hook: 턴 종료 시 telegram 자동 전송 + 응답 대기 (v3.9)
핵심: Claude가 뭘 하든 상관없이, 턴이 끝나면 무조건 실행됨
"""
def main():
# 1. Telegram 모드 ON인지 확인
if not is_telegram_mode_on(input_data):
return 0
# 2. Claude가 이미 telegram_send를 호출했는지 확인
if has_telegram_send_in_turn(lines, last_user_idx):
return 0 # Claude가 보냈으면 중복 방지
# 3. Claude가 안 보냈으면 Hook이 대신 전송
summary = extract_last_assistant_summary(lines, last_user_idx)
send_telegram_auto(session_id, summary,
project_name=project_name,
session_name=session_name,
project_dir=project_dir)
# 4. 응답 대기 (Telegram Reply)
poll_response(session_id, question_id, timeout=300)
Bridge Daemon 시작
# Bridge 시작 (백그라운드 실행)
./scripts/telegram-bridge.sh start
# 상태 확인
./scripts/telegram-bridge.sh status
# 출력: ✅ Daemon 실행 중 (PID: 58952)
# 중지
./scripts/telegram-bridge.sh stop
설정 (settings.json)
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "python3 ~/.claude/hooks/check-completion-notification.py"
}]
}]
}
}
Telegram 메시지 포맷
메시지 포맷은 Claude Code에게 변경해 달라고 요청하면 변경해 줍니다.
🤖 itdalife-new / feature-auth
📁 /Users/eyeson/workspaces/itdalife-new
✅ Hook v3.9 업데이트 완료
- 세션명/프로젝트명 표시 추가
- 작업 요약 최대 600자
━━━━━━━━━━━━━━━━━━━━━━━━━
💬 Reply로 다음 지시를 보내주세요
💤 done 입력 시 대기 종료
세션 관리
하나의 Telegram 채팅방으로 수신하다보니, 여러 개의 터미널 띄워 놨을 때 구분이 잘 안되어서 세션명을 지정할 수 있게 만들었습니다.
# 세션명 설정 (여러 세션 구분용)
/session feature-auth
# Telegram 모드 ON/OFF
/telegram on
/telegram off
파일 구조
전역으로 적용해야 하는 부분과 프로젝트 단위로 적용해야 하는 부분을 잘 구분해야 합니다.
전역 설정 (~/.claude/)
~/.claude/
├── hooks/
│ └── check-completion-notification.py # Stop Hook (v3.9)
├── commands/
│ └── session.md # /session 명령어
└── settings.json # Hook 설정
프로젝트별 설정 (/project/)
/project/
├── .telegram-mode # ON/OFF 플래그
├── .session-name # 세션명
├── mcp-servers/
│ └── telegram/
│ └── src/
│ ├── bridge/ # HTTP 서버 + Telegram Polling
│ └── mcp/ # (레거시) MCP 서버
└── scripts/
└── telegram-bridge.sh # Bridge 데몬 관리 스크립트
결과와 배운 점
핵심 배운 점
"AI에게 중요한 작업을 맡길 때는 의지가 아닌 시스템으로 강제해야 한다"
❌ "꼭 알림 보내줘" (프롬프트 의존) → 깜빡할 수 있음
❌ PreToolUse Hook으로 경고 → 무시할 수 있음
✅ Stop Hook으로 자동 실행 → 100% 보장