Permita que agentes de voz em tempo real chamem ferramentas de função e servidores MCP remotos.
Você pode adicionar ferramentas a uma sessão Realtime para que o modelo consulte dados, execute ações ou chame serviços durante uma conversa ao vivo. O cliente usa os mesmos eventos para configurar as ferramentas, tanto com um canal de dados WebRTC quanto com uma conexão WebSocket.
Use ferramentas de função quando o aplicativo precisar executar a ferramenta e retornar o resultado. Use ferramentas MCP quando quiser que a Realtime API se conecte a um servidor remoto de ferramentas.
Escolha o tipo de ferramenta
Tipo de ferramenta
Quando usar
Quem executa
function
Seu aplicativo controla a lógica de negócio, as verificações de aprovação ou o acesso a sistemas privados.
Seu cliente ou servidor recebe uma chamada de função e retorna function_call_output.
mcp com server_url
Você quer que o modelo chame ferramentas disponibilizadas por um servidor MCP remoto.
A Realtime API chama o servidor MCP remoto.
mcp com connector_id
Você usa um conector integrado legado com um modelo existente.
A Realtime API chama o conector com a autorização que você fornece.
Adicione as ferramentas em um dos dois níveis:
No nível da sessão, use session.tools em session.update se quiser disponibilizar a ferramenta durante toda a sessão.
No nível da resposta, use response.tools em response.create se precisar da ferramenta por apenas um turno.
Configure uma ferramenta de função
Prefira ferramentas de função quando a execução couber ao aplicativo. O modelo fornece os argumentos da chamada de função, e seu código executa a ação e envia o resultado de volta em um item function_call_output.
Configure uma ferramenta de função com session.update
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27constevent= { type: "session.update", session: { type: "realtime", model: "gpt-realtime-2.1", tools: [ { type: "function", name: "lookup_order", description: "Look up an order by its order number.", parameters: { type: "object", properties: { order_number: { type: "string", description: "The customer-facing order number.", }, }, required: ["order_number"], }, }, ], tool_choice: "auto", },};ws.send(JSON.stringify(event));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27event = { "type": "session.update", "session": { "type": "realtime", "model": "gpt-realtime-2.1", "tools": [ { "type": "function", "name": "lookup_order", "description": "Look up an order by its order number.", "parameters": { "type": "object", "properties": { "order_number": { "type": "string", "description": "The customer-facing order number.", } }, "required": ["order_number"], }, } ], "tool_choice": "auto", },}ws.send(json.dumps(event))
As ferramentas MCP são úteis quando um servidor MCP remoto já disponibiliza a ferramenta ou quando um modelo existente usa um conector integrado legado. Ao contrário das ferramentas de função, as ferramentas MCP são executadas pela própria Realtime API.
No Realtime, a definição de uma ferramenta MCP tem os seguintes campos:
type: "mcp"
server_label
Um dos campos server_url ou connector_id
Os campos opcionais authorization e headers
O campo opcional allowed_tools
O campo opcional require_approval
O campo opcional server_description
Este exemplo disponibiliza um servidor MCP de documentação durante toda a sessão:
O uso de connector_id está obsoleto nos modelos lançados após 1º de setembro de 2026. Use server_url para se conectar a um servidor MCP remoto ou
tunnel_id para se conectar a um servidor MCP local por meio de um
túnel MCP seguro. Os modelos existentes continuam oferecendo suporte a conectores. O exemplo abaixo usa o modelo gpt-realtime-1.5, lançado antes dessa data.
Os conectores integrados usam a mesma estrutura das ferramentas MCP, mas recebem connector_id em vez de server_url. Por exemplo, o Google Agenda usa connector_googlecalendar. No Realtime, use esses conectores integrados para operações de leitura, como pesquisar ou ler eventos ou e-mails. Informe o token de acesso OAuth do usuário em authorization e, sempre que possível, restrinja as ferramentas disponíveis com allowed_tools:
Os servidores MCP remotos
não recebem automaticamente todo o contexto da conversa,
mas podem ver qualquer dado que o modelo envie em uma chamada de ferramenta.
Limite as ferramentas disponíveis com allowed_tools e exija aprovação para qualquer ação que você não executaria automaticamente.
Fluxo de execução das ferramentas MCP no Realtime
Ao contrário das ferramentas do tipo function no Realtime, as ferramentas MCP remotas são executadas pela própria Realtime API. Seu cliente não executa a ferramenta remota nem retorna um item function_call_output. O cliente configura o acesso, monitora os eventos do ciclo de vida do MCP e pode enviar uma resposta de aprovação se o servidor a solicitar.
O fluxo típico segue estas etapas:
Você envia session.update ou response.create com uma entrada em tools cujo type é mcp.
O servidor começa a importar as ferramentas e emite mcp_list_tools.in_progress.
Enquanto a listagem estiver em andamento, o modelo só poderá chamar ferramentas já carregadas. Se quiser aguardar antes de iniciar um turno que dependa dessas ferramentas, monitore o evento mcp_list_tools.completed. O evento conversation.item.done cujo item.type é mcp_list_tools mostra os nomes das ferramentas que o servidor de fato importou. Se a importação falhar, você receberá mcp_list_tools.failed.
O usuário fala ou envia texto. O cliente cria uma resposta, ou a sessão a cria automaticamente, conforme a configuração.
Se o modelo escolher uma ferramenta MCP, você verá response.mcp_call_arguments.delta e response.mcp_call_arguments.done.
Se a ferramenta exigir aprovação, o servidor adicionará à conversa um item cujo item.type é mcp_approval_request. Seu cliente deve responder com um item mcp_approval_response.
Quando a ferramenta começar a ser executada, você verá response.mcp_call.in_progress. Se a execução for bem-sucedida, você receberá em seguida um evento response.output_item.done cujo item.type é mcp_call. Se houver falha, você receberá response.mcp_call.failed.
O evento response.done de uma resposta pode chegar antes que as chamadas MCP dessa resposta terminem. Quando a resposta e todas as suas chamadas MCP tiverem terminado, envie outro evento response.create para que o modelo use os resultados e continue a conversa. Repita essa etapa se o modelo fizer outras chamadas MCP. A Realtime API não cria essas respostas subsequentes automaticamente.
Este manipulador de eventos registra os principais eventos do ciclo de vida do MCP, mas não gerencia as respostas subsequentes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61def on_message(ws, message): event = json.loads(message) event_type = event["type"] if event_type == "mcp_list_tools.in_progress": print("Listing MCP tools for item:", event["item_id"]) return if event_type == "mcp_list_tools.completed": print("MCP tool listing complete for item:", event["item_id"]) return if event_type == "mcp_list_tools.failed": print("MCP tool listing failed for item:", event["item_id"]) return if event_type == "conversation.item.done": item = event["item"] if item["type"] == "mcp_list_tools": names = ", ".join(tool["name"] for tool in item["tools"]) print(f"MCP tools ready on {item['server_label']}: {names}") return if item["type"] == "mcp_approval_request": print("Approval required for:", item["name"], item["arguments"]) return if event_type == "response.mcp_call_arguments.done": print("Final MCP call arguments:", event["arguments"]) return if event_type == "response.mcp_call.in_progress": print("Running MCP tool for item:", event["item_id"]) return if event_type == "response.mcp_call.failed": print("MCP tool call failed for item:", event["item_id"]) return if event_type == "response.output_item.done": item = event["item"] if item["type"] == "mcp_call": print( f"MCP output from {item['server_label']}.{item['name']}:", item.get("output"), ) return if item["type"] == "message": text_parts = [ part["text"] for part in item.get("content", []) if part["type"] == "output_text" ] print("Assistant:", "".join(text_parts)) return if event_type == "response.done": print("Realtime turn complete.")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// Call for each received event. Tool results can arrive after response.done.func logMCPEvent(event realtime.RealtimeServerEventUnion) error { switch e := event.AsAny().(type) { case realtime.RealtimeErrorEvent: return fmt.Errorf("Realtime API error: %s", e.Error.Message) case realtime.McpListToolsFailed, realtime.ResponseMcpCallFailed: return fmt.Errorf("MCP failed: %s", event.Type) case realtime.ResponseOutputItemDoneEvent: item := e.Item.OfRealtimeMcpToolCall if item.Type == "mcp_call" { if item.JSON.Error.Valid() || !item.JSON.Output.Valid() { return fmt.Errorf("MCP call failed or has no output") } fmt.Fprintln(log.Writer(), "Tool output:", item.Output) } } return nil}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77completed_events = {}expected_calls = []completed_calls = {}complete = connection.find do |event| case event when OpenAI::Realtime::McpListToolsInProgress puts("Listing MCP tools for item: #{event.item_id}") when OpenAI::Realtime::McpListToolsFailed raise "MCP tool listing failed for item: #{event.item_id}" when OpenAI::Realtime::McpListToolsCompleted puts("MCP tools ready for item: #{event.item_id}") connection.response.create( output_modalities: [:text], input: [ { type: :message, role: :user, content: [ { type: :input_text, text: "Which Realtime API transport should browser clients use?" } ] } ], tool_choice: :required, parallel_tool_calls: false ) when OpenAI::Realtime::ConversationItemDone item = event.item case item when OpenAI::Realtime::RealtimeMcpListTools names = item.tools.map(&:name).join(", ") puts("MCP tools ready on #{item.server_label}: #{names}") when OpenAI::Realtime::RealtimeMcpApprovalRequest puts("Approval required for: #{item.name} #{item.arguments}") end when OpenAI::Realtime::ResponseMcpCallArgumentsDone puts("Final MCP call arguments: #{event.arguments}") when OpenAI::Realtime::ResponseMcpCallInProgress puts("Running MCP tool for item: #{event.item_id}") when OpenAI::Realtime::ResponseMcpCallCompleted puts("MCP tool call completed: #{event.item_id}") when OpenAI::Realtime::ResponseMcpCallFailed raise "MCP tool call failed: #{event.item_id}" when OpenAI::Realtime::ResponseOutputItemDoneEvent item = event.item case item when OpenAI::Realtime::RealtimeMcpToolCall raise "MCP tool call failed" if item.error || item.output.nil? completed_calls[item.id] = true puts("MCP output from #{item.server_label}.#{item.name}: #{item.output}") when OpenAI::Realtime::RealtimeConversationItemAssistantMessage text = item.content.filter_map do |content| content.text if content.type == :output_text end.join puts("Assistant: #{text}") end when OpenAI::Realtime::RealtimeErrorEvent raise "Realtime API error: #{event.error.message}" when OpenAI::Realtime::ResponseDoneEvent raise "Realtime response did not complete" unless event.response.status == :completed expected_calls.replace(Array(event.response.output).grep(OpenAI::Realtime::RealtimeMcpToolCall).map(&:id)) raise "The response did not call an MCP tool" if expected_calls.empty? completed_events[:response] = true end if completed_events[:response] && expected_calls.all? { |id| completed_calls[id] } puts("Realtime turn complete.") true else false endendraise "Connection closed before the MCP tool result arrived" unless complete
Falhas comuns
mcp_list_tools.failed: a Realtime API não conseguiu importar ferramentas do servidor remoto ou do conector. Verifique o valor de server_url ou connector_id, a autenticação, a conexão com o servidor e os nomes das ferramentas que você especificou em allowed_tools.
response.mcp_call.failed: o modelo selecionou uma ferramenta, mas a chamada não foi concluída. Examine o conteúdo do evento e o item mcp_call recebido em seguida para identificar erros de protocolo MCP, de execução ou de transporte.
mcp_approval_request sem um mcp_approval_response correspondente: a chamada da ferramenta fica pendente até que o cliente a aprove ou rejeite explicitamente.
Um turno começa enquanto mcp_list_tools.in_progress ainda está ativo: nesse turno, o modelo só pode usar ferramentas que já terminaram de carregar.
Uma resposta usa tool_choice: "required", mas nenhuma ferramenta está disponível no momento: o modelo não tem nenhuma ferramenta que possa chamar. Aguarde mcp_list_tools.completed, confirme que pelo menos uma ferramenta foi importada ou use outro valor de tool_choice nos turnos que não exigem uma ferramenta.
A validação da definição da ferramenta MCP falha antes do início da importação: as causas comuns incluem repetir um server_label no mesmo array tools, definir tanto server_url quanto connector_id, omitir ambos na solicitação inicial de criação da sessão, usar um connector_id inválido ou enviar authorization e headers.Authorization juntos. Para conectores, nunca envie headers.Authorization.
Aprove ou rejeite chamadas de ferramentas MCP
Se uma ferramenta exigir aprovação, a Realtime API inserirá um item mcp_approval_request na conversa. Para prosseguir, envie um novo evento conversation.item.create cujo item.type seja mcp_approval_response.
1
2
3
4
5
6
7
8
9# Use the ID from the received MCP approval-request item.approval_request_id = item.idconnection.conversation.items.create( type: :mcp_approval_response, id: "approval_#{SecureRandom.hex(8)}", approval_request_id: approval_request_id, approve: true)
Se você rejeitar a solicitação, defina approve como false e, se quiser, inclua uma justificativa em reason.
Use o MCP em uma única resposta
Se o MCP só precisar ficar disponível por um turno, adicione o mesmo objeto de ferramenta MCP a response.tools em vez de session.tools:
Isso é útil quando apenas uma resposta precisa de contexto externo ou quando turnos diferentes devem usar servidores MCP diferentes.
Reutilize um rótulo de servidor já definido
server_label identifica de forma estável a definição de uma ferramenta na sessão Realtime atual. Depois de definir um servidor ou conector com server_label e um dos campos server_url ou connector_id, basta informar o mesmo rótulo nos eventos session.update ou response.create subsequentes. Com esse server_label, a Realtime API reutiliza a definição anterior sem exigir que você envie novamente o objeto completo da ferramenta.
A definição só pode ser reutilizada na mesma sessão. Se você iniciar uma nova sessão Realtime, envie novamente a definição MCP completa para que o servidor possa importar a lista de ferramentas.