{
  "markdown": "# Microsoft Teams Channel for Claude Code\n\nConnect a Claude Code session to Microsoft Teams via an MCP server running on Bun. Messages from Teams are delivered to your Claude session in real time; use the `reply`, `react`, and `edit_message` tools to respond.\n\n## Prerequisites\n\n- [Bun](https://bun.sh) runtime: `curl -fsSL https://bun.sh/install | bash`\n- An Azure Bot registration ([create one here](https://portal.azure.com/#create/Microsoft.AzureBot))\n  - Copy the **App ID**, **App Password**, and **Tenant ID**\n  - See [Bot permissions](#bot-permissions) for required scopes\n- A public HTTPS endpoint for the webhook (e.g., [Tailscale Funnel](https://tailscale.com/kb/1223/funnel), VPN, or Azure App Service) — see [Security](#security-webhook-authentication)\n\n## Setup\n\n### 1. Clone the plugin\n\n```bash\ngit clone https://github.com/daocoding/claude-teams.git\ncd claude-teams\n```\n\n### 2. Configure credentials\n\nCreate the state directory and save your Azure Bot credentials:\n\n```bash\nmkdir -p ~/.claude/channels/teams\n```\n\nThen launch Claude Code and run:\n\n```\n/teams:configure <APP_ID> <APP_PASSWORD> <TENANT_ID>\n```\n\nOr write `~/.claude/channels/teams/.env` manually (see [.env.example](.env.example)).\n\n### 3. Expose the webhook\n\nThe server listens on port **3980** by default. Expose it via HTTPS and register the URL in your Azure Bot's **Messaging endpoint**:\n\n```\nhttps://your-domain.com/api/messages\n```\n\n> **Important:** Do not use a raw public URL without network-level security. See [Security: Webhook Authentication](#security-webhook-authentication).\n\n### 4. Launch with the channel\n\n**Development / pre-approval (now):**\n\n```bash\nclaude --load-development-channels /path/to/claude-teams\n```\n\nThis loads the plugin directly from your local clone.\n\n**Official plugin (future — once approved by Anthropic):**\n\n```bash\nclaude --channels plugin:teams-channel\n```\n\n### 5. Pair a user\n\n1. Have the Teams user DM your bot — they'll receive a 6-character pairing code\n2. In your Claude Code terminal, run: `/teams:access pair <CODE>`\n3. Once all users are paired, lock it down: `/teams:access policy allowlist`\n\n## Tools\n\n| Tool | Description |\n|------|-------------|\n| `reply` | Send a message to a Teams conversation. Pass `conversation_id` from the inbound message. Optionally pass `reply_to` (activity_id) for threading. |\n| `react` | React with an emoji (sent as a threaded reply — Teams Bot API has limited native reaction support). |\n| `edit_message` | Update a previously sent bot message. Edits don't trigger push notifications. |\n| `download_attachment` | Download an attachment by URL to the local inbox. Returns the file path. |\n\n## Environment variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `MICROSOFT_APP_ID` | — | Azure Bot App ID (required) |\n| `MICROSOFT_APP_PASSWORD` | — | Azure Bot App Password (required) |\n| `MICROSOFT_TENANT_ID` | — | Azure AD Tenant ID |\n| `TEAMS_WEBHOOK_PORT` | `3980` | HTTP port for Bot Framework webhook |\n| `TEAMS_WEBHOOK_PATH` | `/api/messages` | Webhook URL path |\n| `TEAMS_STATE_DIR` | `~/.claude/channels/teams` | State directory |\n\n## Access control\n\nSee [ACCESS.md](ACCESS.md) for full details.\n\n- **DM policy**: `pairing` (default) → `allowlist` (production)\n- **Group chats**: must be explicitly added via `/teams:access group add <id>`\n- **Pending entries**: auto-expire after 24 hours\n\n## How it works\n\n```\nTeams User  ──Bot Framework──▶  Webhook (Bun HTTP)  ──MCP notification──▶  Claude Code\n                                                                              │\nClaude Code  ──MCP tool call──▶  reply/react/edit  ──Bot Framework API──▶  Teams User\n```\n\nThe server runs as an MCP server connected to Claude Code via stdio. It simultaneously runs an HTTP server to receive Bot Framework webhook callbacks. Inbound messages are delivered as `notifications/claude/channel` MCP notifications; outbound messages use the Bot Framework REST API.\n\n## Roadmap\n\n- **Multi-user CLI sessions** — route non-owner conversations to separate `claude --print --resume` processes, so multiple Teams users can interact with the bot concurrently\n- **Owner DM routing** — designate one conversation for live MCP delivery while others get independent CLI sessions\n- **Group workspace isolation** — sandboxed working directories per group chat\n- **Outbound file attachments** — send files from Claude to Teams\n- **Adaptive Cards** — rich card formatting for structured responses\n- **JWT validation** — verify Bot Framework tokens for production-grade webhook security\n\n## Limitations\n\n- **No JWT validation**: see [Security: Webhook Authentication](#security-webhook-authentication) for mitigations.\n- **No message history**: the Bot Framework webhook only delivers new messages. The assistant cannot retrieve earlier messages.\n- **Reactions**: Teams Bot API has limited reaction support. The `react` tool sends the emoji as a threaded reply instead.\n- **File attachments**: images and files are downloaded to `~/.claude/channels/teams/inbox/`. Images can be viewed with the Read tool. Sending files from Claude to Teams is not yet supported.\n## Bot Permissions\n\nThis plugin uses **minimal permissions** — only what's needed for messaging.\n\n### Azure Bot Framework scope\n\nThe bot authenticates with `https://api.botframework.com/.default`, which grants:\n\n- **Send and receive messages** — reply to conversations, send typing indicators\n- **Edit messages** — update previously sent bot messages\n- **No Graph API access** — the bot cannot read email, calendar, files, or any other Microsoft 365 data\n\n### Teams app manifest permissions\n\nWhen registering the bot in Teams Admin Center or via app manifest:\n\n| Permission | Why |\n|-----------|-----|\n| `TeamMessagingSettings.Read` | Receive messages from chats |\n| `ChatMessage.Send` | Send replies back |\n\nThe bot **does not** require or request:\n\n- `User.Read.All` or any directory permissions\n- `Files.Read` / `Sites.Read` or any SharePoint/OneDrive access\n- `Mail.Read` / `Calendars.Read` or any Exchange access\n- Admin consent (single-tenant bots only need user-level consent)\n\n### Single-tenant vs multi-tenant\n\nThis plugin is designed for **single-tenant** deployment (your own Azure AD tenant). Set `MICROSOFT_TENANT_ID` in your `.env` to restrict authentication to your tenant only. Do not leave it empty in production — an empty tenant ID falls back to `botframework.com` which allows any tenant.\n\n## Security: Webhook Authentication\n\n**This plugin does not validate Bot Framework JWT tokens on incoming webhook requests.** This means anyone who discovers your webhook URL can send forged messages that will be delivered to your Claude Code session as if they came from a legitimate Teams user.\n\n**Risk:** An attacker could impersonate an approved user or inject arbitrary prompts into your session.\n\n**Recommended mitigations (use at least one):**\n\n1. **Network-level security (strongly recommended)** — expose the webhook only through [Tailscale Funnel](https://tailscale.com/kb/1223/funnel), a VPN, or Azure VNET. This ensures only trusted networks can reach the endpoint.\n2. **Firewall rules** — restrict inbound traffic to [Microsoft's Bot Framework IP ranges](https://learn.microsoft.com/en-us/azure/bot-service/bot-service-resources-faq-security).\n3. **Reverse proxy with auth** — place the webhook behind nginx/Caddy with mutual TLS or basic auth.\n\n**Do not expose the webhook on a public URL (e.g., raw ngrok) without one of the above.** JWT validation is on the [roadmap](#roadmap).\n\n## License\n\nApache-2.0\n",
  "bytes": 7567,
  "sha": "9c1e06701b3a05a656f6eef465f52e7abe9726fa2cbfe0f0e3cc15bc7f2a898b",
  "repo_slug": "daocoding/claude-teams",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_daocoding_claude_teams_teams_channel_6f0e3f79/readme"
}