Teams MCP - Local Development — Unique AI Documentation
Teams MCP - Local Development
This guide walks through setting up the Teams MCP Server for local development and testing.
Prerequisites
| Requirement | Version | Purpose |
|---|---|---|
| Node.js | 20+ | Runtime |
| pnpm | 9+ | Package manager |
| Docker | 24+ | Run PostgreSQL and RabbitMQ |
| Azure CLI | Latest | Configure Entra app registration |
| MCP Inspector | 0.17.2 | MCP Client |
A public reverse proxy, recommended:
- Azure Dev Tunnels for webhook testing
Quick Start
# Clone and install
git clone git@github.com:Unique-AG/connectors.git
cd services/teams-mcp
pnpm install
# Start infrastructure
docker compose up -d
# Configure environment
cp .env.example .env
# Edit .env with your values (see below)
# Run migrations
pnpm db:migrate
# Start development server
pnpm dev
The server starts at the configured port.
Infrastructure Setup
Docker Compose
The included docker-compose.yaml provides PostgreSQL and RabbitMQ:
docker compose up -d
| Service | Credentials |
|---|---|
| PostgreSQL | postgres:postgres |
| RabbitMQ | guest:guest |
| RabbitMQ Management | guest:guest |
Microsoft Entra App Registration
You need a Microsoft Entra ID app registration for OAuth. See Authentication Setup for detailed instructions.
For local development, configure:
| Setting | Value |
|---|---|
| Redirect URI | http://localhost:<port>/auth/callback |
| Supported account types | Your organization only |
Environment Configuration
Create .env from the template:
cp .env.example .env
Required Variables
# Application
SELF_URL=http://localhost:<port>
# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/teams_mcp
# RabbitMQ
AMQP_URL=amqp://guest:guest@localhost:5672
# Microsoft (from Entra app registration)
MICROSOFT_CLIENT_ID=<your-client-id>
MICROSOFT_CLIENT_SECRET=<your-client-secret>
MICROSOFT_WEBHOOK_SECRET=<generate-128-char-hex>
MICROSOFT_PUBLIC_WEBHOOK_URL=<your-tunnel-url> # See webhook testing below
# Security (generate with: openssl rand -hex 32)
AUTH_HMAC_SECRET=<64-char-hex>
ENCRYPTION_KEY=<64-char-hex>
# Unique API (for local testing, use external mode)
UNIQUE_SERVICE_AUTH_MODE=external
UNIQUE_API_BASE_URL=http://localhost:8092/public/
UNIQUE_INGESTION_SERVICE_BASE_URL=http://localhost:8091
Generating Secrets
# For MICROSOFT_WEBHOOK_SECRET (128 chars)
openssl rand -hex 64
# For AUTH_HMAC_SECRET and ENCRYPTION_KEY (64 chars each)
openssl rand -hex 32
Webhook Testing
Microsoft Graph webhooks require a publicly accessible HTTPS endpoint. For local development, use Azure Dev Tunnels:
Setup Dev Tunnel
# Install (macOS)
brew install azure-dev-tunnels
# Login
devtunnel user login
# Create persistent tunnel
devtunnel create teams-mcp --allow-anonymous
# Start tunnel
devtunnel port create teams-mcp -p <port>
devtunnel host teams-mcp
Configure Environment
Set MICROSOFT_PUBLIC_WEBHOOK_URL to your tunnel URL:
MICROSOFT_PUBLIC_WEBHOOK_URL=https://abc123.devtunnels.ms
This URL is used when creating Microsoft Graph subscriptions.
Development Workflow
Available Scripts
| Script | Description |
|---|---|
pnpm dev |
Start with hot reload |
pnpm build |
Build for production |
pnpm test |
Run unit tests |
pnpm test:watch |
Run tests in watch mode |
pnpm test:coverage |
Run tests with coverage |
pnpm test:e2e |
Run end-to-end tests |
pnpm db:generate |
Generate migrations from schema changes |
pnpm db:migrate |
Apply pending migrations |
pnpm db:studio |
Open Drizzle Studio (database GUI) |
pnpm style |
Check code style (Biome) |
pnpm style:fix |
Fix code style issues |
Testing the OAuth Flow
- Start the dev server:
pnpm dev - Open
http://localhost:<port>/.well-known/oauth-authorization-server - You should see the OAuth metadata JSON
- Connect with an MCP client that supports OAuth
Testing Chat Tools
After connecting a test user via MCP Inspector:
Discover ids — call
list_teamsto find team ids andlist_chatsto find chat ids. Both return ids alongside display names and metadata so you can identify the right target unambiguously.Read messages — call
get_chat_messageswith a chat id, orget_channel_messageswith a team id and channel id (uselist_channelsto find channel ids). Both return paginated message history.Search — call
search_messageswith a keyword query. Results span both chats and channels; passdetail=fullto hydrate full message content.Send — call
send_chat_messagewith a chat id to post to a 1:1 or group chat, orsend_channel_messagewith a team id and channel id to post to a channel. Verify the message appears in the Teams client.
All tool inputs accept ids only (no display-name lookup at call time) — always use the list_* tools first to obtain the correct id.
Testing Webhooks
- Ensure dev tunnel is running
- Complete OAuth flow to create a user
- The system automatically creates a Microsoft Graph subscription
- Hold a Teams meeting with transcription enabled
- After the meeting, check logs for webhook notifications
Database Inspection
Use Drizzle Studio to inspect the database:
pnpm db:studio
Opens a browser UI at https://local.drizzle.studio.
Debugging
Common Issues
OAuth redirect mismatch:
- Verify
SELF_URLmatches the redirect URI in your Entra app registration - Include the exact path:
http://localhost:<port>/auth/callback
Webhook not received:
- Check dev tunnel is running and accessible
- Verify
MICROSOFT_PUBLIC_WEBHOOK_URLis set correctly - Check Microsoft Graph subscription was created (see logs)