디스코드 구글캘린더 연동 봇 만들기: 카톡 캡처 OCR 자동 등록 시스템 구축
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
Discord 구글 캘린더 봇을 직접 만들어 운영하면 일정 입력이라는 잡일이 거의 사라집니다. 입력 방법은 두 가지입니다. 첫째, 텍스트 한 줄 — 채널에 "내일 오후 3시 강남역 미팅"처럼 적기만 하면 됩니다. 둘째, 이미지 캡처 — 카카오톡으로 받은 모임 안내, 학원 시간표, 행사 포스터를 그대로 드래그하면 됩니다. 둘 다 Claude CLI가 읽어 Google Calendar에 자동 등록합니다. 매번 손으로 캘린더 앱을 열어 제목·시간·장소를 입력하던 마찰이 사라집니다. 본인은 이 봇으로 누적 [N]건+ 일정을 자동 등록하며 운영 중입니다.
아래에서는 Discord 메시지(텍스트 또는 이미지) → Claude CLI → Google Calendar MCP 파이프라인을 하나씩 짜 나갑니다. macOS + Python + discord.py + Claude Code CLI + Google Calendar MCP + SQLite 조합이고, 한 시간 남짓이면 본인 환경에서 그대로 따라 만들 수 있습니다. 직전 편 Discord 유튜브 봇 → Notion 아카이브와 같은 "Discord = 인박스" 패턴의 캘린더 버전입니다.
1. 왜 이 조합인가
구조 자체는 복잡하지 않습니다. 무엇이든 일단 Discord 채널에 던져 두면, 그걸 Claude가 읽어 일정으로 정리한 뒤 Google Calendar에 옮겨 박아 줍니다. 채팅창은 그때그때 떠오른 일정을 아무렇게나 흘려 넣는 자리이고, 캘린더는 그렇게 들어온 것들이 제대로 자리 잡는 곳입니다. 사람이 하는 일은 텍스트 한 줄을 적거나 캡처 한 장을 드래그하는 것까지입니다.
입력은 두 경로로 나뉩니다. 텍스트 메시지는 이미지 처리 없이 바로 Claude CLI가 일정으로 구조화합니다. "담주 수요일 7시 저녁 약속"처럼 적어도 됩니다. 이미지 첨부는 Claude CLI의 비전이 카카오톡 캡처나 안내문을 직접 해석합니다. 이미지 일정을 읽을 때 보통 별도 OCR 엔진을 붙이지만, 이 봇은 그러지 않습니다. Claude 비전이 제목·시작·종료·장소를 바로 뽑아내므로, OCR 텍스트를 다시 파싱하는 중간 단계가 없어 한국어 안내문처럼 레이아웃이 제각각인 이미지에도 강합니다. 두 경로 모두 같은 일정 JSON으로 합류해 동일하게 등록됩니다.
등록도 Google Calendar API를 직접 다루지 않습니다. Claude Code CLI에 연결된 Google Calendar MCP가 이벤트 생성을 대신하므로, OAuth 토큰을 코드로 관리할 필요가 없습니다. 봇은 "이런 일정을 등록해줘"라고 Claude에게 위임하고 결과만 받습니다.
마지막으로, 잘못 읽었을 때를 대비합니다. 등록 결과는 Discord 임베드로 돌아오고 [수정]/[삭제] 버튼이 붙습니다. 시간을 잘못 잡았으면 그 임베드에 "수정: 내일 14시"라고 답장 한 줄만 보내면 캘린더 이벤트가 갱신됩니다.
2. 사전 준비물 체크리스트
- macOS, Python 3.11+, Discord 계정과 전용 채널 1개
- Discord 봇(Developer Portal) — Message Content Intent 활성화
- Claude Code CLI 설치 +
claude.ai Google CalendarMCP 연결 (claude mcp list로 연결 상태 확인) - Google 계정(Calendar) — Claude MCP에 연결
- SQLite (macOS 기본 포함)
- launchd (상시 실행용, macOS 기본)
준비물에 별도 OCR 서비스나 Google Cloud API 키 발급이 없다는 점이 이 구성의 장점입니다. 비전과 캘린더 등록을 모두 Claude CLI 한 곳으로 모았기 때문입니다.
3. 단계별 구현
3.1 Discord 봇 생성 + 전용 채널
Discord Developer Portal에서 새 애플리케이션을 만들고 Bot 탭에서 토큰을 발급합니다. 반드시 Privileged Gateway Intents에서 Message Content Intent를
켜야 메시지 본문과 첨부 이미지를 읽을 수 있습니다. OAuth2 URL Generator로 봇을 서버에 초대한 뒤, 일정 전용 채널을 하나 만들고 개발자 모드에서 채널 ID를 복사합니다. 토큰과 채널 ID는
.env의 DISCORD_TOKEN, DISCORD_CHANNEL_ID에만 저장합니다.
3.2 Claude CLI + Google Calendar MCP 연결 확인
이 봇의 등록 단계는 전적으로 Calendar MCP에 의존합니다. 터미널에서 다음으로 연결 상태를 먼저 확인합니다.
claude mcp list # claude.ai Google Calendar 가 Connected 인지 확인
여기서 Calendar MCP가 연결돼 있지 않으면 추출은 되더라도 등록이 전부 실패하므로, 구현 전에 반드시 연결 상태를 확보합니다.
3.3 추출 호출 — 메시지에서 일정 JSON 뽑기
봇은 on_message로 전용 채널의 메시지를 감시합니다. 텍스트만 있는 메시지는 다운로드 없이 본문을 그대로 프롬프트에 넣습니다. 이미지
첨부가 있으면 첨부 폴더에 내려받고, 그 경로를 프롬프트에 넣어 Claude CLI 비전이 읽도록 합니다. 두 경우 모두 같은 추출 프롬프트를 거쳐 동일한 일정 JSON으로 수렴합니다.
python3 -m venv .venv && source .venv/bin/activate
pip install discord.py aiohttp python-dotenv
추출 프롬프트에는 일정 JSON 스키마와 함께 현재 KST 시각을 반드시 주입합니다. 그래야 "내일 2시", "담주 화요일"처럼 상대 표현만 있는 일정도 절대 날짜로 변환됩니다. 반환된 JSON은 제목·시작·종료·종일 여부·장소·신뢰도(confidence)·되묻기 필요 여부(needs_clarification) 필드로 파싱합니다. 되묻기가 필요한 경우(상대 날짜가 모호하거나 시간이 비어 있을 때)에는 바로 등록하지 않고 채널에 한 번 되묻습니다.
3.4 등록 호출 — Calendar MCP + 결과 임베드/버튼
추출한 일정 JSON을 Claude CLI + Calendar MCP에 넘겨 이벤트를 생성합니다. 생성된 이벤트의 링크를 받아 Discord 결과 임베드를 만들고, discord.py의 View로
[수정]/[삭제] 버튼을 붙입니다. 신뢰도가 CONFIDENCE_THRESHOLD보다 낮으면 임베드에 주의 표시를 남겨 사람이 한 번 더 검토하도록 유도합니다(등록 자체는 진행). 잘못
등록됐다면 임베드에 답장으로 "수정: ..." 한 줄을 보내거나 버튼을 눌러 즉시 고칠 수 있습니다.
3.5 SQLite 상태 — 캐치업 커서 + 매핑
state.py는 두 가지를 SQLite에 저장합니다. 첫째, 마지막으로 처리한 메시지 ID를 커서로 두어 봇이 재시작하면 그 이후 메시지만 캐치업합니다. 둘째, Discord 임베드
메시지 ID와 캘린더 이벤트 ID의 매핑을 저장해, 나중에 수정·삭제 요청이 들어왔을 때 어떤 이벤트를 손볼지 특정하고 같은 일정이 두 번 등록되는 것을 막습니다.
3.6 상시 실행 — launchd 등록
봇을 launchd로 등록하면 로그인 후 항상 떠 있게 됩니다. 다만 macOS에서 Google Drive(CloudStorage) 경로를 작업 디렉터리로 두면 권한 문제로 봇이 파일을 못 읽는 함정이 있는데, 이는 4장에서 다룹니다. 등록 후에는 전용 채널에 카톡 캡처를 한 장 던져 결과 임베드와 실제 캘린더 등록을 확인합니다.
4. 자주 만나는 에러 3가지
4.1 launchd가 Google Drive 폴더에 접근하지 못해 봇이 멈춤
launchd로 상시 실행할 때 작업 디렉터리를 Google Drive(CloudStorage) 경로로 두면, macOS 개인정보 보호(TCC) 권한에 막혀 봇이 코드·데이터 파일을 읽지 못합니다. 해결책은
운영 사본을 로컬(~/.discord-calendar/)에 두고 거기서 봇을 구동하는 것입니다. 원본은 Google Drive에서 편집하고 sync.sh로 로컬에
동기화합니다. launchd plist의 WorkingDirectory도 로컬 경로로 지정합니다.
4.2 "내일", "담주 화" 같은 상대 날짜를 엉뚱한 날로 등록
캡처나 텍스트에 절대 날짜가 없고 상대 표현만 있으면 캘린더에 잘못된 날짜로 등록됩니다. 추출 프롬프트에 현재 KST 시각을 주입해 상대 표현을 절대 날짜로 변환하고, 그래도 모호하면
needs_clarification으로 표시해 등록을 보류하고 채널에 되묻도록 했습니다.
4.3 절전/깨어남 이후 봇이 좀비가 되어 그 사이 메시지 누락
macOS가 절전에서 깨어나면 Discord 커넥션이 끊겨, 그 사이 올라온 캡처가 처리되지 않을 수 있습니다. SQLite 캐치업 커서로 마지막 처리 메시지 이후를 재처리하고, sleepwatcher의
~/.wakeup 훅으로 깨어날 때 봇을 자동 재시작해 누락을 막습니다.
마치며
이 봇을 쓰고 나서 달라진 건, 카톡으로 받은 일정 캡처를 더 이상 손으로 캘린더에 옮겨 적지 않게 됐다는 점입니다. 채널에 캡처 한 장을 던지면 몇 초 뒤 캘린더에 일정이 박혀 있고, 잘못 읽었더라도 답장 한 줄로 고칩니다.
운영자 운영 노트 (실측 1차 정보 — 발행 전 교체): 누적 등록 [N]건. 가장 까다로웠던 부분은 [상대 날짜 되묻기 / 저화질 캡처 인식 등 실제 케이스]. 비전 OCR이 한국어 안내문을 [어디까지] 읽었는지 소회.
이 글의 봇은 Discord 콘텐츠 아카이브 시리즈의 한 편입니다. 뉴스 URL·인스타 저장 같은 변형 봇은 후속 편에서 다룰 예정입니다. 본문 중 명령어가 동작하지 않으면 Discord.py 공식 문서와 Claude Code CLI 문서를 함께 확인하기를 권합니다.
같은 주제 다른 글 — Discord·Notion 콘텐츠 자동 아카이브
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글






작성해주신 글을 참고해서 저도 디스코드와 구글 캘린더를 연동하는 에이전트를 만들어봤습니다! 캡처 사진 인식률도 생각보다 훨씬 좋고, 텍스트 추출도 정확해서 정말 만족스럽게 사용 중입니다. 좋은 정보 공유해주셔서 감사합니다!
답글삭제