callwright について
Callwrightは、Retell経由で電話をかけるセルフホスト可能なMCP音声エージェントです。アシスタントが作成し、ユーザーが承認した指示に従い、多言語で通話して結果を返します。
主な機能
- 01ユーザー承認後に電話を発信
- 02通話結果と文字起こしを取得
- 03通話プロフィールと設定を管理
- 04通話言語の追加と検証
- 05通話内容からプロフィールを学習
- 06不通時は既定で一度だけ再発信
活用シーン
- 01予約済みの予定を電話で確認
- 02承認された時間帯で席を予約
- 03予約せずに店舗へ情報を問い合わせ
- 04保存済みのプロフィール情報で予約を変更
MCP 対応
Callwrightは、電話の発信、結果の取得、プロフィールや設定の管理、言語、学習のツールをMCPクライアントに提供します。発信前に内容を読み返し、明示的な確認を求めます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y callwrightRETELL_API_KEYシークレットYour Retell secret API key (stays server-side)MCP_AUTH_TOKENシークレットBearer token clients must send; required when exposed beyond localhostPORTPort the HTTP MCP server listens on (default 8787)ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
Callwright
A voice agent that places phone calls — reservations, appointments, confirmations, general inquiries — on your behalf, shaped by an LLM's direction + grounding. It discloses it's an AI, negotiates within bounds you set, never fabricates, and reports the outcome.
Built on Retell. Exposed as an MCP server so any MCP-capable assistant (Claude, ChatGPT, Cursor, Copilot) can place calls for you — combining callwright (the actuator) with your other MCPs (WorkIQ, Gmail, calendar — the sensors) for context.
Just ask
You don't fill out forms — you ask your assistant in plain language, and it gathers the context (from your calendar, email, or the chat), shapes the call, reads it back to you, and dials on your OK:
"Find the repair appointment in my calendar and call the contractor to confirm it's still on for Thursday."
"Call Sakura Sushi and book a table for 4 this Friday at 7 — anytime between 6:30 and 8 is fine."
"Ring my dentist and move my cleaning to sometime next week; my member ID is in my profile."
"電話して、東京の美容院に明日の午後カットの予約を取って." — (places the call in Japanese)
"Call this hotel in Kyoto and ask their hire-car rate to the airport — just gathering info, don't book."
The assistant pulls only the minimal details each call needs, confirms the plan with you first, then places it fire-and-forget and fetches the outcome when you ask.
How it works
You (chat) --> Host LLM --gathers context from other MCPs--> shapes a place_call
|
v
callwright MCP --validate + profile + compose + guard--> Retell --> phone
| |
+-- get_call_outcome / learn_from_call <-- outcome --+
- Generic agent, not per-scenario. One agent prompt = fixed guardrails (disclose AI, never pay, never fabricate, PII-minimize) + injected per-call direction. Handles any scenario and language.
- Multilingual, extensible at runtime. Ships speaking English and Japanese;
add_languagestands up a brand-new call language (translated prompt + a native voice + its own agent) entirely from chat — no redeploy. All language phrasing is data (lang-phrases.json), not code. - Purpose-first disclosure. Opens with the goal ("I'm an AI assistant. I'm calling to confirm..."), not a name. Your name surfaces only when a business needs it.
- Data minimization, filled lazily. PII lives in
principal.facts(shared only if asked); each call carries only the minimal relevant subset, and the read-back lists exactly which data types go out. When a call uses a durable fact you haven't saved, it offers to remember it — so the profile fills from use, not an upfront interview. - Learns from every call. When a call defers on a missing detail, the profile is enriched so next time it's collected up front — manually (
learn_from_call) or automatically via a signature-verified Retell webhook. A genuinely new scenario is staged and proposed (never silently created), with guards against over-specific splintering. - Bounded retry. An unanswered/busy call is re-dialed — exactly once by default, never more without an explicit request (anti-spam).
ツール
セットアップとプロファイル
| ツール | 目的 |
|---|---|
get_setup_status | 設定済みの項目と不足している項目を確認 |
configure | 名前、折り返し先、基本情報を保存(プロビジョニングは任意) |
list_scenarios | 登録済みのシナリオプロファイルと保留中の候補を一覧表示 |
通話
| ツール | 目的 |
|---|---|
place_call | デフォルトではドライラン(読み上げ内容を返します)。発信するには confirm:true を指定します。lang と overrides.retry に対応しています |
get_call_outcome | call_id による通話結果、分析、文字起こし |
list_recent_calls | 最近の通話 |
list_retries | 最近の自動再発信(応答なしの場合) |
言語
| ツール | 目的 |
|---|---|
list_voices | 言語を追加するために Retell の音声を確認 |
list_languages | このサーバーから発信可能な言語 |
add_language | 実行時に新しい通話言語を追加(翻訳 → エージェント) |
verify_language | 新しい言語の品質ゲート(レビューカードと任意のライブテスト通話) |
update_language / remove_language | 追加した言語を変更/削除 |
学習
| ツール | 目的 |
|---|---|
learn_from_call | プロファイルを拡充するか、新しいシナリオ候補を登録 |
list_candidates | 登録済みのシナリオ候補(新規プロファイルの保留中項目) |
create_profile | 新しいシナリオプロファイルを作成(提案して確認、ガード付き) |
add_scenario_alias | 通話タイプを既存のプロファイルに統合 |
reject_candidate | ノイズまたは一度限りの候補を削除 |
place_call は呼び出し後に処理結果を待たないツールで、ゲート付きです。最初の呼び出しでは、個人を特定できる情報(PII)の範囲を含む読み上げ内容が返されます。confirm:true で確認した後にのみ発信します。
get_call_outcome は標準の outcome オブジェクトを返します。Retell の組み込み call_successful シグナルと一致しない場合、カスタム分析を優先したステータスが正となります。診断用に、両方の生シグナルも引き続き利用できます。情報提供を目的とする通話が成功した場合は completed を使用し、booked は実際の予約、アポイントメント、または確約がある場合に限って使用します。
Retell のセットアップ(前提条件)
Callwright は Retell 経由で発信するため、機能を利用するには、発信が有効になっている Retell アカウントが必要です。Retell ダッシュボードで次の手順を行います。
- アカウントを作成し、支払い方法(Stripe)を追加します。通話と電話番号は従量課金制で、Callwright の追加料金はありません。
- KYC 認証を完了します。発信と電話番号の購入を有効にするために必須です。認証が完了していない場合、通話はブロックされます。(本人確認または事業者確認は一度のみで、通常はすぐに承認されます。)
- 電話番号を購入します。これが発信者番号(
from番号)になります。米国の市内局番の番号が最も安価です。Callwright はconfigure run_provisioningの実行時にこれを自動選択します。 - API キーを作成します(Settings → API Keys)。これが
RETELL_API_KEYです。サーバー側に保持し、ブラウザーやチャットには絶対に含めないでください。
任意ですが、推奨:
- 認証済み電話番号/ブランド通話(ダッシュボード → Telephony) — 番号を登録することで、通信事業者によって "Spam Likely" と判定されにくくなり、発信時の応答率が大きく改善します。
不要(現在ここでは使用していません):
- A2P 10DLC 登録 — SMS の送信にのみ必要です。事業者プロフィール → ブランド → キャンペーンの複数段階の承認が必要で、継続的な費用もかかります。Callwright の SMS 通知機能は実装済みですが現在は保留されているため、発信するだけであれば登録を省略できます。
料金は通話時間と発信先によって決まり(米国内でおよそ ~$0.015/分、国外ではそれより高額)、これに電話番号の月額レンタル料が加わります。
インストール
callwright として npm に公開されています。グローバルにインストールすると、callwright(サーバー)と callwright-init(セットアップウィザード)コマンドを利用できます。
npm install -g callwright
または、このリポジトリをクローンして npm install を実行すると、ソースから実行できます(node server.js、node init.js)。
どちらの場合も、callwright はセルフホスト型のシングルユーザー HTTP MCP サーバーです。自身の Retell 認証情報を使って、自分のインスタンスを実行します(上記のRetell のセットアップを参照)。情報が共有されたり、マルチテナントになったりすることはありません。
ローカルで実行する
グローバルインストールを使用する場合:
callwright-init # one-time setup wizard (number, agent, your identity)
export RETELL_API_KEY=key_xxx # [Environment]::SetEnvironmentVariable on Windows
callwright # MCP server on :8787 (POST /mcp)
リポジトリをクローンした場合は、代わりに node init.js と node server.js を使用します。
セットアップ状況はいつでも確認できます:callwright-init status(または node init.js status)。
CLI から MCP を介さずに通話を開始します:node dispatch.js <job.json> --go。
ローカルで使用する場合、
MCP_AUTH_TOKENは任意です。設定しない場合、サーバーはループバック接続のみを受け付けます。サーバーを localhost の外部に公開する際は設定してください(ホスト環境にデプロイするを参照)。
ホスト環境にデプロイする(シングルユーザー)
目標:自分だけが使用できるリモート MCP URL を用意します。ウェブクライアント(claude.ai、chatgpt.com)とローカルクライアントの両方で動作します。
1. 永続ディスクのあるホストを選ぶ
config.json と scenario-profiles.json は実行時(configure と learn_from_call により)に書き込まれるため、一時的なファイルシステムやサーバーレスのファイルシステムは避けてください。適したサービス:Fly.io(ボリューム)、Railway(ボリューム)、Render(ディスク)。常時稼働の小規模インスタンスで十分です。通話量はごくわずかです。
2. 環境変数を設定する(ホストのダッシュボード)
RETELL_API_KEY = key_xxx # your Retell secret - stays server-side
MCP_AUTH_TOKEN = <long random> # the bearer token only you hold
PORT = 8787 # or whatever the host injects
CALLWRIGHT_DATA_DIR = /data # persistent volume for runtime state
CALLWRIGHT_PUBLIC_URL = https://your-host.example.com # optional: enables the auto-learn webhook (Retell posts call_analyzed back here)
CLAUDE_ROUTINE_URL = https://api.anthropic.com/v1/claude_code/routines/trig_xxx/fire # optional immediate call completion wake-up
CLAUDE_ROUTINE_TOKEN = <routine trigger token> # dedicated token generated by the Claude Routine
.env.example を参照してください。Retell のキーをブラウザーやチャットに決して入力しないでください。
通話が TickTick タスクから開始される場合、呼び出し元のアシスタントは
tracking.ticktick_task_id を place_call に渡せます。Callwright はその不透明な ID を Retell の保存専用メタデータに格納し、自動リトライ時も保持して、最終的な call_analyzed ウェブフックを使って、設定済みの Claude Routine を起動します。
Routine の URL とトークンは任意です。1 時間ごとのポーリングが引き続きフォールバックとして使われます。
3. デプロイする
Docker を利用できます:
docker build -t callwright .
docker run -p 8787:8787 --env-file .env callwright
または、このリポジトリをホストに指定します(Dockerfile が自動検出されます)。再起動後も config.json / scenario-profiles.json が保持されるよう、アプリのディレクトリにボリュームをマウントしてください。
Docker を使わない方法:ホストに npm からインストールして、バイナリを直接実行します(実行時の状態を再起動後も保持できるよう、CALLWRIGHT_DATA_DIR を永続ボリュームに設定してください):
npm install -g callwright
CALLWRIGHT_DATA_DIR=/data callwright # reads RETELL_API_KEY / MCP_AUTH_TOKEN from env
4. MCP 経由で初回セットアップする(ウェブページ不要)
セットアップはチャット内で行います:
- サーバーに接続します(下記を参照)。
- アシスタントに
run_provisioning: trueと名前、折り返し先電話番号を指定してconfigureを呼び出すよう依頼します。これにより、キーが検証され、Retell の電話番号が選択され、汎用エージェントが作成され、プロフィールが保存されます。 get_setup_statusがready: trueを返すことを確認します。
(必要であれば、ホストのシェルで一度 node init.js を実行してもかまいません。)
クライアントを接続する
URL をデプロイ先のホストに置き換え、トークンを MCP_AUTH_TOKEN に置き換えます。サーバーはトークンを2 通りの方法で受け付けます。Authorization: Bearer ヘッダー(Desktop/Code/Cursor)または ?key= URL クエリパラメーター(コネクターのフォームにヘッダーフィールドがないウェブクライアント)です。
Claude.ai(ウェブ)
ウェブコネクターのフォームには URL しか入力できないため、トークンを URL に含めます。
- Settings → Connectors → Add custom connector(または Browse connectors → Add custom)を選択します。
- 名前:
Callwright - URL: ホスト +
/mcp+?key=とトークンを貼り付けます:https://your-host.example.com/mcp?key=<MCP_AUTH_TOKEN> - 保存してから、チャットで有効にします(🔌/ツールメニュー)。"どのような callwright ツールがありますか?" と尋ねて、接続を確認します。
トークンは URL に含まれるため、コネクター URL はパスワードのように扱ってください。URL を知っている人は誰でも、あなたの Retell アカウントに料金が発生する通話を開始できます。
MCP_AUTH_TOKENを変更して、コネクターを更新すればトークンをローテーションできます。
Claude Desktop / Cursor
{
"mcpServers": {
"callwright": {
"url": "https://your-host.example.com/mcp",
"headers": { "Authorization": "Bearer <MCP_AUTH_TOKEN>" }
}
}
}
Claude Code
claude mcp add --transport http callwright https://your-host.example.com/mcp \
--header "Authorization: Bearer <MCP_AUTH_TOKEN>"
ChatGPT(開発者モード/コネクター)
同じ URL でカスタム MCP コネクターを追加します。ヘッダーと ?key= のどちらも使用できます。
**「ツールの実行前に確認」**を有効にしておいてください。
place_callはデフォルトでドライランですが、費用が発生し、実際の人に連絡するアクチュエーターには、ツール実行前の確認も二重の安全策として有効です。
セキュリティに関する注意事項
- **単一のベアラートークンがロックになります。**トークンを持つ人は誰でも、Retell アカウントに請求される電話をかけられます。パスワードのように扱い、
MCP_AUTH_TOKENを変更してローテーションしてください。 - **最小権限の Retell キー。**完全な管理者権限が不要な場合は、スコープを限定したキーを使用してください。
- **PII。**継続的に使用する事実情報は、ホスト上の
config.jsonに保存されます。電話では最小限の情報のみを送信し、事業者から求められた場合にのみ共有します。読み上げによって、毎回どの情報が共有されるか確認できます。 MCP_AUTH_TOKENが設定されていない場合、サーバーはループバック接続のみを受け付けます(ローカル開発用)。
主なファイル
| ファイル | 目的 |
|---|---|
server.js | MCP サーバー(Streamable HTTP、ベアラー認証)+自動学習/再試行用ウェブフック |
dispatch-core.js | 検証 → プロファイル → 変数の作成 → 発信(共通コア) |
dispatch.js | dispatch-core を使用する CLI |
setup-core.js | プロビジョニング+設定+ステータス+遅延保存用ヘルパー(init と MCP で共用) |
lang-core.js | 実行時の言語管理(追加/検証/更新/削除、音声) |
lang-phrases.json | 言語ごとに作成したフレーズ(コードではなくデータ) |
learn-core.js | プロファイルの充実化+新しいシナリオ候補の登録(細分化の防止) |
retry-core.js | 応答なしの場合の再試行ポリシー+再発信の回数制限付き判断 |
routine-core.js | 冪等な Retell 通話完了処理 → Claude Routine のトリガー |
init.js | ターミナルセットアップウィザード(node init.js/node init.js status) |
update-prompt.js | 既存のエージェントにプロンプト+ツール+エチケット+ウェブフックを適用 |
place_call.schema.json | LLM が入力するジョブの契約 |
generic-prompt.md / .ja.md | 汎用エージェント用プロンプト(ガードレール+{{variables}}) |
scenario-profiles.json | 学習用プロファイル(シナリオごとの推奨詳細) |
learn.js / get-call.js | プロファイルを充実させる/通話結果を取得する CLI |
paths.js | 変更可能な状態ファイルのパスを解決(CALLWRIGHT_DATA_DIR に対応) |
scripts/release.ps1 | ワンショットリリース:バージョン更新+テスト+プッシュ+npm および MCP レジストリへの公開 |
docs/ | 設計仕様(言語追加、プロファイル学習) |
webhook/ | オプションのサーバーレス Retell→Resend メール通知機能(MCP とは独立) |
ユーザーごとの実行時ファイルである
config.json、agents.json、.retell-ids.json、job.*.json、grounding.*.jsonは Git の追跡対象外です。これらは実行時(init/configureによる)に作成されるか、 個人の通話データを含みます。決してコミットしないでください。config.example.jsonとexamples/から始めてください。
開示と法令遵守について
エージェントはすべての通話の冒頭で、必ず AI であることを開示します。これは変更・削除できない動作です。AI による通話の開示は、一部の管轄区域(例:カリフォルニア州の B.O.T. Act)で法的に義務付けられており、どこでも実践することが望ましいです。また、エージェントは情報を捏造せず、事業者から求められた場合にのみ個人データを共有します。商用利用または大規模な利用を行う場合は、管轄区域の弁護士に要件を確認してください。
オプション:すべての通話についてメールで通知
webhook/ を参照してください。通話結果をメールで通知する、サーバーレスの Retell→Resend 通知機能です。
これは MCP とは独立しており(MCP は get_call_outcome を使って必要に応じて通話結果を取得します)、デフォルトではデプロイも接続もされません。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。