Extending the Agent's Tools
The four built-in tools are just the default registry. The Realtime API’s function calling is its plugin mechanism, and the bridge exposes it two ways - both merged into every session’s tools array:
flowchart LR
Model["gpt-realtime<br/>(decides to call a tool)"]
Bridge["this bridge"]
You["your handler<br/>(in-process)"]
MCP["remote MCP server<br/>(dialed by OpenAI)"]
Model -- "function call" --> Bridge -- "params" --> You -- "string result" --> Bridge -- "function_call_output" --> Model
Model -- "mcp tool call" --> MCP --> Model
Custom function tools (the bridge executes them)
Section titled “Custom function tools (the bridge executes them)”Register a name, a JSON schema and a handler; when the model calls the tool, the handler runs in your process and its returned string goes back as the tool output. A thrown error becomes an error output the model can recover from - it never crashes the call.
import { loadConfig, startServer, type CustomTool } from "@komaa/openai-msteams-bridge";
const tools: CustomTool[] = [ { name: "lookup_order", description: "Look up the status of a customer order by its order number.", parameters: { type: "object", properties: { orderNumber: { type: "string", description: "e.g. KO-1234" } }, required: ["orderNumber"], }, async handler({ orderNumber }, ctx) { ctx.log.info(`lookup_order ${String(orderNumber)}`); return await crm.orderStatus(String(orderNumber)); // the agent speaks this }, }, { name: "transfer_call", description: "Offer to transfer the caller to a human. Call when the caller asks for a person.", parameters: { type: "object", properties: {}, required: [] }, handler: (_params, ctx) => { notifyHumanQueue(ctx.callId); return "A colleague has been notified and will join shortly. Let the caller know."; }, },];
startServer(loadConfig(), undefined, undefined, { tools });The handler context carries per-call state: { callId, participantCount, recordingActive, log }.
Rules and behavior:
- Names must not collide with the built-ins (
end_call,express,show_image,look); collisions and duplicate names fail at startup, not mid-call. - Return a string - it is the model’s tool result, so write it the way you would brief the agent (“Order KO-1 shipped yesterday”, not JSON dumps, unless the model should read structure).
- Keep handlers fast. The model (and the caller) waits on the result. Enforce your own timeout for slow backends and return a graceful failure string.
- After every tool result the bridge requests a follow-up response, so the agent speaks the outcome without a special prompt.
The example project ships a runnable lookup_order registration.
Remote MCP servers (the Realtime API executes them)
Section titled “Remote MCP servers (the Realtime API executes them)”Pass MCP tool entries and OpenAI dials the server and runs its tools server-side - the bridge does nothing at call time. This works with any remote MCP server and with OpenAI’s built-in connectors, and is the closest thing to a tool marketplace available on the Realtime wire.
Via env (JSON array):
OPENAI_MCP_SERVERS='[{"server_label":"calendar","server_url":"https://mcp.example.com/sse","allowed_tools":["list_events","create_event"]}]'Or programmatically:
startServer(loadConfig(), undefined, undefined, { mcpServers: [{ server_label: "calendar", server_url: "https://mcp.example.com/sse", allowed_tools: ["list_events", "create_event"], authorization: process.env.MCP_CALENDAR_TOKEN, }],});Entries pass through to the session’s tools array with type: "mcp". Validation is fail-loud at startup: server_label is required and server_url must be https.
Which extension point to use
Section titled “Which extension point to use”| Custom function tool | Remote MCP server | |
|---|---|---|
| Executes | In your process (the bridge) | On OpenAI’s side, against the remote server |
| Latency | Your handler + one round trip | Handled inside the Realtime API |
| Credentials | Stay in your process | authorization is forwarded to OpenAI with the session config |
| Best for | Your own systems (CRM, telephony actions, StandIn-side effects) | Third-party services that already speak MCP |
| Setup | Code (library embedding) | Env or code |