채널은 Claude Code 세션으로 이벤트를 푸시하는 MCP 서버이므로 Claude는 터미널 외부에서 발생하는 일에 반응할 수 있습니다.
단방향 또는 양방향 채널을 구축할 수 있습니다. 단방향 채널은 Claude가 작동할 수 있도록 알림, 웹훅 또는 모니터링 이벤트를 전달합니다. 채팅 브리지와 같은 양방향 채널은 Claude가 메시지를 다시 보낼 수 있도록 회신 도구를 노출합니다. 신뢰할 수 있는 발신자 경로가 있는 채널은 권한 프롬프트를 릴레이하도록 선택할 수 있으므로 원격으로 도구 사용을 승인하거나 거부할 수 있습니다.
이 페이지에서 다루는 내용:
- 개요: 채널의 작동 방식
- 필요한 것: 요구 사항 및 일반 단계
- 예: 웹훅 수신기 구축: 최소 단방향 연습
- 서버 옵션: 생성자 필드
- 알림 형식: 이벤트 페이로드
- 회신 도구 노출: Claude가 메시지를 다시 보낼 수 있도록 함
- 인바운드 메시지 게이팅: 프롬프트 주입을 방지하기 위한 발신자 확인
- 권한 프롬프트 릴레이: 도구 승인 프롬프트를 원격 채널로 전달
개요
채널은 Claude Code와 동일한 머신에서 실행되는 MCP 서버입니다. Claude Code는 이를 서브프로세스로 생성하고 stdio를 통해 통신합니다. 채널 서버는 외부 시스템과 Claude Code 세션 간의 브리지입니다:- 채팅 플랫폼 (Telegram, Discord): 플러그인이 로컬에서 실행되고 플랫폼의 API를 폴링하여 새 메시지를 확인합니다. 누군가 봇에 DM을 보내면 플러그인이 메시지를 수신하고 Claude로 전달합니다. 노출할 URL이 없습니다.
- 웹훅 (CI, 모니터링): 서버가 로컬 HTTP 포트에서 수신합니다. 외부 시스템이 해당 포트에 POST하고 서버가 페이로드를 Claude로 푸시합니다.
필요한 것
유일한 하드 요구 사항은@modelcontextprotocol/sdk 패키지와 Node.js 호환 런타임입니다. Bun, Node, Deno 모두 작동합니다. 연구 미리보기의 사전 구축된 플러그인은 Bun을 사용하지만 채널이 반드시 그럴 필요는 없습니다.
서버는 다음을 수행해야 합니다:
claude/channel기능을 선언하여 Claude Code가 알림 리스너를 등록하도록 함- 무언가 발생할 때
notifications/claude/channel이벤트를 내보냄 - stdio 전송을 통해 연결 (Claude Code가 서버를 서브프로세스로 생성)
--dangerously-load-development-channels를 사용하여 로컬에서 테스트합니다. 자세한 내용은 연구 미리보기 중 테스트를 참조하세요.
예: 웹훅 수신기 구축
이 연습은 HTTP 요청을 수신하고 Claude Code 세션으로 전달하는 단일 파일 서버를 구축합니다. 마지막에는 CI 파이프라인, 모니터링 알림 또는curl 명령과 같이 HTTP POST를 보낼 수 있는 모든 것이 Claude로 이벤트를 푸시할 수 있습니다.
이 예제는 기본 제공 HTTP 서버 및 TypeScript 지원을 위해 Bun을 런타임으로 사용합니다. 대신 Node 또는 Deno를 사용할 수 있습니다. 유일한 요구 사항은 MCP SDK입니다.
채널 서버 작성
webhook.ts라는 파일을 생성합니다. 이것이 전체 채널 서버입니다: stdio를 통해 Claude Code에 연결되고 포트 8788에서 HTTP POST를 수신합니다. 요청이 도착하면 본문을 채널 이벤트로 Claude로 푸시합니다.webhook.ts
- 서버 구성: 기능에
claude/channel이 있는 MCP 서버를 생성합니다. 이것이 Claude Code에 이것이 채널임을 알려줍니다.instructions문자열은 Claude의 시스템 프롬프트로 이동합니다: Claude에 예상할 이벤트, 회신 여부, 회신해야 하는 경우 사용할 도구 및 전달할 속성(예:chat_id)을 알려줍니다. - Stdio 연결: stdin/stdout을 통해 Claude Code에 연결합니다. 이는 모든 MCP 서버에 표준입니다: Claude Code가 이를 서브프로세스로 생성합니다.
- HTTP 리스너: 포트 8788에서 로컬 웹 서버를 시작합니다. 모든 POST 본문은
mcp.notification()을 통해 채널 이벤트로 Claude로 전달됩니다.content는 이벤트 본문이 되고 각meta항목은<channel>태그의 속성이 됩니다. 리스너는mcp인스턴스에 액세스해야 하므로 동일한 프로세스에서 실행됩니다. 더 큰 프로젝트의 경우 별도의 모듈로 분할할 수 있습니다.
Claude Code에 서버 등록
Claude Code가 시작하는 방법을 알 수 있도록 MCP 구성에 서버를 추가합니다. 동일한 디렉토리의 프로젝트 수준 Claude Code는 시작 시 MCP 구성을 읽고 각 서버를 서브프로세스로 생성합니다.
.mcp.json의 경우 상대 경로를 사용합니다. ~/.claude.json의 사용자 수준 구성의 경우 모든 프로젝트에서 서버를 찾을 수 있도록 전체 절대 경로를 사용합니다:.mcp.json
테스트
연구 미리보기 중에 사용자 정의 채널은 허용 목록에 없으므로 개발 플래그로 Claude Code를 시작합니다:Claude Code가 시작되면 MCP 구성을 읽고 페이로드는 Claude Code 세션에 Claude Code 터미널에서 Claude가 메시지를 수신하고 응답을 시작하는 것을 볼 수 있습니다: 파일 읽기, 명령 실행 또는 메시지가 요구하는 모든 작업. 이것은 단방향 채널이므로 Claude는 세션에서 작동하지만 웹훅을 통해 아무것도 다시 보내지 않습니다. 회신을 추가하려면 회신 도구 노출을 참조하세요.이벤트가 도착하지 않으면 진단은
webhook.ts를 서브프로세스로 생성하며 구성한 포트(이 예제에서는 8788)에서 HTTP 리스너가 자동으로 시작됩니다. 서버를 직접 실행할 필요가 없습니다.“조직 정책에 의해 차단됨”이 표시되면 팀 또는 엔터프라이즈 관리자가 먼저 채널을 활성화해야 합니다.별도의 터미널에서 HTTP POST를 메시지와 함께 서버로 보내 웹훅을 시뮬레이션합니다. 이 예제는 CI 실패 알림을 포트 8788로 보냅니다 (또는 구성한 포트):<channel> 태그로 도착합니다:curl이 반환한 것에 따라 달라집니다:curl은 성공하지만 Claude에 도달하지 않음: 세션에서/mcp를 실행하여 서버의 상태를 확인합니다. “연결 실패”는 일반적으로 서버 파일의 종속성 또는 가져오기 오류를 의미합니다.~/.claude/debug/<session-id>.txt의 디버그 로그에서 stderr 추적을 확인합니다.curl이 “연결 거부”로 실패함: 포트가 아직 바인딩되지 않았거나 이전 실행의 오래된 프로세스가 포트를 보유하고 있습니다.lsof -i :<port>는 수신 중인 것을 표시합니다. 세션을 다시 시작하기 전에 오래된 프로세스를kill합니다.
연구 미리보기 중 테스트
연구 미리보기 중에 모든 채널은 등록하기 위해 승인된 허용 목록에 있어야 합니다. 개발 플래그는 확인 프롬프트 후 특정 항목에 대한 허용 목록을 우회합니다. 이 예제는 두 항목 유형을 모두 보여줍니다:--channels와 결합하면 우회가 --channels 항목으로 확장되지 않습니다. 연구 미리보기 중에 승인된 허용 목록은 Anthropic에서 큐레이션되므로 채널은 구축 및 테스트하는 동안 개발 플래그에 남아 있습니다.
이 플래그는 허용 목록만 건너뜁니다.
channelsEnabled 조직 정책은 여전히 적용됩니다. 신뢰할 수 없는 소스의 채널을 실행하는 데 사용하지 마세요.서버 옵션
채널은Server 생성자에서 이러한 옵션을 설정합니다. instructions 및 capabilities.tools 필드는 표준 MCP입니다. capabilities.experimental['claude/channel'] 및 capabilities.experimental['claude/channel/permission']은 채널 특정 추가 사항입니다:
| 필드 | 유형 | 설명 |
|---|---|---|
capabilities.experimental['claude/channel'] | object | 필수. 항상 {}. 존재는 알림 리스너를 등록합니다. |
capabilities.experimental['claude/channel/permission'] | object | 선택 사항. 항상 {}. 이 채널이 권한 릴레이 요청을 수신할 수 있음을 선언합니다. 선언되면 Claude Code는 도구 승인 프롬프트를 채널로 전달하므로 원격으로 승인하거나 거부할 수 있습니다. 권한 프롬프트 릴레이를 참조하세요. |
capabilities.tools | object | 양방향만. 항상 {}. 표준 MCP 도구 기능. 회신 도구 노출을 참조하세요. |
instructions | string | 권장. Claude의 시스템 프롬프트에 추가됩니다. Claude에 예상할 이벤트, <channel> 태그 속성의 의미, 회신 여부, 회신해야 하는 경우 사용할 도구 및 전달할 속성(예: chat_id)을 알려줍니다. |
capabilities.tools를 생략합니다. 이 예제는 채널 기능, 도구 및 설정된 지침이 있는 양방향 설정을 보여줍니다:
notifications/claude/channel으로 mcp.notification()을 호출합니다. 매개변수는 다음 섹션에 있습니다.
알림 형식
서버는 두 개의 매개변수로notifications/claude/channel을 내보냅니다:
| 필드 | 유형 | 설명 |
|---|---|---|
content | string | 이벤트 본문. <channel> 태그의 본문으로 전달됩니다. |
meta | Record<string, string> | 선택 사항. 각 항목은 채팅 ID, 발신자 이름 또는 알림 심각도와 같은 라우팅 컨텍스트를 위해 <channel> 태그의 속성이 됩니다. 키는 식별자여야 합니다: 문자, 숫자 및 밑줄만. 하이픈 또는 다른 문자를 포함하는 키는 자동으로 삭제됩니다. |
Server 인스턴스에서 mcp.notification()을 호출하여 이벤트를 푸시합니다. 이 예제는 두 개의 메타 키가 있는 CI 실패 알림을 푸시합니다:
<channel> 태그로 래핑된 Claude의 컨텍스트에 도착합니다. source 속성은 서버의 구성된 이름에서 자동으로 설정됩니다:
회신 도구 노출
채널이 양방향인 경우(알림 포워더가 아닌 채팅 브리지), Claude가 메시지를 다시 보낼 수 있도록 표준 MCP 도구를 노출합니다. 도구 등록에 대해 채널 특정 사항은 없습니다. 회신 도구에는 세 가지 구성 요소가 있습니다:Server생성자 기능의tools: {}항목이므로 Claude Code가 도구를 발견합니다- 도구의 스키마를 정의하고 전송 로직을 구현하는 도구 핸들러
- Claude에 도구를 호출할 시기와 방법을 알려주는
Server생성자의instructions문자열
회신 도구 등록
다음을
webhook.ts에 추가합니다. import는 다른 가져오기와 함께 파일 맨 위로 이동합니다. 두 핸들러는 Server 생성자와 mcp.connect() 사이에 있습니다. 이것은 Claude가 chat_id 및 text로 호출할 수 있는 reply 도구를 등록합니다:webhook.ts입니다. 아웃바운드 회신은 Server-Sent Events (SSE)를 사용하여 GET /events를 통해 스트리밍되므로 curl -N localhost:8788/events는 실시간으로 볼 수 있습니다. 인바운드 채팅은 POST /에 도착합니다:
"회신
인바운드 메시지 게이팅
게이트되지 않은 채널은 프롬프트 주입 벡터입니다. 엔드포인트에 도달할 수 있는 모든 사람이 Claude 앞에 텍스트를 넣을 수 있습니다. 채팅 플랫폼 또는 공개 엔드포인트를 수신하는 채널은 무언가를 내보내기 전에 실제 발신자 확인이 필요합니다.mcp.notification()을 호출하기 전에 발신자를 허용 목록과 비교하여 확인합니다. 이 예제는 집합에 없는 발신자의 메시지를 삭제합니다:
message.from.id, message.chat.id가 아닙니다. 그룹 채팅에서 이들은 다르며 방에 게이트하면 허용 목록에 있는 그룹의 모든 사람이 세션에 메시지를 주입할 수 있습니다.
Telegram 및 Discord 채널은 동일한 방식으로 발신자 허용 목록에 게이트합니다. 페어링으로 목록을 부트스트랩합니다: 사용자가 봇에 DM을 보내면 봇이 페어링 코드로 회신하고 사용자가 Claude Code 세션에서 승인하며 플랫폼 ID가 추가됩니다. 전체 페어링 흐름은 구현 중 하나를 참조하세요. iMessage 채널은 다른 접근 방식을 취합니다: 시작 시 메시지 데이터베이스에서 사용자의 자신의 주소를 감지하고 자동으로 통과시키며 다른 발신자는 핸들로 추가됩니다.
권한 프롬프트 릴레이
권한 릴레이는 Claude Code v2.1.81 이상이 필요합니다. 이전 버전은
claude/channel/permission 기능을 무시합니다.Bash, Write 및 Edit과 같은 도구 사용 승인을 다룹니다. 프로젝트 신뢰 및 MCP 서버 동의 대화는 릴레이되지 않습니다. 이들은 로컬 터미널에만 나타납니다.
릴레이 작동 방식
권한 프롬프트가 열리면 릴레이 루프에는 네 가지 단계가 있습니다:- Claude Code는 짧은 요청 ID를 생성하고 서버에 알립니다
- 서버는 프롬프트 및 ID를 채팅 앱으로 전달합니다
- 원격 사용자가 예 또는 아니오로 해당 ID로 회신합니다
- 인바운드 핸들러는 회신을 판정으로 구문 분석하고 Claude Code는 ID가 열린 요청과 일치하는 경우에만 적용합니다
권한 요청 필드
Claude Code의 아웃바운드 알림은notifications/claude/channel/permission_request입니다. 채널 알림과 같이 전송은 표준 MCP이지만 메서드 및 스키마는 Claude Code 확장입니다. params 객체에는 서버가 아웃바운드 프롬프트로 포맷하는 네 개의 문자열 필드가 있습니다:
| 필드 | 설명 |
|---|---|
request_id | a-z에서 그려진 5개의 소문자이며 l을 제외하므로 휴대폰에 입력할 때 1 또는 I로 읽히지 않습니다. 아웃바운드 프롬프트에 포함하여 회신에서 에코할 수 있도록 합니다. Claude Code는 발급한 ID를 가진 판정만 수락합니다. 로컬 터미널 대화는 이 ID를 표시하지 않으므로 아웃바운드 핸들러가 이를 학습하는 유일한 방법입니다. |
tool_name | Claude가 사용하려는 도구의 이름(예: Bash 또는 Write). |
description | 이 특정 도구 호출이 수행하는 작업의 인간이 읽을 수 있는 요약이며 로컬 터미널 대화가 표시하는 동일한 텍스트입니다. Bash 호출의 경우 이는 Claude의 명령 설명이거나 주어진 것이 없으면 명령 자체입니다. |
input_preview | 도구의 인수를 JSON 문자열로 200자로 잘린 것입니다. Bash의 경우 명령입니다. Write의 경우 파일 경로 및 콘텐츠의 접두사입니다. 한 줄 메시지만 공간이 있는 경우 프롬프트에서 생략합니다. 서버가 표시할 내용을 결정합니다. |
notifications/claude/channel/permission이며 두 필드가 있습니다: 위의 ID를 에코하는 request_id 및 'allow' 또는 'deny'로 설정된 behavior. Allow는 도구 호출을 진행하도록 합니다. Deny는 이를 거부하며 로컬 대화에서 아니오로 답변하는 것과 동일합니다. 어느 판정도 향후 호출에 영향을 주지 않습니다.
채팅 브리지에 릴레이 추가
양방향 채널에 권한 릴레이를 추가하려면 세 가지 구성 요소가 필요합니다:Server생성자의experimental기능 아래claude/channel/permission: {}항목이므로 Claude Code가 프롬프트를 전달하는 방법을 알 수 있습니다notifications/claude/channel/permission_request에 대한 알림 핸들러가 프롬프트를 포맷하고 플랫폼 API를 통해 전송합니다- 인바운드 메시지 핸들러의 확인이
yes <id>또는no <id>를 인식하고 텍스트를 Claude로 전달하는 대신notifications/claude/channel/permission판정을 내보냅니다
들어오는 요청 처리
Server 생성자와 mcp.connect() 사이에 알림 핸들러를 등록합니다. Claude Code는 권한 대화가 열릴 때 4개의 요청 필드로 호출합니다. 핸들러는 플랫폼에 대한 프롬프트를 포맷하고 ID로 회신하기 위한 지침을 포함합니다:인바운드 핸들러에서 판정 가로채기
인바운드 핸들러는 플랫폼에서 메시지를 수신하는 루프 또는 콜백입니다: 발신자에 게이트하고
notifications/claude/channel을 내보내 채팅을 Claude로 전달하는 동일한 위치입니다. 채팅 전달 호출 전에 판정 형식을 인식하고 대신 권한 알림을 내보내는 확인을 추가합니다.정규식은 Claude Code가 생성하는 ID 형식과 일치합니다: 5개 문자, l 없음. /i 플래그는 휴대폰 자동 수정이 회신을 대문자로 만드는 것을 허용합니다. 다시 보내기 전에 캡처된 ID를 소문자로 만듭니다.- 다른 형식: 인바운드 핸들러의 정규식이 일치하지 않으므로
approve it또는 ID 없는yes와 같은 텍스트는 Claude로 일반 메시지로 넘어갑니다. - 올바른 형식, 잘못된 ID: 서버가 판정을 내보내지만 Claude Code는 해당 ID를 가진 열린 요청을 찾지 못하고 자동으로 삭제합니다.
전체 예제
아래의 조립된webhook.ts는 이 페이지의 세 가지 확장을 모두 결합합니다: 회신 도구, 발신자 게이팅 및 권한 릴레이. 여기서 시작하는 경우 초기 연습에서 프로젝트 설정 및 .mcp.json 항목도 필요합니다.
curl에서 양쪽 방향을 테스트 가능하게 하려면 HTTP 리스너는 두 경로를 제공합니다:
GET /events: SSE 스트림을 열어 두고 각 아웃바운드 메시지를data:줄로 푸시하므로curl -N은 Claude의 회신 및 권한 프롬프트가 실시간으로 도착하는 것을 볼 수 있습니다.POST /: 인바운드 측, 이전과 동일한 핸들러이지만 이제 채팅 전달 분기 전에 판정 형식 확인이 삽입되었습니다.
"권한
webhook.ts를 생성합니다:
/events 스트림에 나타나며 5자 ID를 포함합니다. 원격 측에서 승인합니다:
reply 도구를 통해 돌아오고 스트림에도 도착합니다.
이 파일의 3개의 채널 특정 부분:
Server생성자의 기능:claude/channel은 알림 리스너를 등록하고,claude/channel/permission은 권한 릴레이에 옵트인하며,tools는 Claude가 회신 도구를 발견하도록 합니다.- 아웃바운드 경로:
reply도구 핸들러는 Claude가 대화형 응답을 위해 호출하는 것입니다.PermissionRequestSchema알림 핸들러는 권한 대화가 열릴 때 Claude Code가 호출하는 것입니다. 둘 다send()를 호출하여/events를 통해 브로드캐스트하지만 시스템의 다른 부분에 의해 트리거됩니다. - HTTP 핸들러:
GET /events는 SSE 스트림을 열어 두므로 curl이 아웃바운드를 실시간으로 볼 수 있습니다.POST는 인바운드이며X-Sender헤더에 게이트됩니다.yes <id>또는no <id>본문은 Claude Code로 판정 알림으로 이동하며 Claude에 도달하지 않습니다. 다른 모든 것은 채널 이벤트로 Claude로 전달됩니다.
플러그인으로 패키징
채널을 설치 가능하고 공유 가능하게 하려면 플러그인으로 래핑하고 마켓플레이스에 게시합니다. 사용자는/plugin install로 설치한 다음 --channels plugin:<name>@<marketplace>로 세션별로 활성화합니다.
자신의 마켓플레이스에 게시된 채널은 승인된 허용 목록에 없으므로 여전히 --dangerously-load-development-channels를 실행해야 합니다. 추가되려면 공식 마켓플레이스에 제출합니다. 채널 플러그인은 승인되기 전에 보안 검토를 거칩니다. 팀 및 엔터프라이즈 계획에서 관리자는 대신 조직의 자신의 allowedChannelPlugins 목록에 플러그인을 포함할 수 있으며, 이는 기본 Anthropic 허용 목록을 대체합니다.
참고 항목
- 채널을 설치하고 Telegram, Discord, iMessage 또는 fakechat 데모를 사용하며 팀 또는 엔터프라이즈 조직에 대해 채널을 활성화합니다
- 작동하는 채널 구현은 페어링 흐름, 회신 도구 및 파일 첨부가 있는 완전한 서버 코드입니다
- MCP는 채널 서버가 구현하는 기본 프로토콜입니다
- 플러그인을 사용하여 채널을 패키징하면 사용자가
/plugin install로 설치할 수 있습니다