call4me
call4me позволяет вашему AI-агенту звонить по телефону от вашего имени. Попросите Claude, ChatGPT, Cursor, Codex или собственное приложение забронировать столик, записать вас к стоматологу, отменить подписку или задать вопрос компании — сервис позвонит, подождёт на линии, пройдёт телефонное меню, поговорит с ответившим человеком и сообщит результат вместе с расшифровкой разговора. Кроме того, сервис может позвонить вам и подключить к разговору. Звонки оплачиваются из авансового баланса, пополнить который можно начиная с $10.
Использование
Размещённый MCP-сервер доступен по адресу https://call4.me/mcp (HTTP с потоковой передачей). Агент выполнит вход через браузер с помощью Google или X. Проще всего вставить в агент инструкцию со страницы call4.me/mcp. Чтобы настроить подключение вручную:
, или отправьте заголовок "Authorization: Bearer " на /mcp">
claude code: claude mcp add --scope user --transport http call4me https://call4.me/mcp then /mcp, call4me, authenticate
codex: codex mcp add call4me --url https://call4.me/mcp then codex mcp login call4me
claude desktop / claude.ai / chatgpt: settings, connectors, add custom connector: https://call4.me/mcp
can't sign in? create a key at https://call4.me/account and use https://call4.me/mcp/<key>, or send "Authorization: Bearer <key>" to /mcp
В Cursor добавьте сервер в ~/.cursor/mcp.json и выполните вход, когда Cursor предложит это сделать.
{
"mcpServers": {
"call4me": { "url": "https://call4.me/mcp" }
}
}
В собственном коде можно использовать пакет Vercel AI SDK, чтобы предоставить агенту те же инструменты:
npm install call4me-ai-sdk ai zod @ai-sdk/openai
import { call4meTools } from 'call4me-ai-sdk';
// with CALL4ME_API_KEY set (from https://call4.me/account):
// generateText({ model, prompt: 'Call ... and ask ...', tools: call4meTools() })
-
Примеры: реальные звонки и запросы, с помощью которых они были совершены.
-
Блог: руководства по Claude Code, пакету AI SDK и другим темам.
-
Реестр MCP:
io.github.skeptrunedev/call4me.
Остальная часть README предназначена для тех, кто работает над самим call4me или размещает собственную копию сервиса.
Как работает звонок
agent ──MCP──▶ worker ──POST /v2/calls──▶ Telnyx ──PSTN──▶ business
▲ │ media stream (PCMU, bidirectional RTP)
│ webhooks ▼
└──────────────── VoiceSession (Durable Object) ◀──WS──▶ GPT-Live (gpt-live-1, audio/pcmu 8k)
└─ back office (Responses model):
end_call · ask_user · press_digits
-
src/server/voice/prompt.ts: инструкции для звонящего. Здесь задаётся поведение сервиса: без вступительного сообщения о его природе, уведомления о записи и пересказа разговора в конце; если собеседник прямо спросит, является ли звонящий AI, нужно ответить честно. -
src/server/voice/session.ts: передача аудио и вспомогательные функции. -
src/server/services/dialer.ts: выполнение звонков, выделение номеров для аккаунтов и обработка обратных звонков. -
src/server/services/numbers.ts: номера call4me, назначенные аккаунту, и собственные номера пользователя, подтверждённые для звонков. Telnyx хранит единый список подтверждённых номеров для всего нашего аккаунта у оператора, поэтомуverified_numbersсвязывает каждый номер с аккаунтом call4me, который подтвердил его свежим кодом. Номер, уже отмеченный в Telnyx как подтверждённый, никогда не назначается другому аккаунту. Если звонок совершается с собственного номера (from), он может быть направлен только компаниям в той же стране; при этом пользователю всё равно звонят с номера call4me. -
src/server/mcp/server.ts: инструменты MCP.
При выполнении исходящих и входящих звонков приложение не запрашивает запись. После завершения звонка уже имеющиеся записи, сохранённые в Telnyx, можно прослушать или открыть на странице звонка после входа в аккаунт. Их также можно получить через MCP с помощью call4me_get_recordings({ call_id }) или отправив запрос GET /api/calls/{call_id}/recordings с ключом API call4me или токеном OAuth в заголовке Bearer.
Перед обращением к Telnyx в обоих случаях проверяется принадлежность аккаунта; в ответ возвращаются новые ссылки для скачивания, которые не сохраняются. Пустой результат может означать, что обработка ещё не завершена или запись не была сохранена. Срок действия ссылок может истечь; ими следует делиться только с владельцем аккаунта.
В записях trunk используются идентификаторы сегментов звонка. Для них предусмотрена отдельная таблица идентификаторов провайдера, которая заполняется данными из проверенных webhook-запросов. Для существующих звонков идентификаторы определяются по точному совпадению ID управления в истории webhook-запросов Telnyx.
Приложение не пытается сопоставлять записи по номерам телефонов или временным меткам. Если срок хранения истории провайдера истёк и сопоставление не было сохранено, можно найти только записи, напрямую связанные с ID управления.
Поиск записей не обращается к голосовой сессии и не меняет подсказки, активные инструменты, аудио или настройки записи Telnyx. Формат ответов с текущим статусом звонка и расшифровкой остаётся без изменений.
Описание OpenAPI для API записей доступно по адресу /api/openapi.json. Запустите
npm run openapi:generate, чтобы заново сформировать openapi.json на основе общих схем MCP и HTTP.
CI проверяет, не разошёлся ли сгенерированный файл с исходными схемами. Перед развёртыванием через git выполните npm test, npm run check, npm run lint и npx wrangler deploy --dry-run.
При восстановлении после проблем с меню новые телефонные подсказки отслеживаются отдельно от временных меток расшифровки, а уже принятые нажатия клавиш сохраняются. Если меню повторяется, ввод оказывается недопустимым или записанная инструкция приводит в тупик, после паузы в записи можно перезапустить существующую вспомогательную модель. Система дожидается выполнения ожидающих инструментов и продолжения их работы, не прерывает ожидание на линии или разговор с ответившим человеком и просит модель выбрать поддерживаемый вариант из услышанных пунктов меню, а не бездумно повторять нажатия клавиш.
В npm test входят тесты повторного воспроизведения сообщений провайдера для восстановления после ошибок и проверки связанных с ним временных условий. Чтобы проверить настроенную вспомогательную модель на синтетических сценариях работы с меню, запустите npm run test:menu:live с OPENAI_API_KEY (или локальным .dev.vars). Эта проверка выполняет запросы к OpenAI, анализирует предложенные вызовы инструментов, но не запускает инструменты и не совершает телефонных звонков.
Настройка
- Telnyx: приложение Call Control (его ID хранится в
TELNYX_CONNECTION_ID) с URL для webhook-запросовhttps:///webhooks/telnyx, ключ API и публичный ключ webhook для аккаунта.
Номер для каждого аккаунта приобретается при первом звонке и привязывается к этому приложению.
-
OpenAI: ключ API с доступом к GPT-Live.
-
Stripe: конечная точка webhook
https:///webhooks/stripeдля событийcheckout.session.completed,checkout.session.async_payment_succeeded,invoice.paid,customer.subscription.updated,customer.subscription.deleted,charge.refunded. Подписки поддержки блога поступают на ту же конечную точку с тегамиapp=callbay, kind=supporter(см.src/server/services/supporters.ts).
Кредиты
Все звонки оплачиваются заранее. Пополнения начинаются от $10; по умолчанию баланс ежемесячно пополняется на ту же сумму через подписку Stripe. Кредиты начисляются при событии invoice.paid. Перед набором номера для звонка резервируется максимально возможная стоимость. Резервирование выполняется одной условной операцией вставки, поэтому параллельные звонки не могут привести к перерасходу. После завершения звонка сумма списания корректируется с учётом фактического времени разговора.
- Секреты (
wrangler secret put): см.src/server/env.d.ts.
Два Worker
Сеансы звонков выполняются в отдельном Worker — call4me-voice (wrangler.voice.jsonc, src/server/voice/worker.ts), который также принимает медиапотоки Telnyx на voice.call4.me. Развёртывание Worker перезапускает определённые в нём durable objects. Благодаря тому, что сеансы вынесены отдельно, сайт можно обновлять без прерывания звонков. CI развёртывает голосовой Worker с помощью scripts/deploy-voice.sh: если сборка не изменилась, скрипт пропускает развёртывание; в противном случае он дожидается завершения всех текущих звонков, выполняет развёртывание и не принимает новые звонки, пока не начнёт работать новая версия и Cloudflare не получит ещё минуту на остановку старой. Не развёртывайте этот Worker и не меняйте его секреты другими способами: любой из них приводит к перезапуску всех активных звонков. Для голосового Worker нужны секреты OPENAI_API_KEY, TELNYX_API_KEY, TELNYX_CONNECTION_ID, RAINDROP_WRITE_KEY и STREAM_SECRET (значение должно совпадать с секретом сайта): npx wrangler secret put -c wrangler.voice.jsonc.
Краулеры
/robots.txt разрешает доступ всем краулерам ко всем путям, в том числе для поиска с помощью ИИ, генерации ответов и обучения моделей.
Маска охватывает текущие и будущие краулеры, поэтому вести список разрешённых краулеров по именам не требуется.
Рекомендуемые настройки краулеров Cloudflare хранятся в cloudflare.crawlers.json. Запустите npm run crawlers для их проверки или npm run crawlers -- --apply, чтобы применить настройки и проверить результат. Для выполнения команды требуется CLOUDFLARE_API_TOKEN с разрешениями Zone Read, Zone Settings Read и Write, а также Bot Management Read и Write для call4.me. Если какая-либо настройка недоступна или не соответствует ожидаемому значению, команда завершится с ошибкой. Отдельно проверьте AI Crawl Control и правила брандмауэра: они не должны блокировать краулеры. Автоматическая защита Cloudflare от DDoS-атак остаётся включённой.
Если токен учётной записи позволяет управлять токенами, но не имеет нужных разрешений для этой зоны, запустите npm run crawlers -- --apply --authorize, чтобы добавить необходимые разрешения для call4.me. Команда получает идентификаторы разрешений из Cloudflare и сохраняет существующие разрешения и ограничения.
В редакторе токенов разрешения на запись обозначены как Edit. Некоторые продукты Cloudflare для защиты от ботов могут не поддерживать токены учётных записей. Если Cloudflare отклоняет токен учётной записи с правильно заданными разрешениями, используйте пользовательский токен из раздела «Мой профиль».
Чтобы управлять зафиксированной политикой другого сайта, передайте путь с помощью --policy /path/to/cloudflare.crawlers.json.
Публикация общедоступных страниц
npm run build:site преобразует существующие представления Hono в общедоступные страницы HTML и Markdown, сохраняет их в dist/site, копирует общедоступные ресурсы и добавляет контрольные суммы к CSS и JavaScript. Wrangler автоматически запускает эту сборку перед локальной разработкой, пробными запусками и развёртыванием. В CI сборка также выполняется перед проверкой сгенерированного манифеста маршрутов и запуском тестов. Для создания общедоступных страниц не используются база данных и учётные данные. Платные статьи не включаются в статический манифест.
src/server/static-entry.ts отдаёт эти документы через привязку к кэшируемым ресурсам Cloudflare, не инициализируя приложение и не обращаясь к D1. CSS, изображения и скрипты доставляются напрямую как статические ресурсы. Переходы между страницами постепенно улучшают обычную навигацию и учитывают настройку уменьшения анимации. Для аудио сохраняется обработчик диапазонов байтов, необходимый для перемотки.
Общедоступный контент одинаков для всех посетителей. Навигация по учётной записи, счётчики и комментарии в блоге с экранированием загружаются после отображения страницы из закрытых динамических конечных точек, которые не кэшируются. Поиск, сортировка по популярности, подтверждение подписки, настройка MCP с аутентификацией, учётные записи, платежи, OAuth и все операции записи по-прежнему обрабатываются существующим сервером. Параметр ?live=1 открывает динамическую страницу, если JavaScript отключён или не удаётся загрузить актуальные комментарии. Файлы cookie для первичного источника перехода создаются отдельно для каждого посетителя; для платной целевой страницы Reddit источник перехода фиксируется до выдачи файла cookie посещения.
Блог
/blog содержит Markdown-файлы в src/content/blog — по одному на публикацию. Список статей указан в index.ts, а изображения для заголовков размещаются в public/static/blog/.svg. В блоге также есть лента Atom, отметки «Нравится», комментарии, рассылка по электронной почте (отправляется из /admin/blog для учётных записей из ADMIN_EMAILS) и платные публикации для ежемесячных подписчиков.
Связанные статьи подбираются с помощью локальных векторных представлений, построенных на CPU, и ранжируются в рамках редакционных тематик, заданных в scripts/related-topics.ts. После добавления статьи или изменения её SEO-заголовка, тегов либо тематики запустите npm run blog:related, проверьте подобранные материалы в src/content/blog/related.generated.ts и зафиксируйте обновлённый индекс. При первом запуске загружается закреплённая версия модели EmbeddingGemma; при последующих запусках используется кэш ~/.cache/call4me/transformers. Текст статей остаётся локально. Сайт отдаёт сгенерированный индекс, не запуская модель для построения векторных представлений. Если сходство материалов ниже заданного порога, статья может получить меньше трёх рекомендаций. Команда npm test проверяет актуальность индекса, не загружая модель.
Самостоятельное размещение
Создайте форк, заведите собственную базу D1 (wrangler d1 create callbay) и укажите её идентификатор и собственное доменное имя в wrangler.jsonc.
Для локального запуска выполните npm run db:migrate:local && npm run dev и добавьте секреты в .dev.vars.
Мониторинг ИИ
Raindrop отслеживает текущий разговор (callbay_voice_call), запуски моделей во внутренней системе (callbay_back_office) и сводку после завершения звонка (callbay_call_recap). В каждом событии идентификатор учётной записи используется как идентификатор пользователя, а идентификатор звонка — как идентификатор разговора. В события включены названия моделей, время выполнения, статус и спаны инструментов внутренней системы. Аудиозаписи звонков и URL записей не загружаются.
Для локального запуска добавьте RAINDROP_WRITE_KEY в .dev.vars, а также настройте этот ключ как секрет Cloudflare Worker с помощью npx wrangler secret put RAINDROP_WRITE_KEY. Необязательный параметр RAINDROP_PROJECT_ID задаёт слаг проекта; если его не указать, используется проект по умолчанию для ключа записи. Без ключа записи мониторинг отключён. Эти необязательные параметры перечислены в .dev.vars.example.
Входные и выходные данные ИИ обрабатываются средствами Raindrop для удаления персональных данных (PII); перед этим применяются существующие в call4me маски для секретов, используемых в каждом звонке. Аргументы и результаты инструментов отображаются в выходных данных ИИ внутренней системы после удаления персональных данных. Спаны инструментов содержат их названия, длительность и обобщённый статус ошибки, поэтому конфиденциальные данные не попадают в атрибуты трассировки без обработки. Имена и адреса электронной почты учётных записей не передаются в качестве пользовательских атрибутов.
Удаление персональных данных в SDK основано на поиске по шаблонам и не гарантирует удаление всех конфиденциальных сведений.
Мониторинг работает отдельно от аудио звонка и инструментов. Конечные события и поставленные в очередь спаны инструментов отправляются в течение срока работы Worker или Durable Object. Если к моменту завершения звонка запуск модели во внутренней системе ещё не завершён, он помечается как прерванный; позднее поступившие результаты инструментов не возобновляют уже закрытую сессию мониторинга.
После звонка проверьте в Raindrop три названия событий, фактические входные и выходные данные, соответствующие идентификаторы учётной записи и звонка, а также названия и длительность выполнения инструментов. Если во время звонка модель внутренней системы не запускалась, событие для неё не создаётся. Сигналы обратной связи, аудиовложения и самодиагностика агента не отслеживаются, поскольку в текущем сценарии звонка нет соответствующих элементов обратной связи и инструментов диагностики.
Для расследования инцидентов подключите MCP-сервер Raindrop и установите навык расследования с помощью npx skills add raindrop-ai/skills --skill raindrop-investigate. Подключите Slack в Raindrop, чтобы получать оповещения. При необходимости создайте учётную запись Raindrop.
Лицензия
MIT