MCP 커넥터
Claude 같은 MCP 클라이언트에 번호를 붙여 대화로 전화를 거는 방법.
gateway는 MCP(Model Context Protocol) 서버를 함께 제공합니다. Claude 같은 MCP 클라이언트에 번호를 붙이면 대화로 전화를 걸고, 결과를 조회하고, 통화를 끊을 수 있습니다.
서버 주소
https://vox-gateway-prod.fly.dev/mcp/끝 슬래시가 계약입니다. /mcp로 접속하는 클라이언트도 있어 서버가 정규화해 주지만, 설정에는 슬래시까지 넣으세요.
연결하기
연결 방법은 셋이고, 클라이언트가 헤더를 넣을 수 있는지에 따라 갈립니다. 헤더를 지정할 수 있으면 번호 API 키 하나로 끝나고, 그렇지 않은 클라이언트(Claude 웹·데스크톱의 커넥터 화면에는 임의 헤더 칸이 없습니다)를 위해 나머지 둘이 있습니다.
| 방법 | 정체성 | 쓸 수 있는 조건 |
|---|---|---|
| 헤더에 번호 API 키 | 그 번호 | 언제나 — 헤더를 지정할 수 있는 클라이언트라면 추가 설정이 필요 없습니다. |
| 계정으로 로그인 (OAuth) | 여러분의 계정 | 플랫폼에서 켜져 있어야 합니다. |
| 커넥터 전용 주소 | 그 번호 | 운영자가 번호 단위로 열어 준 경우에만 — 기본은 닫혀 있습니다. |
헤더에 번호 API 키
인증은 REST와 같은 번호 API 키입니다. 그대로 Bearer로 넘기면 됩니다.
{
"mcpServers": {
"vox-gateway": {
"url": "https://vox-gateway-prod.fly.dev/mcp/",
"headers": { "Authorization": "Bearer tg_live_..." }
}
}
}계정으로 로그인 (OAuth)
커넥터가 OAuth로 연결되면 키가 아니라 여러분의 계정이 정체성이 됩니다. 접근 가능한 워크스페이스의 번호가 모두 보이고, 도구에 번호 선택 인자가 추가됩니다(from_number · number). 이 방식은 플랫폼에서 켜져 있을 때만 나타납니다 — 커넥터를 추가해도 로그인 화면으로 넘어가지 않으면 꺼져 있는 것입니다.
커넥터 전용 주소
기본적으로 닫혀 있는 제한 기능입니다. 운영자가 번호 단위로 열어 준 경우에만 동작하고, 열려 있지 않은 번호의 주소는 형식이 맞아도 404입니다. 열려 있는지는 번호 상세에서 확인하세요 — 주소가 보이지 않으면 아직 열려 있지 않은 것이고, 주소를 직접 만들어 붙여넣는 것으로는 열리지 않습니다.
https://vox-gateway-prod.fly.dev/mcp/t/{번호 API 키}/번호 상세 › 아웃바운드에서는 앞부분만 마스킹되어 보이고, 복사를 누르면 그때 완성 주소를 가져옵니다(워크스페이스 관리자만, 가져간 기록이 남습니다). 2026년 8월 20일 이전에 발급한 키는 복사할 수 없어 재발급이 필요합니다.
이 URL 자체가 자격증명입니다. 주소를 아는 사람은 그 번호로 전화를 걸고 통화 이력을 볼 수 있습니다. 여러 사람에게 같은 주소를 주면 서로의 통화 이력이 보이므로, 격리가 필요하면 번호를 따로 발급하세요. 무효화는 키 재발급입니다.
제공 도구
| 도구 | 인자 | 하는 일 |
|---|---|---|
make_call | phone_number 필수instruction 필수language ko | vi | en | zh | es (미지정=저장된 통화 언어)from_number (OAuth 연결 시) | 전화를 겁니다. call_id · status · from · from_number를 돌려줍니다. |
get_call | call_id 필수 | 통화 하나의 상태·요약·시각·녹음 유무를 조회합니다. |
list_my_calls | limit (기본 20) | 최근 통화를 최신순으로 나열합니다. 전문·재생 링크는 싣지 않습니다. |
get_transcript | call_id 필수 | 통화에서 오간 말을 turn 단위로 읽습니다. 통화의 status가 함께 옵니다. |
get_recording_link | call_id 필수 | 녹음을 들을 수 있는 시한부 링크를 발급합니다. |
end_call | call_id 필수number (OAuth 연결 시) | 진행 중인 통화를 즉시 끊습니다. |
list_my_numbers | 없음 | 발신 가능한 번호를 나열합니다. OAuth로 연결했을 때만 제공됩니다. |
- REST와 달리
make_call은instruction이 필수입니다. MCP는 “임무를 말로 시키는” 표면이라 임무 없이 거는 것이 의미가 없기 때문입니다. 반대로 REST는 agent가 이미 임무를 아는 연동을 상정해to만 필수입니다. end_call은 통화 밖에서 부르는 도구라 기다리지 않고 즉시 끊습니다. 통화 중인 agent가 작별 인사를 하고 끊으려면 MCP가 아니라 REST hangup을 쓰세요 — MCP로 부르면 인사가 잘립니다.- 조회 도구(
get_call·list_my_calls·get_transcript·get_recording_link)는 그 키의 번호로 건 통화만 돌려줍니다. 남의 통화는 존재 여부도 알려주지 않고call not found가 됩니다. summary는 통화 전체를 한 줄로 줄인 값입니다. “상대가 뭐라고 했어?”처럼 실제로 오간 말(날짜·금액·약속)을 물으면 요약에서 추측하지 말고get_transcript를 부르게 하세요.
통화 결과 확인
통화가 끝나면 세 가지를 볼 수 있습니다 — 요약 한 줄(get_call), 오간 말 전문(get_transcript), 녹음(get_recording_link). 셋은 서로 대체재가 아닙니다.
전문 읽기
get_transcript은 turn 배열과 함께 통화의 status를 돌려줍니다. 빈 배열의 뜻이 그 값으로 갈립니다— 진행 중이면 “아직 아무도 말하지 않았다”이고, 끝난 통화면 “전사본이 없는 통화”(받지 않았거나 말 없이 끝남)입니다. 후자를 “상대가 아무 말도 안 했다”고 옮기면 사실과 다릅니다.
상대 쪽 텍스트는 음성 인식 결과라 잘못 들은 말이 섞일 수 있고 숫자가 말로 풀려 나오기도 합니다 — 원문이 아니라 “들린 것”으로 다루세요. 진행 중에 불러도 그 시점까지의 턴을 돌려줍니다.
녹음 듣기
오디오는 커넥터로 오갈 수 없습니다 — 이 연결은 텍스트만 주고받습니다. 그래서 get_recording_link은 파일이 아니라 브라우저에서 열 링크를 돌려줍니다(url · expires_at). 녹음을 듣는 유일한 길입니다.
get_call과 list_my_calls의 각 통화에는 recording이 함께 옵니다. get_recording_link는 이 값이 available일 때만 링크를 내주므로, 링크를 찍어보기 전에 여기부터 읽는 편이 빠릅니다.
| recording | 뜻 | 링크 요청 시 |
|---|---|---|
available | 녹음 파일이 있습니다. | 링크를 발급합니다. |
pending | 통화가 방금 끝나 파일을 마감하는 중입니다. | 거절 — 몇 초 뒤 다시 부르세요(없다고 단정하지 마세요). |
none | 이 통화는 녹음되지 않았습니다. | 거절 — 지난 통화를 소급해 녹음할 수는 없습니다. |
failed | 녹음을 시도했지만 파일이 남지 않았습니다. | 거절 — 재시도해도 같습니다. |
녹음은 번호 단위 설정입니다 — 번호 관리 › 번호 › 음성 탭의 “통화 녹음” 토글이고, 다음 통화부터 적용됩니다. 통화 한 건만 켜고 끌 수는 없습니다.
재생 링크는 로그인 없이 열립니다. 주소를 가진 사람은 만료 전까지 누구나 녹음을 들을 수 있으니 자격증명처럼 다루고, 요청한 본인에게만 건네세요. 기본 유효기간은 24시간이며 응답의 expires_at이 정확한 만료 시각입니다. 같은 통화로 다시 발급해도 안전하지만 이미 나간 링크가 무효가 되지는 않습니다 — 링크는 무상태 서명이라 개별 회수가 없고, 만료를 기다리는 것 외에는 운영자가 서명 키를 갈아 그 시점의 모든 링크를 한꺼번에 죽이는 방법뿐입니다.
번호 결정
번호 API 키나 커넥터 전용 주소로 연결했다면 그 키의 번호로 고정됩니다 — 고를 것이 없고, 아래 인자도 나타나지 않습니다.
OAuth로 연결했다면 정체성이 계정이라 번호가 자동으로 정해지지 않습니다. 규칙은 다음 순서입니다.
- 번호를 지정했으면 그 번호 — 거는 도구는
from_number, 끊는 도구는number입니다. 접근 권한이 없으면 403number_not_allowed. - 지정하지 않았고 접근 가능한 번호가 정확히 하나면 그 번호.
- 둘 이상이면 임의로 고르지 않고 거절합니다 — 후보 목록을 함께 돌려주니 하나를 골라 다시 부르세요.
{
"ok": false,
"reason": "from_number_required",
"candidates": [
{ "number_id": "6b2e…", "phone": "07079193558", "workspace_name": "우리 팀" },
{ "number_id": "8c41…", "phone": "07079193559", "workspace_name": "지원팀" }
]
}end_call도 같은 상황에서 같은 모양으로 거절하는데, 사유 이름만 number_required입니다 — 그 도구의 인자 이름이 number이기 때문입니다.
조회 도구는 접근 가능한 워크스페이스를 가로질러 통화를 찾지만, 끊는 표면은 번호 단위로 좁아집니다 — 그래서 list_my_calls로 찾은 통화를 끊을 때 번호를 함께 넘겨야 할 수 있습니다. 값은 후보 목록이나 조회 결과의 number_id를 그대로 쓰면 됩니다.
발신 번호가 없을 때는 422 no_number_available입니다. 전체 코드는 에러 코드를 보세요.