@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: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).
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: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:- Set the identity’s Agent voice URL to where the bridge listens.
- Set
WORKER_SHARED_SECRETto the shared secret from pairing - both sides must match exactly, or the WebSocket handshake is rejected with401. - 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.