Skip to content

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):

Terminal window
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.

Custom function toolRemote MCP server
ExecutesIn your process (the bridge)On OpenAI’s side, against the remote server
LatencyYour handler + one round tripHandled inside the Realtime API
CredentialsStay in your processauthorization is forwarded to OpenAI with the session config
Best forYour own systems (CRM, telephony actions, StandIn-side effects)Third-party services that already speak MCP
SetupCode (library embedding)Env or code