Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

callrail-mcp

A read-only Model Context Protocol server for the CallRail v3 REST API. Lets Claude Code (or any MCP client) list and inspect calls, companies, trackers, form submissions, text conversations, users, tags, notifications, and integrations.

Read-only by design — no outbound calls, SMS sends, or updates are exposed.

Install

The package is plain Python. With uv:

uv tool install --from . callrail-mcp

Or with pip:

pip install .

Configure

Variable Required Notes
CALLRAIL_API_KEY yes Found at Account Settings → Integrations → API Access in CallRail.
CALLRAIL_BASE_URL no Defaults to https://api.callrail.com/v3.
CALLRAIL_DEFAULT_ACCOUNT_ID no If set, account_id is optional on each tool call. Otherwise, use list_accounts first. For agency users, use the agency account_id; sub-companies are listed via list_companies and scoped per-tool with company_id.
CALLRAIL_MCP_TRANSPORT no stdio (default) for local Claude Desktop / Claude Code, or http for a remote server reachable from mobile / claude.ai.
CALLRAIL_MCP_BEARER_TOKEN http only Required when CALLRAIL_MCP_TRANSPORT=http. Clients must send Authorization: Bearer <token>.
CALLRAIL_MCP_HOST no Default 0.0.0.0. HTTP transport only.
CALLRAIL_MCP_PORT no Default 8000. HTTP transport only.

A starter .env.example is included.

Local: wire into Claude Desktop / Claude Code (stdio)

claude mcp add callrail \
  --env CALLRAIL_API_KEY=your_key \
  -- uvx --from . callrail-mcp

For Claude Desktop, add to claude_desktop_config.json:

{
  "mcpServers": {
    "callrail": {
      "command": "uvx",
      "args": ["--from", "/path/to/callrail-mcp", "callrail-mcp"],
      "env": { "CALLRAIL_API_KEY": "your_key" }
    }
  }
}

Remote: mobile and claude.ai (HTTP)

Mobile, claude.ai web, and cloud Claude Code (the GitHub-connected web agent) all need a hosted server — they can't run a local stdio process. Run with:

export CALLRAIL_API_KEY=your_key
export CALLRAIL_MCP_TRANSPORT=http
export CALLRAIL_MCP_BEARER_TOKEN=$(python -c 'import secrets; print(secrets.token_urlsafe(32))')
callrail-mcp

Deploy to Fly.io (recommended)

A Dockerfile and fly.toml are committed. From the repo root:

# 1. Install + auth (one-time)
brew install flyctl   # or: curl -L https://fly.io/install.sh | sh
fly auth login

# 2. Create the app, keeping our committed fly.toml
fly launch --copy-config --no-deploy --name <unique-app-name>

# 3. Set secrets
fly secrets set \
  CALLRAIL_API_KEY=your_callrail_key \
  CALLRAIL_MCP_BEARER_TOKEN=$(python -c 'import secrets; print(secrets.token_urlsafe(32))')

# 4. Ship it
fly deploy

# 5. Grab the public hostname + token for the connector step below
fly status
fly secrets list   # token value is hidden; you saved it from step 3, right?

The default fly.toml provisions a 256 MB shared-cpu machine with auto-stop — fine for occasional use. For always-warm response, set min_machines_running = 1 in fly.toml and redeploy.

Add as a custom connector (one-time, account-wide)

Once deployed, in claude.ai → Settings → Connectors → Add custom connector:

URL:    https://<your-app-name>.fly.dev/mcp
Header: Authorization: Bearer <CALLRAIL_MCP_BEARER_TOKEN>

The same connector is then available across:

  • claude.ai web chat
  • Claude on iOS / Android
  • Cloud Claude Code (every GitHub-connected repo, current and future)
  • Local Claude Code / Claude Desktop (alternative to the stdio config above)

Per-repo override

If you'd rather scope the connector to specific repos instead of account-wide, commit a .mcp.json in each repo root:

{
  "mcpServers": {
    "callrail": {
      "type": "http",
      "url": "https://<your-app-name>.fly.dev/mcp",
      "headers": { "Authorization": "Bearer ${CALLRAIL_MCP_BEARER_TOKEN}" }
    }
  }
}

Then set CALLRAIL_MCP_BEARER_TOKEN as a Claude Code secret for that repo.

Custom MCP connectors require a Pro/Team/Enterprise plan in claude.ai.

Tools

Tool Endpoint
list_accounts, get_account /a.json, /a/{id}.json
list_companies, get_company /a/{id}/companies(.json)
list_calls, get_call /a/{id}/calls(.json)
get_call_summary, get_call_timeseries /a/{id}/calls/summary.json, /calls/timeseries.json
get_call_recording /a/{id}/calls/{call_id}/recording.json
list_trackers, get_tracker /a/{id}/trackers(.json)
list_form_submissions /a/{id}/form_submissions.json
list_text_conversations, get_text_conversation /a/{id}/text-messages(.json)
list_users, get_user /a/{id}/users(.json)
list_tags, list_notifications, list_integrations /a/{id}/tags.json, /notifications.json, /integrations.json

Pagination is not auto-followed: each list tool returns the raw {page, per_page, total_pages, total_records, …} envelope so the client can decide whether to fetch the next page (page=N).

Local development

uv sync
uv run callrail-mcp                                    # stdio server
npx @modelcontextprotocol/inspector uv run callrail-mcp # interactive UI

License

MIT.

About

Claude Code

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages