Claude Code iMessage 채널 연동: 터미널 없이 핸드폰으로 AI 코딩 어시스턴트 사용하기
Claude Code에 iMessage 채널을 연동해서 터미널 없이 핸드폰으로 AI 코딩 어시스턴트를 사용하는 방법. 설정 과정에서 만나는 bun 미설치, FDA 권한 등 흔한 함정과 해결법을 정리했어요.
1. 왜 iMessage 연동인가?
Claude Code는 강력하지만 터미널에 묶여 있다는 한계가 있어요. 소파에 누워서, 출퇴근 중에, 또는 잠깐 자리를 비운 사이에 코드 관련 질문을 하고 싶을 때가 있잖아요.
Claude Code v2.1.80부터 채널(Channels) 기능이 research preview로 도입됐어요. 채널은 외부 메시징 플랫폼의 메시지를 실행 중인 Claude Code 세션으로 밀어넣는 MCP 서버예요. 현재 지원되는 플랫폼은 세 가지예요:
- Telegram — 봇 토큰 기반
- Discord — 봇 토큰 기반
- iMessage — 토큰 없이 Mac의
chat.db직접 읽기
iMessage는 별도 봇 생성이나 토큰 발급 없이 Mac에서 바로 사용할 수 있다는 점이 매력적이에요. 하지만 설정 과정에서 예상치 못한 함정이 있었어요.
2. 아키텍처: 어떻게 동작하는가?
연동 설정 전에 전체 구조를 이해하면 트러블슈팅이 훨씬 수월해요.
전체 흐름
iPhone에서 iMessage 전송
↓ (iCloud 동기화)
Mac 메시지 앱 → ~/Library/Messages/chat.db 에 기록
↓ (1초 간격 폴링)
채널 서버 (bun 프로세스) → 새 메시지 감지
↓ (MCP stdio 통신)
Claude Code 세션 → 메시지 수신, 처리, 응답 생성
↓ (AppleScript)
Mac 메시지 앱 → iMessage로 응답 전송
↓ (iCloud 동기화)
iPhone에서 응답 수신
핵심 포인트
별도 서버가 아니라 같은 세션이에요. 채널 서버는 Claude Code가 띄우는 자식 프로세스(bun)이고, 표준입출력(stdio)으로 통신해요. 별도 세션을 생성하거나 백그라운드 데몬이 도는 게 아니에요.
Claude Code 세션 (터미널)
└── MCP 서버 (bun server.ts)
├── chat.db 폴링 (1초 간격)
├── 인바운드 → MCP notification → 같은 세션으로 전달
└── 아웃바운드 → AppleScript → 메시지 앱으로 전송
채널 서버를 닫으면 iMessage 연동도 끊겨요. 항상 켜두려면 터미널을 열어두거나 백그라운드 프로세스로 실행해야 해요.
메시지 수신 방식
채널 서버는 chat.db를 SQLite로 직접 읽어요. 서버 시작 시점의 마지막 메시지 ID(watermark)를 기록하고, 이후 새로운 메시지만 감지해요.
// 서버 내부 폴링 로직 (개념)
const watermark = getMaxRowId() // 시작 시점의 마지막 ID
setInterval(() => {
const newMessages = db.query(
'SELECT * FROM message WHERE ROWID > ?', [watermark]
)
for (const msg of newMessages) {
handleInbound(msg) // ← 접근 제어 → MCP notification
}
}, 1000) // 1초 간격
이 방식 덕분에 서버 재시작 시 과거 메시지가 재전송되지 않아요.
응답 전송 방식
Claude가 답변을 생성하면 채널 서버의 reply 도구를 호출해요. 이 도구는 AppleScript로 메시지 앱을 제어해서 실제 iMessage를 보내요.
-- 내부적으로 이런 AppleScript가 실행됨
tell application "Messages"
set targetChat to a reference to chat id "iMessage;-;+821012345678"
send "답변 내용" to targetChat
end tell
긴 메시지는 자동으로 청크 분할되고, 마지막 청크에 Sent by Claude 서명이 붙어요.
3. 사전 준비: 세 가지 필수 요건
3-1. Bun 설치 (가장 흔한 함정)
이 부분에서 막히는 분이 많을 거예요. 채널 서버는 Bun 런타임이 필수예요. Node.js가 아니라 Bun이에요.
왜 Bun인가? 서버가 bun:sqlite — Bun의 네이티브 SQLite 모듈 — 을 사용하기 때문이에요. Node.js의 better-sqlite3 같은 패키지가 아니라 Bun 런타임에 내장된 모듈이라 Bun 없이는 아예 실행이 안 돼요.
// server.ts 첫 줄
#!/usr/bin/env bun
// Bun 네이티브 SQLite
import { Database } from 'bun:sqlite'
Bun이 없으면 어떻게 되느냐고요? Claude Code 터미널에는 Listening for channel messages from: plugin:imessage@claude-plugins-official이라고 뜨지만, 실제로는 서버 프로세스가 즉시 종료돼요. 메시지를 보내도 아무 반응이 없어요.
제가 실제로 겪은 상황이에요:
# Claude Code 화면에는 이렇게 나오지만...
Listening for channel messages from: plugin:imessage@claude-plugins-official
# 실제로는 bun이 없어서 서버가 바로 죽은 상태
# → iMessage를 보내도 아무 반응 없음 😱
이 메시지는 Claude Code가 채널 플러그인을 등록할 때 출력하는 거라서, 서버 프로세스의 실제 상태와 무관해요. 가장 먼저 bun을 설치하세요.
# Bun 설치
curl -fsSL https://bun.sh/install | bash
# 셸 재시작 (또는 source)
source ~/.zshrc # zsh 기준
# 설치 확인
bun --version
# 1.3.11 (이상)
3-2. Full Disk Access (전체 디스크 접근권한)
chat.db는 macOS가 TCC(Transparency, Consent, and Control)로 보호하는 파일이에요. 아무 프로세스나 읽을 수 없어요.
터미널 앱이 아니라 bun 바이너리에 FDA를 줘야 해요. 채널 서버는 bun이 실행하는 거니까요.
시스템 설정 → 개인정보 보호 및 보안 → 전체 디스크 접근권한
여기에 추가해야 할 대상:
- 터미널 앱 (Terminal, iTerm2, 또는 IDE)
- bun 바이너리 (
~/.bun/bin/bun)
bun을 추가하는 방법:
+버튼 클릭Cmd+Shift+G로 경로 이동 창 열기/Users/사용자명/.bun/bin/bun입력- 추가
FDA가 없으면 서버가 시작하자마자 이런 에러와 함께 종료돼요:
imessage channel: cannot open chat.db — authorization denied
Grant Full Disk Access to your terminal (or the bun binary):
System Settings → Privacy & Security → Full Disk Access
3-3. iMessage 동기화 확인
iPhone의 iMessage가 Mac으로 동기화되어야 해요. 두 가지를 확인하세요:
문자 메시지 전달:
iPhone → 설정 → 메시지 → 문자 메시지 전달 → [Mac 이름] 활성화
iCloud 메시지 동기화:
iPhone → 설정 → Apple ID → iCloud → 메시지 → 켜기
Mac → 시스템 설정 → Apple ID → iCloud → 메시지 → 켜기
확인 방법: Mac에서 메시지 앱을 열고 최근 대화가 보이면 동기화가 되고 있는 거예요.
4. 설정 과정
Step 1: 플러그인 설치
Claude Code 세션에서:
/plugin install imessage@claude-plugins-official
만약 플러그인을 찾을 수 없다는 메시지가 나오면, 마켓플레이스를 업데이트하세요:
/plugin marketplace update claude-plugins-official
또는 마켓플레이스를 처음 추가하는 경우:
/plugin marketplace add anthropics/claude-plugins-official
Step 2: 채널과 함께 Claude Code 시작
기존 세션을 종료하고 새로 시작해요. 채널은 세션 시작 시점에 --channels 플래그로 지정해야 하며, 실행 중인 세션에 나중에 추가할 수는 없어요.
claude --channels plugin:imessage@claude-plugins-official
성공하면 이런 메시지가 보여요:
Listening for channel messages from: plugin:imessage@claude-plugins-official
Experimental · inbound messages will be pushed into this session,
this carries prompt injection risks.
Restart Claude Code without --channels to disable.
Step 3: 자기 자신한테 테스트
iMessage의 self-chat(자기 자신한테 메시지 보내기)은 접근 제어를 바이패스해요. 별도 설정 없이 바로 동작해요.
iPhone이나 다른 Apple 기기에서 자기 번호로 메시지를 보내보세요:
나: "현재 작업 디렉토리에 뭐가 있어?"
Claude Code 터미널에 인바운드 메시지가 표시되고, Claude가 처리한 뒤 iMessage로 답변이 와야 해요.
참고: 첫 번째 응답을 보낼 때 macOS가 "터미널이 메시지 앱을 제어하려고 합니다"라는 자동화 권한 팝업을 띄워요. 허용을 클릭하세요.
Step 4: 다른 사람 허용 (선택)
기본 정책은 allowlist이며 목록이 비어 있어요. 자기 자신만 통과하는 상태예요. 다른 사람을 추가하려면:
/imessage:access allow +821012345678
핸들은 전화번호(+국가번호...) 또는 Apple ID 이메일([email protected]) 형식이에요.
현재 상태를 확인하려면:
/imessage:access
5. 접근 제어: allowlist vs pairing
iMessage 채널의 접근 제어는 ~/.claude/channels/imessage/access.json에 저장돼요. 이 파일은 메시지가 들어올 때마다 다시 읽히기 때문에, 변경사항이 즉시 반영돼요.
DM 정책 세 가지
| 정책 | 동작 | 사용 시나리오 |
|---|---|---|
allowlist (기본) |
명시적으로 추가한 사람만 통과 | 대부분의 경우 |
pairing |
모르는 번호가 문자하면 페어링 코드 자동 응답 | ⚠️ 비추천 |
disabled |
self-chat 외 모든 메시지 차단 | 나만 사용 |
pairing 모드는 피하세요. iMessage는 당신의 개인 chat.db를 읽기 때문에, pairing 모드를 켜면 연락처에 있는 모든 사람이 문자를 보낼 때마다 "페어링 코드: ABC123" 같은 자동 응답을 받게 돼요. Telegram이나 Discord와 달리 전용 봇 계정이 아니라 본인 번호에서 나가는 거예요.
# ❌ 이렇게 하지 마세요
/imessage:access policy pairing # 모든 연락처에 자동 응답 발생
# ✅ 이렇게 하세요
/imessage:access allow +821012345678 # 필요한 사람만 명시적 추가
access.json 구조
{
"dmPolicy": "allowlist",
"allowFrom": ["+821012345678", "[email protected]"],
"groups": {
"iMessage;+;chat123456": {
"requireMention": true,
"allowFrom": []
}
},
"pending": {},
"mentionPatterns": ["@claude"]
}
allowFrom— 허용된 개인 핸들 목록groups— 그룹 채팅별 설정 (requireMention으로 멘션 필수 여부 설정)mentionPatterns— iMessage에는 구조화된 멘션이 없으므로, 정규식 패턴으로 감지
그룹 채팅 추가
# 그룹 추가 (멘션 필수)
/imessage:access group add "iMessage;+;chat123456"
# 멘션 없이도 모든 메시지 수신
/imessage:access group add "iMessage;+;chat123456" --no-mention
6. 트러블슈팅: 실제로 겪은 문제들
문제 1: "Listening" 메시지가 뜨는데 메시지가 안 온다
증상: Claude Code 화면에 Listening for channel messages from: plugin:imessage@claude-plugins-official이 표시되지만, iMessage를 보내도 아무 반응이 없어요.
원인: 99% 확률로 bun이 설치되어 있지 않거나 PATH에 없는 경우예요. Listening... 메시지는 Claude Code가 플러그인을 등록할 때 출력하는 것이지, 서버 프로세스가 정상 동작 중이라는 의미가 아니에요.
확인 방법:
# bun이 설치되어 있는지 확인
which bun
# 없으면: bun not found
# 기본 설치 경로 확인
ls ~/.bun/bin/bun
해결 방법:
# 설치
curl -fsSL https://bun.sh/install | bash
source ~/.zshrc
# 확인
bun --version
문제 2: chat.db 접근 거부
증상: 서버가 시작하자마자 종료되고, 에러 로그에 authorization denied가 보여요.
확인 방법:
# 파일이 보이는지 (ls는 FDA 불필요)
ls ~/Library/Messages/chat.db
# → 파일 경로가 보여야 함
# 실제로 읽을 수 있는지 (FDA 필요)
sqlite3 ~/Library/Messages/chat.db "SELECT count(*) FROM message;"
# → 숫자가 나와야 함. "authorization denied"면 FDA 문제
해결 방법: 시스템 설정 → 개인정보 보호 및 보안 → 전체 디스크 접근권한에 터미널 앱과 bun 바이너리 추가.
주의: ls로 파일이 보인다고 FDA가 된 게 아니에요. ls는 디렉토리 권한만 필요하고, sqlite3로 파일을 여는 건 TCC 보호를 거쳐요.
문제 3: channels 디렉토리가 없다
증상: ~/.claude/channels/imessage/ 디렉토리가 존재하지 않아요.
실제로는 문제가 아닐 수 있어요. 이 디렉토리는 access.json을 처음 수정할 때 생성돼요(접근 정책 변경, 사용자 추가 등). 서버가 정상 동작하더라도 access.json을 수정한 적이 없으면 디렉토리가 없을 수 있어요.
# 디렉토리 존재 여부 확인
ls ~/.claude/channels/imessage/
# 없으면 수동 생성 (선택)
mkdir -p ~/.claude/channels/imessage
문제 4: self-chat이 동작하지 않는다
확인 포인트:
- 동일한 Apple ID인지 확인 — iPhone과 Mac이 같은 Apple ID로 로그인되어 있어야 해요
- iCloud 메시지 동기화가 켜져 있는지 — 양쪽 모두
- Mac 메시지 앱에 메시지가 보이는지 — 메시지 앱을 열어서 직접 확인
- 서버가 실제로 동작 중인지 — bun 설치와 FDA를 다시 확인
문제 5: 응답이 안 보내진다
첫 응답 시 macOS가 자동화 권한을 요청해요. 이 팝업을 놓치면 응답이 안 가요.
"터미널(또는 IDE)이(가) '메시지' 앱을 제어하려고 합니다."
→ [허용] 클릭
이미 거부한 경우: 시스템 설정 → 개인정보 보호 및 보안 → 자동화 → 터미널 앱에서 메시지 허용.
7. 실전 활용 팁
배경 실행
터미널을 닫으면 채널 서버도 종료돼요. 항상 켜두려면:
# tmux나 screen으로 백그라운드 실행
tmux new-session -d -s claude-imessage \
'claude --channels plugin:imessage@claude-plugins-official'
# 세션 확인
tmux list-sessions
# 세션에 다시 붙기
tmux attach -t claude-imessage
여러 채널 동시 사용
--channels 플래그에 여러 플러그인을 공백으로 구분해서 전달할 수 있어요:
claude --channels \
plugin:imessage@claude-plugins-official \
plugin:telegram@claude-plugins-official
응답 서명 끄기
기본적으로 응답 끝에 Sent by Claude가 붙어요. 끄려면:
IMESSAGE_APPEND_SIGNATURE=false claude --channels plugin:imessage@claude-plugins-official
텍스트 청크 설정
긴 응답은 자동 분할되는데, 분할 크기와 방식을 조정할 수 있어요:
# 최대 2000자 단위로 분할
/imessage:access set textChunkLimit 2000
# 줄바꿈 기준으로 분할 (기본: length)
/imessage:access set chunkMode newline
8. 보안 고려사항
채널은 편리하지만 보안 의식이 필요해요.
프롬프트 인젝션 위험
Claude Code 시작 시 경고가 뜨는 이유가 있어요:
Experimental · inbound messages will be pushed into this session,
this carries prompt injection risks.
iMessage로 들어오는 메시지는 곧 Claude Code에 대한 프롬프트예요. 악의적인 사용자가 allowlist에 들어와 있으면, 의도치 않은 명령을 실행시킬 수 있어요.
권한 릴레이
채널 서버가 권한 릴레이를 지원하면, iMessage로 도구 사용 승인/거부를 할 수 있어요. 형식은:
yes abcde ← 승인
no abcde ← 거부
이 기능 때문에 allowlist 관리가 더 중요해요. allowlist에 있는 사람은 Claude Code 세션의 도구 사용 권한을 승인/거부할 수 있거든요.
안전한 사용 규칙
- allowlist는 신뢰하는 사람만 — 도구 권한까지 위임하는 거예요
- pairing 모드 사용 자제 — 개인 번호에서 자동 응답이 나가요
- 민감한 프로젝트에서는 self-chat만 —
disabled정책 사용 - 무인 실행 시 주의 —
--dangerously-skip-permissions는 정말 신뢰할 수 있는 환경에서만
9. 핵심 개념 정리
| 개념 | 설명 |
|---|---|
| 채널(Channel) | MCP 서버가 외부 메시지를 Claude Code 세션으로 밀어넣는 메커니즘 |
| MCP stdio | 채널 서버와 Claude Code가 표준입출력으로 통신하는 방식 |
| Watermark | 서버 시작 시점의 마지막 메시지 ID. 이후 메시지만 처리 |
| Self-chat | 자기 자신한테 보내는 메시지. 접근 제어 바이패스 |
| FDA (Full Disk Access) | macOS의 전체 디스크 접근권한. chat.db 읽기에 필수 |
| 핸들(Handle) | 전화번호 또는 이메일 형식의 발신자 식별자 |
| 페어링(Pairing) | 미등록 사용자가 코드를 받아 인증하는 과정 (iMessage에서는 비추천) |
| Echo 필터링 | Self-chat 시 자기 메시지의 에코를 걸러내는 로직 |
10. FAQ
Q: iPhone 없이 Mac에서만 사용할 수 있나요?
A: 네, 가능해요. Mac 메시지 앱에서 직접 자기 자신한테 메시지를 보내도 동작해요. 하지만 핸드폰에서 사용하는 게 채널의 핵심 장점이에요.
Q: Claude Code가 꺼지면 밀린 메시지를 나중에 처리하나요?
A: 아니요. 서버 시작 시점 이후의 메시지만 처리해요. 서버가 꺼진 동안 온 메시지는 무시돼요. 항상 켜두려면 tmux 등으로 백그라운드 실행하세요.
Q: 그룹 채팅에서도 사용할 수 있나요?
A: 네, /imessage:access group add <chatGuid> 명령어로 그룹을 추가할 수 있어요. 기본적으로 멘션 패턴이 필요하며, --no-mention 옵션으로 모든 메시지를 수신할 수도 있어요.
Q: 이미지를 보내면 Claude가 볼 수 있나요?
A: 네, 메시지당 첫 번째 이미지의 파일 경로가 Claude에게 전달돼요. Claude는 이 파일을 읽어서 분석할 수 있어요.
Q: Telegram이나 Discord 채널과 동시에 사용할 수 있나요?
A: 네, --channels 플래그에 여러 플러그인을 공백으로 나열하면 돼요.
11. 참고 자료
- Claude Code Channels 공식 문서 — 채널 기능 전반, 설정 방법, 보안 가이드
- iMessage 플러그인 소스 코드 — 서버 구현 코드
- Bun 공식 사이트 — Bun 런타임 설치 및 문서
- Channels Reference — 커스텀 채널 빌드 가이드