For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
기본 탐색 메뉴
Theme

Realtime에서 도구 사용하기

실시간 음성 에이전트가 함수 도구와 원격 MCP 서버를 호출하도록 설정하세요.

Realtime 세션에 도구를 추가하면 모델이 실시간 대화 중에 데이터를 조회하거나 작업을 수행하거나 서비스를 호출할 수 있습니다. 클라이언트가 WebRTC 데이터 채널을 사용하든 WebSocket을 사용하든 도구 설정에 사용하는 이벤트는 같습니다.

애플리케이션에서 도구를 실행하고 결과를 반환하려면 함수 도구를 사용하세요. Realtime API가 대신 원격 도구 서버에 연결하도록 하려면 MCP 도구를 사용하세요.

도구 유형 선택하기

도구 유형 사용 조건 실행 주체와 동작
function 애플리케이션에서 비즈니스 로직, 승인 확인 또는 비공개 시스템 접근을 처리합니다. 클라이언트나 서버가 함수 호출을 받아 function_call_output을 반환합니다.
mcp와 server_url 모델이 원격 MCP 서버에서 제공하는 도구를 호출해야 합니다. Realtime API가 원격 MCP 서버를 호출합니다.
mcp와 connector_id 기존 모델에서 레거시 기본 제공 커넥터를 사용합니다. Realtime API가 개발자가 제공한 권한으로 커넥터를 호출합니다.

도구는 다음 두 위치 중 하나에 추가하세요.

  • 세션 수준에서 설정하려면 session.tools를 session.update에 포함하세요. 세션 전체에서 도구를 사용할 수 있습니다.
  • 응답 수준에서 설정하려면 response.tools를 response.create에 포함하세요. 한 턴에만 도구가 필요할 때 사용합니다.

함수 도구 설정하기

애플리케이션에서 도구를 실행해야 한다면 기본적으로 함수 도구를 사용하세요. 모델이 함수 호출 인수를 보내면 애플리케이션 코드가 작업을 실행하고 function_call_output 항목으로 결과를 돌려줍니다.

session.update로 함수 도구 설정하기
const event = {
  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));

모델이 함수를 호출하면 함수 호출 항목을 수신하고 애플리케이션 로직을 실행한 다음 결과를 보내세요.

함수 호출 결과 보내기
const event = {
  type: "conversation.item.create",
  item: {
    type: "function_call_output",
    call_id: functionCall.call_id,
    output: JSON.stringify({
      status: "shipped",
      delivery_date: "2026-05-09",
    }),
  },
};

ws.send(JSON.stringify(event));
ws.send(
  JSON.stringify({
    type: "response.create",
    response: { output_modalities: ["text"], tool_choice: "none" },
  })
);

함수 호출 과정을 이벤트별로 살펴보려면 대화 관리를 참조하세요.

MCP 도구 설정하기

원격 MCP 서버에서 이미 도구를 제공하거나 기존 모델이 레거시 기본 제공 커넥터를 사용하는 경우 MCP 도구가 유용합니다. 함수 도구와 달리 MCP 도구는 Realtime API가 직접 실행합니다.

Realtime의 MCP 도구는 다음 필드로 구성됩니다.

  • type: "mcp"
  • server_label
  • server_url 또는 connector_id 중 하나
  • authorization 및 headers(선택 사항)
  • allowed_tools(선택 사항)
  • require_approval(선택 사항)
  • server_description(선택 사항)

다음 예제에서는 세션 전체에서 문서용 MCP 서버를 사용할 수 있도록 설정합니다.

session.update로 MCP 도구 설정하기
const event = {
  type: "session.update",
  session: {
    type: "realtime",
    model: "gpt-realtime-2.1",
    output_modalities: ["text"],
    tools: [
      {
        type: "mcp",
        server_label: "openai_docs",
        server_url: "https://developers.openai.com/mcp",
        allowed_tools: ["search_openai_docs", "fetch_openai_doc"],
        require_approval: "never",
      },
    ],
  },
};

ws.send(JSON.stringify(event));

레거시 커넥터

connector_id는 2026년 9월 1일 다음 날부터 출시된 모델에서 사용 중단 예정(deprecated)입니다. 원격 MCP 서버에 연결하려면 server_url을 사용하세요. 로컬 MCP 서버에 연결하려면 tunnel_id를 지정해 보안 MCP 터널을 사용하세요. 기존 모델은 계속 커넥터를 지원합니다. 아래 예제에서 사용하는 gpt-realtime-1.5는 기준일 이전에 출시된 모델입니다.

기본 제공 커넥터도 같은 MCP 도구 구조를 사용하지만 connector_id를 server_url 대신 전달합니다. 예를 들어 Google Calendar에서는 connector_googlecalendar를 사용합니다. Realtime에서는 일정이나 이메일을 검색하거나 읽는 등의 조회 작업에 기본 제공 커넥터를 사용하세요. 사용자의 OAuth 액세스 토큰을 authorization에 전달하고, 가능하면 allowed_tools로 사용할 수 있는 도구를 제한하세요.

Google Calendar 커넥터 설정하기
const event = {
  type: "session.update",
  session: {
    type: "realtime",
    model: "gpt-realtime-1.5",
    output_modalities: ["text"],
    tools: [
      {
        type: "mcp",
        server_label: "google_calendar",
        connector_id: "connector_googlecalendar",
        authorization: "<google-oauth-access-token>",
        allowed_tools: ["search_events", "read_event"],
        require_approval: "never",
      },
    ],
  },
};

ws.send(JSON.stringify(event));

원격 MCP 서버는 전체 대화 컨텍스트를 자동으로 받지는 않지만, 모델이 도구 호출에 포함해 보내는 데이터는 모두 볼 수 있습니다. 사용할 수 있는 도구를 제한하려면 allowed_tools를 사용하세요. 자동으로 실행하지 않을 작업은 모두 승인을 거치도록 설정하세요.

Realtime MCP 플로우

Realtime의 function 도구와 달리 원격 MCP 도구는 Realtime API가 직접 실행합니다. 클라이언트는 원격 도구를 실행하지 않으며 function_call_output도 반환하지 않습니다. 클라이언트는 접근 권한을 설정하고 MCP 수명 주기 이벤트를 수신합니다. 서버가 승인을 요청하면 클라이언트에서 승인 여부를 응답할 수 있습니다.

일반적인 플로우는 다음과 같습니다.

  1. session.update 또는 response.create를 보냅니다. 이때 tools에 type이 mcp인 항목을 포함합니다.
  2. 서버가 도구를 가져오기 시작하면서 mcp_list_tools.in_progress를 보냅니다.
  3. 도구 목록을 가져오는 동안에는 모델이 아직 로드되지 않은 도구를 호출할 수 없습니다. 해당 도구가 필요한 턴을 시작하기 전에 로드가 끝날 때까지 기다리려면 mcp_list_tools.completed 이벤트를 수신하세요. conversation.item.done 이벤트 중 item.type이 mcp_list_tools인 이벤트에서 실제로 가져온 도구의 이름을 확인할 수 있습니다. 가져오기에 실패하면 mcp_list_tools.failed 이벤트를 수신합니다.
  4. 사용자가 말하거나 텍스트를 보내면 클라이언트가 응답을 생성하거나 세션 설정에 따라 응답이 자동으로 생성됩니다.
  5. 모델이 MCP 도구를 선택하면 response.mcp_call_arguments.delta와 response.mcp_call_arguments.done을 수신합니다.
  6. 승인이 필요하면 서버가 item.type이 mcp_approval_request인 항목을 대화에 추가합니다. 클라이언트는 mcp_approval_response 항목으로 응답해야 합니다.
  7. 도구가 실행되면 response.mcp_call.in_progress를 수신합니다. 실행에 성공하면 이후에 response.output_item.done 이벤트를 수신하며, 이때 item.type은 mcp_call입니다. 실패하면 response.mcp_call.failed 이벤트를 수신합니다.
  8. response.done은 해당 응답의 MCP 호출이 끝나기 전에 도착할 수 있습니다. 응답이 완료되고 해당 응답의 MCP 호출이 모두 끝나면 response.create 이벤트를 다시 보내 모델이 결과를 활용해 대화를 이어 가도록 하세요. 모델이 MCP 호출을 추가로 수행하면 이 단계를 반복하세요. Realtime API는 이러한 후속 응답을 자동으로 생성하지 않습니다.

다음 이벤트 핸들러는 주요 MCP 수명 주기 이벤트를 로그에 기록합니다. 후속 응답은 별도로 관리해야 합니다.

Realtime 세션에서 MCP 이벤트 수신하기
function parseRealtimeEvent(rawMessage) {
  if (typeof rawMessage === "string") {
    return JSON.parse(rawMessage);
  }

  if (typeof rawMessage?.data === "string") {
    return JSON.parse(rawMessage.data);
  }

  return JSON.parse(rawMessage.toString());
}

function getOutputText(item) {
  if (item.type !== "message") return "";

  return (item.content ?? [])
    .filter((part) => part.type === "output_text")
    .map((part) => part.text)
    .join("");
}

ws.on("message", (rawMessage) => {
  const event = parseRealtimeEvent(rawMessage);

  switch (event.type) {
    case "mcp_list_tools.in_progress":
      console.log("Listing MCP tools for item:", event.item_id);
      break;

    case "mcp_list_tools.completed":
      console.log("MCP tool listing complete for item:", event.item_id);
      break;

    case "mcp_list_tools.failed":
      console.error("MCP tool listing failed for item:", event.item_id);
      break;

    case "conversation.item.done":
      if (event.item.type === "mcp_list_tools") {
        const names = event.item.tools.map((tool) => tool.name).join(", ");
        console.log(`MCP tools ready on ${event.item.server_label}: ${names}`);
      }

      if (event.item.type === "mcp_approval_request") {
        console.log(
          "Approval required for:",
          event.item.name,
          event.item.arguments
        );
      }
      break;

    case "response.mcp_call_arguments.done":
      console.log("Final MCP call arguments:", event.arguments);
      break;

    case "response.mcp_call.in_progress":
      console.log("Running MCP tool for item:", event.item_id);
      break;

    case "response.mcp_call.failed":
      console.error("MCP tool call failed for item:", event.item_id);
      break;

    case "response.output_item.done":
      if (event.item.type === "mcp_call") {
        console.log(
          `MCP output from ${event.item.server_label}.${event.item.name}:`,
          event.item.output
        );
      }

      if (event.item.type === "message") {
        console.log("Assistant:", getOutputText(event.item));
      }
      break;

    case "response.done":
      console.log("Realtime turn complete.");
      break;
  }
});

자주 발생하는 오류

  • mcp_list_tools.failed 이벤트는 Realtime API가 원격 서버나 커넥터에서 도구를 가져오지 못했음을 나타냅니다. server_url 또는 connector_id, 인증 정보, 서버 연결 상태, allowed_tools에 지정한 도구 이름을 확인하세요.
  • response.mcp_call.failed 이벤트는 모델이 도구를 선택했지만 호출이 완료되지 않았음을 나타냅니다. 이벤트 페이로드와 이후에 수신하는 mcp_call 항목에서 MCP 프로토콜, 실행 또는 전송 오류를 확인하세요.
  • mcp_approval_request에 대응하는 mcp_approval_response가 없으면 클라이언트가 명시적으로 승인하거나 거부할 때까지 도구 호출을 진행할 수 없습니다.
  • 턴이 시작될 때 mcp_list_tools.in_progress 상태이면 해당 턴에서는 이미 로드가 끝난 도구만 사용할 수 있습니다.
  • 응답에 tool_choice: "required"를 설정했지만 현재 사용할 수 있는 도구가 없으면 모델이 호출할 수 있는 도구가 없습니다. mcp_list_tools.completed 이벤트를 기다리거나 도구를 하나 이상 가져왔는지 확인하세요. 도구가 필요 없는 턴에는 다른 tool_choice 값을 사용할 수도 있습니다.
  • 도구를 가져오기 전에 MCP 도구 정의 검증에 실패할 수 있습니다. 흔한 원인으로는 server_label이 같은 tools 배열 안에서 중복된 경우, server_url과 connector_id를 모두 설정한 경우, 최초 세션 생성 요청에서 둘 다 누락한 경우, 유효하지 않은 connector_id를 사용한 경우, authorization과 headers.Authorization을 함께 보낸 경우가 있습니다. 커넥터를 사용할 때는 headers.Authorization을 보내지 마세요.

MCP 도구 호출 승인 또는 거부하기

도구에 승인이 필요하면 Realtime API가 대화에 mcp_approval_request 항목을 추가합니다. 호출을 계속하려면 새 conversation.item.create 이벤트를 보내세요. 이때 item.type을 mcp_approval_response로 설정하세요.

MCP 요청 승인하기
function approveMcpRequest(approvalRequestId) {
  const event = {
    type: "conversation.item.create",
    item: {
      type: "mcp_approval_response",
      approval_request_id: approvalRequestId,
      approve: true,
    },
  };

  ws.send(JSON.stringify(event));
}

요청을 거부하려면 approve를 false로 설정하세요. 필요한 경우 reason에 사유를 포함할 수 있습니다.

한 응답에서만 MCP 사용하기

MCP를 한 턴에서만 사용할 수 있도록 하려면 같은 MCP 도구 객체를 response.tools에 추가하세요. 이 경우 session.tools 대신 응답 수준에서 도구를 설정합니다.

한 응답에 MCP 도구 추가하기
const event = {
  type: "response.create",
  response: {
    output_modalities: ["text"],
    tool_choice: "required",
    parallel_tool_calls: false,
    input: [
      {
        type: "message",
        role: "user",
        content: [
          {
            type: "input_text",
            text: "Which transport should I use for browser clients in the Realtime API?",
          },
        ],
      },
    ],
    tools: [
      {
        type: "mcp",
        server_label: "openai_docs",
        server_url: "https://developers.openai.com/mcp",
        allowed_tools: ["search_openai_docs", "fetch_openai_doc"],
        require_approval: "never",
      },
    ],
  },
};

ws.send(JSON.stringify(event));

한 응답에만 외부 컨텍스트가 필요하거나 턴마다 다른 MCP 서버를 사용해야 할 때 유용합니다.

기존에 정의한 서버 레이블 재사용하기

server_label은 현재 Realtime 세션에서 도구 정의를 참조하는 고정 식별자입니다. 서버나 커넥터를 처음 정의할 때 server_label과 함께 server_url 또는 connector_id를 지정하면, 이후 session.update 또는 response.create 이벤트에서는 같은 server_label만 지정해도 됩니다. Realtime API가 기존 정의를 재사용하므로 도구 객체 전체를 다시 보낼 필요가 없습니다.

기존에 정의한 커넥터 재사용하기
const event = {
  type: "response.create",
  response: {
    output_modalities: ["text"],
    input: [
      {
        type: "message",
        role: "user",
        content: [
          {
            type: "input_text",
            text: "Check my schedule for this afternoon.",
          },
        ],
      },
    ],
    // Reuses the google_calendar connector defined earlier in this session.
    tools: [
      {
        type: "mcp",
        server_label: "google_calendar",
      },
    ],
  },
};

ws.send(JSON.stringify(event));

도구 정의는 같은 세션에서만 재사용할 수 있습니다. 새 Realtime 세션을 시작하면 서버가 도구 목록을 가져올 수 있도록 MCP 정의 전체를 다시 보내세요.