telegram-ask-mcp

Claude가 선택지를 물을 때 — 터미널 대신 텔레그램으로 묻고, 폰에서 받은 답을 돌려주는 MCP 서버
MCP · stdio Python · FastMCP 의존성 없음 (stdlib + mcp) MIT
자리에 없어도 폰으로 Claude의 질문에 답하고 작업을 계속 진행시킨다. Claude가 ask_via_telegram 도구를 호출하면 질문이 텔레그램으로 오고, 버튼을 누르거나 번호·자유 텍스트로 답하면 그 답이 Claude로 전달된다.
❓ 어느 방식으로 배포할까요? 1. 블루-그린 2. 카나리 3. 롤링 👉 버튼을 누르거나 번호를 보내세요. 다른 답은 직접 입력해도 됩니다.
2

동작 흐름

  1. Claude가 ask_via_telegram(question, options) 호출
  2. 서버가 질문 + 번호 인라인 버튼을 텔레그램으로 전송
  3. 사용자가 버튼 탭 / 번호 입력 / 자유 텍스트로 응답
  4. 서버가 getUpdates long-poll로 응답을 받아 Claude에 반환
  5. 약 10분 안에 답이 없으면 timeout 반환 → Claude는 평소처럼 터미널에서 재질문
⚠️ 왜 기존 팝업을 자동으로 못 가로채나: MCP 서버는 다른 도구(Claude 내장 AskUserQuestion)를 후킹할 수 없다. 그래서 "묻기" 전용 도구를 만들고, Claude가 질문 상황에서 이 도구를 쓰도록 메모리/규칙으로 유도한다.

도구

ask_via_telegram
질문 전송 후 답 받을 때까지 대기. answer / via(button·text) / option_index / is_custom, 또는 timeout 반환.
notify_telegram
답을 기다리지 않는 단방향 알림. 작업 완료·승인요청 안내 등.
check_config
봇 연결(getMe)·대상 chat_id 점검. 토큰 값은 노출하지 않음.

시작하기 — 봇 만들기부터 연결까지

사전 준비: Python 3.10+ · uv · 텔레그램 계정.

  1. 텔레그램 봇 생성@BotFather 대화에서 /newbot → 봇 이름 → bot으로 끝나는 username 입력 → 토큰 발급(8383…:AAH…xyz 형태). 토큰은 비밀번호 동급, 노출 금지. (분실/노출 시 BotFather /token·/revoke)
  2. 봇에게 먼저 말 걸기 — 만든 봇과의 1:1 대화에서 /start 등 아무 메시지나 전송.
    ❗ 봇은 사용자가 먼저 말 걸기 전엔 사용자에게 메시지를 못 보낸다. 이 단계를 빼먹으면 나중에 질문이 안 날아온다.
  3. 내 chat_id 알아내기 — 봇에게 메시지를 보낸 뒤:
    curl -s "https://api.telegram.org/bot<봇토큰>/getUpdates"
    응답의 result[].message.chat.id 가 내 chat_id. 비어 있으면("result": []) 봇에게 메시지를 안 보낸 것. (또는 @userinfobot 에게 메시지 → ID 회신)
  4. 비밀 파일 만들기 — 토큰을 설정에 직접 안 적으려면(권장):
    mkdir -p ~/.config/telegram-ask
    cat > ~/.config/telegram-ask/secrets.env <<'EOF'
    TELEGRAM_BOT_TOKEN=8383…:AAH…xyz
    TELEGRAM_CHAT_ID=8952171082
    EOF
    chmod 600 ~/.config/telegram-ask/secrets.env
    형식은 KEY=VALUE 또는 export KEY="VALUE" — 쉘 스크립트도 OK. git 커밋 금지.

설치

$ uv tool install git+https://github.com/naryeo628/telegram-ask-mcp

클론 후 설치하려면 git clone … && cd telegram-ask-mcp && uv tool install . — 둘 다 ~/.local/bin/telegram-ask-mcp 실행 파일을 만든다.

Claude Code 등록 (~/.claude.json, user 스코프)

토큰을 설정에 직접 안 적는 방식(권장) — 기존 비밀 파일을 가리키기만 한다:

{
  "mcpServers": {
    "telegram-ask": {
      "command": "/Users/<you>/.local/bin/telegram-ask-mcp",
      "env": {
        "TELEGRAM_ENV_FILE": "/Users/<you>/secrets.env"
      }
    }
  }
}

TELEGRAM_ENV_FILEKEY=VALUE(또는 export KEY="VALUE") 라인을 가진 파일이면 된다(쉘스크립트도 OK). 그 안의 TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID 를 읽는다. 리터럴로 직접 적어도 됨.

Claude Desktop · 기타 클라이언트

같은 mcpServers 블록을 클라이언트 설정 파일에 넣는다.

연결 확인

클라이언트 재시작 후(도구는 재시작해야 로드됨) check_config 실행 → 정상이면:

{ "ok": true, "bot_username": "my_claude_asker_bot",
  "bot_id": 8383648698, "chat_id": "8952171082",
  "wait_sec": 600, "poll_sec": 50 }

환경변수

토큰/chat_id 는 리터럴 → 개별 파일 → 공유 env 파일 순으로 먼저 잡히는 값을 쓴다. 셋 중 하나로만 주입하면 된다 — 설정에 토큰을 직접 안 적고 파일만 가리킬 수 있다.

변수기본설명
TELEGRAM_BOT_TOKEN(1) 봇 토큰 리터럴. 비밀
TELEGRAM_CHAT_ID(1) 대상 chat_id 리터럴
TELEGRAM_BOT_TOKEN_FILE(2) 토큰 원문 1줄 파일 경로
TELEGRAM_CHAT_ID_FILE(2) chat_id 원문 1줄 파일 경로
TELEGRAM_ENV_FILE(3) KEY=VALUE 파일 경로 — 위 두 키를 파싱(쉘스크립트 OK)
TELEGRAM_ASK_WAIT_SEC600전체 응답 대기 한도(초)
TELEGRAM_ASK_POLL_SEC501회 long-poll 길이(초)

"항상 텔레그램으로 묻기" 규칙

Claude가 선택지를 물 상황마다 이 도구를 쓰게 하려면, 유저/프로젝트 메모리나 CLAUDE.md에 적어 둔다:

사용자에게 선택지를 물어야 할 때는 터미널 팝업 대신 telegram-ask 의
ask_via_telegram 를 먼저 호출한다. timeout 이 오면 그때 터미널에서 다시 묻는다.

문제 해결

증상원인 / 해결
check_config "토큰을 찾지 못했습니다"env 미주입 또는 파일 경로 오타. TELEGRAM_ENV_FILE/리터럴 중 하나가 실제로 들어갔는지 확인
질문이 폰으로 안 온다 / getUpdates 빈 배열봇과 1:1 대화에서 먼저 메시지를 보냈는지 확인. 봇은 사용자가 먼저 말 걸기 전엔 발송 불가
답을 보냈는데 반영 안 됨같은 봇으로 여러 인스턴스가 동시 long-poll 중인지 확인(소비자 1명만 가능)
코드 고쳤는데 옛 동작pyproject.toml version을 올린 뒤 uv tool install . --reinstall --no-cache → 클라이언트 재시작

보안

봇 토큰은 MCP 클라이언트 env(또는 비밀 파일)로만 주입. 레포·문서·로그·프론트에 절대 노출 금지. 비밀 파일은 chmod 600 + .gitignore. 노출 의심 시 BotFather /revoke로 즉시 재발급.

getUpdates는 한 번에 하나의 소비자만 받을 수 있어, 같은 봇으로 여러 인스턴스를 동시에 long-poll 하면 서로 업데이트를 가로챌 수 있다(단일 사용자 로컬 환경 기준 설계).