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:

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

  1. Start the dev server: pnpm dev
  2. Open http://localhost:<port>/.well-known/oauth-authorization-server
  3. You should see the OAuth metadata JSON
  4. Connect with an MCP client that supports OAuth

Testing Chat Tools

After connecting a test user via MCP Inspector:

  1. Discover ids — call list_teams to find team ids and list_chats to find chat ids. Both return ids alongside display names and metadata so you can identify the right target unambiguously.

  2. Read messages — call get_chat_messages with a chat id, or get_channel_messages with a team id and channel id (use list_channels to find channel ids). Both return paginated message history.

  3. Search — call search_messages with a keyword query. Results span both chats and channels; pass detail=full to hydrate full message content.

  4. Send — call send_chat_message with a chat id to post to a 1:1 or group chat, or send_channel_message with 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

  1. Ensure dev tunnel is running
  2. Complete OAuth flow to create a user
  3. The system automatically creates a Microsoft Graph subscription
  4. Hold a Teams meeting with transcription enabled
  5. 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:

Webhook not received: