← 블로그 목록
가이드2026-06-01

MCP 전화 tool 설계 — create_call / control_call / send_message 패턴 정리

MCP 전화 tool 설계 — create_call / control_call / send_message 패턴 정리

MCP 서버에 전화 기능을 노출할 때 tool 을 어떻게 쪼개느냐로 LLM 사용성이 갈린다. 너무 잘게 쪼개면 LLM 이 순서 헷갈리고, 너무 묶으면 통제 못 함.

좋은 소식: ClawOps 는 이 tool 셋을 원격 HTTP MCP 서버로 이미 제공한다. 직접 MCP 서버를 짤 필요 없이 URL 한 줄(https://api.claw-ops.com/mcp, 인증은 OAuth)만 등록하면 아래 tool 들이 그대로 노출된다. 이 글은 (1) ClawOps MCP 가 실제로 어떤 tool 을 어떤 모델로 노출하는지, (2) 직접 MCP 서버를 짤 때 같은 패턴을 어떻게 따라야 하는지를 정리한다.

ClawOps MCP 가 노출하는 전화 관련 tool

tool역할호출 시점
create_call전화 발신 (To/From/Url/AI)발신이 필요한 모든 시나리오
control_call진행 중 통화 제어 (현재 hangup)통화 종료
send_messageSMS/LMS/MMS 발송문자 안내·링크 전달
get_call_summary끝난 통화 요약 조회결과 보고
get_transcript통화 전사 조회상세 확인

핵심: 발신은 항상 create_call 하나다. "알림성 단방향"과 "대화형"을 별도 tool 로 쪼개지 않는다. 차이는 tool 이 아니라 어떤 모드로 거느냐에서 갈린다.

  • Url 을 지정하면 → 그 URL 이 반환하는 VoiceML 시나리오대로 통화 진행
  • Url 을 생략하면 → From 번호에 연결된 Agent(실시간 대화) 모드로 통화 진행
  • AI 필드를 지정하면 → AI Completion 모드 (provider/model/api_key + 초기 메시지). Url 과 동시 사용 불가

1. 직접 MCP 서버를 짤 때 — create_call 래핑

ClawOps MCP 를 그대로 쓰지 않고, 자기 도메인 로직을 끼워 직접 MCP 서버를 만들 수도 있다. 이때도 발신 tool 은 하나로 유지하고 내부에서 ClawOps SDK client.calls.create 를 호출한다.

DEFAULT_FROM = "07012345678"  # 발급받은 070 번호

@server.tool()
def create_call(to: str, scenario_url: str | None = None) -> dict:
    """전화 발신.
    - scenario_url 지정: 해당 VoiceML 시나리오대로 통화 진행
    - scenario_url 생략: From 번호에 연결된 Agent(실시간 대화) 모드
    """
    call = client.calls.create(
        to=to,
        from_=DEFAULT_FROM,
        url=scenario_url,  # None 이면 Agent 모드
    )
    return {"call_id": call.call_id, "status": call.status}

LLM 이 헷갈리지 않게: "대화형이냐 알림이냐"를 tool 이름이 아니라 scenario_url 유무로 표현한다고 description 에 명시. 시스템 프롬프트 작성을 LLM 한테 떠넘기지 말 것 — 시나리오는 scenario_url 이 가리키는 서버에서 고정한다.

AI Completion 모드로 발신

provider 를 직접 지정해 AI 가 통화를 처리하게 할 수도 있다.

@server.tool()
def create_ai_call(to: str, instruction: str) -> dict:
    """AI 가 instruction 대로 응대하는 통화. Url 과 동시 사용 불가."""
    call = client.calls.create(
        to=to,
        from_=DEFAULT_FROM,
        ai={
            "provider": "openai",
            "model": "gpt-realtime",
            "api_key": OPENAI_API_KEY,
            "messages": [{"role": "system", "content": instruction}],
        },
    )
    return {"call_id": call.call_id}

2. control_call — 통화 종료

진행 중 통화 제어는 control_call 이다. 현재 지원하는 동작은 Status="completed"(hangup). idempotent 하다.

@server.tool()
def control_call(call_id: str) -> dict:
    """진행 중 통화 종료 (Status='completed')."""
    client.calls.update(call_id, status="completed")
    return {"call_id": call_id, "status": "completed"}

참고: DTMF 전송이나 통화 전환(transfer) 같은 동작은 별도 MCP tool 로 제공되지 않는다. 통화 안에서의 흐름 제어(목적 달성 후 종료 등)는 Agent 모드의 system prompt / VoiceML 시나리오에서 처리하고, 외부에서의 강제 종료만 control_call 로 한다.

3. send_message — 문자 안내

통화 중/후에 링크·주소·기사 연락처 등을 문자로 보내는 패턴.

@server.tool()
def send_message(to: str, body: str) -> dict:
    """SMS/LMS/MMS 발송. 본문 길이에 따라 자동 분류."""
    msg = client.messages.create(to=to, from_=DEFAULT_FROM, body=body)
    return {"message_id": msg.message_id}

4. get_call_summary / get_transcript — 결과 조회

끝난 통화의 요약·전사는 별도 tool 로 조회한다. 둘 다 비동기 처리라 statuscompleted 가 될 때까지 폴링할 수 있다.

@server.tool()
def get_call_summary(call_id: str) -> dict:
    """통화 요약 조회. 아직 처리 중이면 status='pending'."""
    s = client.calls.get_summary(call_id)
    return {"status": s.status, "summary": getattr(s, "result_json", None)}

@server.tool()
def get_transcript(call_id: str) -> dict:
    """통화 전사 조회."""
    t = client.calls.get_transcript(call_id)
    return {
        "status": t.status,
        "segments": [
            {"speaker": seg.speaker, "text": seg.text}
            for seg in (t.segments or [])
        ],
    }

5. 안 권장 — 묶지 말 것

  • make_call_and_get_summary (발신+대기+결과 묶기) — 통화 시간 변동이 큰데 동기 호출이라 timeout 위험. 발신(create_call)과 결과 조회(get_call_summary)는 분리.
  • 알림용/대화용 발신 tool 을 따로 만들기 — 발신은 create_call 하나, 모드는 Url/AI 로 표현.
  • start_recording/stop_recording 별도 tool — ClawOps 는 기본 자동 녹음이라 불필요.

6. tool description 작성 팁 (LLM 한테 잘 쓰이게)

  • 한 문장 안에 언제 쓰는지 명시 ("발신용", "통화 종료용")
  • 파라미터 한국어 예시 ("010-1234-5678 형식")
  • 부작용 명시 ("통화 종료 즉시 호출")
  • 다른 tool 과의 관계 명시 ("결과는 get_call_summary 로 조회")

LLM 은 description 만 보고 어떤 tool 을 쓸지 결정. 모호하면 wrong tool 선택.

7. 작동 원리

ClawOps MCP 를 그대로 쓰는 경우:

LLM (Claude Code / Cursor 등)
  ↓ MCP tool call (HTTP / OAuth)
api.claw-ops.com/mcp (원격 MCP 서버)
  ↓
한국 070 → 대상 휴대폰

직접 MCP 서버를 짜는 경우:

LLM
  ↓ MCP tool call
당신의 MCP 서버 (create_call / control_call ...)
  ↓ ClawOps SDK (client.calls.create ...)
api.claw-ops.com
  ↓
한국 070 → 대상 휴대폰

다음 단계

관련 글 더 보기

가이드

MCP 음성 서버 직접 만들기 — Stdio + HTTP 양쪽 지원, 코드 50줄

Claude / Codex / Cursor / OpenClaw 어느 에이전트에도 붙는 MCP 음성 서버를 직접 만드는 가이드. Stdio + HTTP 양쪽 지원, ClawOps SDK 30줄 wrapping.

가이드

MCP 음성 서버 — Claude / Claude Code / Cursor agent에 한국 070 전화 붙이기

MCP(Model Context Protocol) 원격 서버 연결로 Claude Desktop, Claude Code, Cursor agent 에 한국 070 번호 전화 tool 을 붙이는 가이드. ClawOps 원격 MCP 연결 + 실제 통화 데모.

가이드

Claude Code 에 한국 070 번호 붙이기 — MCP 한 줄로 'thomi 한테 전화 걸어' 가능하게

Claude Code(터미널 CLI) 안에서 한국 070 번호로 직접 전화 걸고 받게 만드는 가이드. MCP 서버 설정 + ClawOps 070 번호 발급 + Claude Code agent 가 부르는 실제 프롬프트.

가이드

Claude Desktop 에 한국 070 번호 붙이기 — ClawOps MCP 커넥터로 전화 거는 Claude 만들기

Claude Desktop(데스크톱 앱)에 한국 070 번호 전화 기능을 붙이는 가이드. ClawOps 원격 MCP 서버를 OAuth 커스텀 커넥터로 연결 + 070 발급 + 실제 사용 프롬프트. (설치할 npm 패키지·API 키 환경변수 불필요)

가이드

ngrok 없이 로컬에서 음성 에이전트 띄우기 — 5분, ClawOps managed inbound

ngrok·터널링·자체 webhook 서버 없이 로컬 머신에서 한국어 voice agent 띄우는 가이드. ClawOps managed inbound 패턴 + Python 30줄.

ClawOps AI 전화 API로 시작하기

070 번호 발급부터 AI 음성 통화까지, REST API 몇 줄이면 됩니다.