본문으로 건너뛰기

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_IDAzure AD App (client) ID
TEAMS_CLIENT_SECRETAzure AD client secret
TEAMS_TENANT_IDAzure AD tenant ID
TEAMS_ALLOWED_USERS봇 사용 허용 AAD object ID 쉼표 구분 목록
TEAMS_ALLOW_ALL_USERStrue 설정 시 allowlist 건너뛰고 모두 허용
TEAMS_HOME_CHANNELcron/proactive 메시지 전달용 conversation ID
TEAMS_HOME_CHANNEL_NAME홈 채널 표시 이름
TEAMS_PORTWebhook 포트 (기본값: 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로 표시.
graphMicrosoft 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/.envANTHROPIC_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 connectSDK 인증 실패. 자격 증명 및 tenant ID가 teams login에서 사용한 계정과 일치하는지 재확인

보안

{#security}

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 없는 요청 거부