Skip to main content
@komaa/openai-msteams-bridge brings an OpenAI Realtime voice agent (gpt-realtime - speech-to-speech: STT + LLM + TTS + turn-taking in one model) onto a Microsoft Teams call. It is the OpenAI analogue of the ElevenLabs and LiveKit bridges: it hosts the HMAC WebSocket that StandIn connects to, then relays audio to and from an OpenAI Realtime session.
Like the other bridges, this is a standalone Node service, not a framework plugin. There is also no agent to configure in a dashboard: the bridge configures each Realtime session itself (model, voice, instructions, VAD, tools) from environment variables. Two variables and it runs.

How it works

The bridge opens one Realtime WebSocket per call (wss://api.openai.com/v1/realtime), configures the session with your instructions plus per-call caller context, and relays audio both ways. The Teams wire is PCM 16 kHz; the Realtime API speaks PCM 24 kHz only, so the bridge converts at that one boundary with a built-in anti-aliased resampler (no codecs, no external dependencies). Caller barge-in maps onto the model’s own interruption handling, and stale “ghost” audio is dropped so nothing plays after the caller cuts in. The agent gets four built-in tools automatically (end_call, look for vision, show_image, express for avatar emotion) - and you can register your own function tools or pass remote MCP servers the Realtime API executes server-side. See Extending the agent’s tools.

Requirements

  • Node.js >= 20.
  • An OpenAI API key with Realtime access (platform.openai.com).
  • A StandIn subscription (standin.komaa.com, free package works) - the hosted media bridge that joins the Teams call and connects to this service. See Architecture.
  • Your own Microsoft Teams bot connected to StandIn - the Teams setup walks through the Azure bot, the app package, and the upload. To try it without one, use the sandbox.

Run

Env-configured, no install step needed:
OPENAI_API_KEY=sk-... \
WORKER_SHARED_SECRET=... \
npx @komaa/openai-msteams-bridge
Optionally shape the agent (all have defaults):
OPENAI_VOICE=marin
OPENAI_INSTRUCTIONS="You are Komaa's friendly receptionist. Keep replies short."
OPENAI_FIRST_MESSAGE="Hello! You've reached Komaa. How can I help?"
Or add it to a project (npm i @komaa/openai-msteams-bridge) and embed it - see the library API for the programmatic surface, custom tools, and a custom vision hook. The bridge binds its media WebSocket (default ws://<host>:8080/voice/msteams/stream; StandIn appends /{callId} per call).
The OpenAI Realtime API caps a session at 60 minutes server-side. Set MAX_CALL_MINUTES below 60 so the bridge’s own governor ends long calls with a spoken goodbye instead of an abrupt drop - the bridge warns at startup when it would not.

Expose the WebSocket (Agent voice URL)

StandIn connects to the bridge from the internet, so the port must be reachable - a public host or a tunnel. With Tailscale Funnel:
tailscale funnel --bg --https=8080 8080
Your Agent voice URL is then:
wss://<machine>.<tailnet>.ts.net:8080/voice/msteams/stream

Connect it to StandIn

Register that URL (with a matching shared secret) on your identity in the dashboard, or use the sandbox to try it without your own Teams bot:
  1. Set the identity’s Agent voice URL to where the bridge listens.
  2. Set WORKER_SHARED_SECRET to the shared secret from pairing - both sides must match exactly, or the WebSocket handshake is rejected with 401.
  3. Place a Teams call (or join the sandbox meeting). StandIn joins, connects to the bridge, and your Realtime agent answers.

Try the runnable example

The fastest way to understand the bridge is to run its example project - a minimal, working embedding you can copy straight into your own repo.

Run the example, step by step

Clone examples/basic-bridge, fill in two environment variables, expose the port, connect it to StandIn, and place a call - with the vision hook and a custom lookup_order tool explained along the way.
Next: the full configuration reference - every environment variable, the call governor, vision, and MCP servers. Deep protocol and library docs live on the project site.

Docs site

npm

Source