Microsoft Teams
anchor alias
anchor alias
Microsoft Teams 설정
Hermes Agent을 Microsoft Teams에 봇으로 연결. Slack의 Socket Mode와 달리 Teams는 공개 HTTPS webhook 호출로 메시지 전달. 인스턴스에 공개 접근 가능한 endpoint 필요 — dev tunnel(로컬 개발) 또는 실제 도메인(프로덕션).
일반 봇 대화 대신 Microsoft Graph 이벤트의 세션 요약 필요? 전용 설정 페이지 사용: Teams Meetings.
봇 응답 방식
| 컨텍스트 | 동작 |
|---|---|
| 개인 채팅 (DM) | 봇이 모든 메시지에 응답. @mention 불필요. |
| 그룹 채팅 | @mention 시에만 봇 응답. |
| 채널 | @mention 시에만 봇 응답. |
Teams는 @mention을 <at>BotName</at> 태그 포함 일반 메시지로 전달. Hermes가 처리 전 자동 제거.
Step 1: Teams CLI 설치
@microsoft/teams.cli가 봇 등록 자동화 — Azure portal 불필요.
npm install -g @microsoft/teams.cli@preview
teams login
로그인 확인 및 본인 AAD object ID 찾기(TEAMS_ALLOWED_USERS에 필요):
teams status --verbose
Step 2: Webhook 포트 노출
Teams는 localhost로 메시지 전달 불가. 로컬 개발 시 터널 도구로 공개 HTTPS URL 확보. 기본 포트 3978 — 필요 시 TEAMS_PORT로 변경.
# devtunnel (Microsoft)
devtunnel create hermes-bot --allow-anonymous
devtunnel port create hermes-bot -p 3978 --protocol https # replace 3978 with TEAMS_PORT if changed
devtunnel host hermes-bot
# ngrok
ngrok http 3978 # replace 3978 with TEAMS_PORT if changed
# cloudflared
cloudflared tunnel --url http://localhost:3978 # replace 3978 with TEAMS_PORT if changed
출력에서 https:// URL 복사 — 다음 단계에서 사용. 개발 중 터널 계속 실행.
프로덕션은 봇 endpoint를 서버 공개 도메인으로 지정 (Production Deployment 참조).
Step 3: 봇 생성
teams app create \
--name "Hermes" \
--endpoint "https://<your-tunnel-url>/api/messages"
CLI가 CLIENT_ID, CLIENT_SECRET, TENANT_ID 출력 + Step 6용 설치 링크. client secret 저장 — 재표시 안 됨.
Step 4: 환경 변수 설정
~/.hermes/.env에 추가:
# Required
TEAMS_CLIENT_ID=<your-client-id>
TEAMS_CLIENT_SECRET=<your-client-secret>
TEAMS_TENANT_ID=<your-tenant-id>
# Restrict access to specific users (recommended)
# Use AAD object IDs from `teams status --verbose`
TEAMS_ALLOWED_USERS=<your-aad-object-id>
Step 5: 게이트웨이 시작
HERMES_UID=$(id -u) HERMES_GID=$(id -g) docker compose up -d gateway
게이트웨이 시작. 기본 webhook 포트 3978 (TEAMS_PORT로 변경). 실행 확인:
curl http://localhost:3978/health # should return: ok
docker logs -f hermes
확인:
[teams] Webhook server listening on 0.0.0.0:3978/api/messages
Step 6: Teams에 앱 설치
teams app get <teamsAppId> --install-link
출력된 링크를 브라우저에서 열기 — Teams 클라이언트에서 직접 열림. 설치 후 봇에 DM 전송 — 준비 완료.
설정 레퍼런스
환경 변수
| 변수 | 설명 |
|---|---|
TEAMS_CLIENT_ID | Azure AD App (client) ID |
TEAMS_CLIENT_SECRET | Azure AD client secret |
TEAMS_TENANT_ID | Azure AD tenant ID |
TEAMS_ALLOWED_USERS | 봇 사용 허용 AAD object ID 쉼표 구분 목록 |
TEAMS_ALLOW_ALL_USERS | true 설정 시 allowlist 건너뛰고 모두 허용 |
TEAMS_HOME_CHANNEL | cron/proactive 메시지 전달용 conversation ID |
TEAMS_HOME_CHANNEL_NAME | 홈 채널 표시 이름 |
TEAMS_PORT | Webhook 포트 (기본값: 3978) |
config.yaml
대안으로 ~/.hermes/config.yaml로 설정:
platforms:
teams:
enabled: true
extra:
client_id: "your-client-id"
client_secret: "your-secret"
tenant_id: "your-tenant-id"
port: 3978
기능
대화형 승인 카드
에이전트가 위험 가능 명령 실행 필요 시, /approve 입력 요청 대신 버튼 4개 포함 Adaptive Card 전송:
- Allow Once — 이 특정 명령 승인
- Allow Session — 이 패턴을 세션 종료까지 승인
- Always Allow — 이 패턴을 영구 승인
- Deny — 명령 거부
버튼 클릭 시 승인이 인라인 처리되고 카드가 결정 내용으로 대체됨.
세션 요약 전달 (Teams Meeting Pipeline)
Teams meeting pipeline plugin 활성화 시, 이 adapter가 세션 요약 외부 전달도 처리 — Teams 통합 표면 하나, 둘 아님. 세션 전사 요약 후 writer가 선택한 Teams 대상에 요약 게시.
파이프라인 요약 전달은 봇 설정과 함께 teams 플랫폼 엔트리 아래 설정:
platforms:
teams:
enabled: true
extra:
# existing bot config (client_id, client_secret, tenant_id, port)...
# Meeting summary delivery (only used when the teams_pipeline plugin is enabled)
delivery_mode: "graph" # or "incoming_webhook"
# For delivery_mode: graph — pick ONE of:
chat_id: "19:meeting_..." # post into a Teams chat
# team_id: "..." # OR post into a channel
# channel_id: "..."
# access_token: "..." # optional; falls back to MSGRAPH_* app credentials
# For delivery_mode: incoming_webhook:
# incoming_webhook_url: "https://outlook.office.com/webhook/..."
| 모드 | 사용 시기 | 트레이드오프 |
|---|---|---|
incoming_webhook | 정적 Teams 생성 URL로 "이 채널에 요약 게시" 단순 처리. | 스레드 회신 없음, 반응 없음, webhook 설정 ID로 표시. |
graph | Microsoft Graph 통해 봇 ID로 채널 스레드 게시 또는 1:1/그룹 채팅 게시. | ChannelMessage.Send (채널) 또는 Chat.ReadWrite.All (채팅) 애플리케이션 권한 포함 Graph app registration 필요. |
teams_pipeline 플러그인 미활성화 시 이 설정은 비활성 — 파이프라인 런타임이 Graph webhook ingress에 바인딩될 때만 작동.
프로덕션 배포
영구 서버는 devtunnel 건너뛰고 서버 공개 HTTPS endpoint로 봇 등록:
teams app create \
--name "Hermes" \
--endpoint "https://your-domain.com/api/messages"
이미 봇 생성됐고 endpoint만 갱신 필요 시:
teams app update --id <teamsAppId> --endpoint "https://your-domain.com/api/messages"
설정 포트(TEAMS_PORT, 기본 3978)가 인터넷에서 접근 가능하고 TLS 인증서 유효한지 확인 — Teams는 self-signed 인증서 거부.
문제 해결
| 문제 | 해결 |
|---|---|
health endpoint 작동하나 봇 무응답 | 터널 실행 중인지, 봇 메시징 endpoint가 터널 URL과 일치하는지 확인 |
로그에 KeyError: 'teams' | 컨테이너 재시작 — 현재 버전에서 수정됨 |
| 봇이 인증 오류 응답 | TEAMS_CLIENT_ID, TEAMS_CLIENT_SECRET, TEAMS_TENANT_ID 모두 정확히 설정됐는지 확인 |
No inference provider configured | ~/.hermes/.env에 ANTHROPIC_API_KEY (또는 다른 provider 키) 설정됐는지 확인 |
| 봇이 메시지 수신하나 무시 | AAD object ID가 TEAMS_ALLOWED_USERS에 없을 수 있음. teams status --verbose 실행으로 확인 |
| 재시작 시 터널 URL 변경 | devtunnel URL은 명명된 터널(devtunnel create hermes-bot) 사용 시 영구. ngrok 및 cloudflared는 유료 플랜 없으면 실행마다 새 URL 생성 — 변경 시 teams app update로 봇 endpoint 갱신 |
| Teams에 "This bot is not responding" 표시 | Webhook이 오류 반환. docker logs hermes에서 traceback 확인 |
로그에 [teams] Failed to connect | SDK 인증 실패. 자격 증명 및 tenant ID가 teams login에서 사용한 계정과 일치하는지 재확인 |
보안
TEAMS_ALLOWED_USERS 항상 설정, 인가된 사용자의 AAD object ID 포함. 미설정 시 봇 발견/설치 가능한 누구든 상호작용 가능.
TEAMS_CLIENT_SECRET를 비밀번호처럼 취급 — Azure portal 또는 Teams CLI로 주기적 교체.
- 자격 증명을
~/.hermes/.env에 저장, 권한600(chmod 600 ~/.hermes/.env) - 봇은
TEAMS_ALLOWED_USERS에 등록된 사용자 메시지만 수락; 인가되지 않은 메시지는 조용히 폐기 - 공개 endpoint(
/api/messages)는 Teams Bot Framework로 인증 — 유효 JWT 없는 요청 거부