Skip to main content
Glama
CTMJSON

ctm-multi-mcp

Official
by CTMJSON

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
CTM_BASE_URLNoOverride API base URL (default: https://api.calltrackingmetrics.com/api/v1).https://api.calltrackingmetrics.com/api/v1
CTM_BASIC_AUTHYesBase64-encoded access_key:secret_key for your parent/reseller account. Get the keys from CTM → Settings → Account Settings → API, or generate the encoded value with `echo -n "access_key:secret_key" | base64`.
CTM_ACCOUNT_IDSNoComma-separated account IDs to limit scope.
CTM_ACCOUNTS_FILENoPath to JSON config file (default: ~/.ctm-accounts.json).~/.ctm-accounts.json

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
server_infoA

Return server version and build info to confirm which code is live.

list_sub_accountsA

List sub-accounts accessible by the parent API key.

Defaults to active accounts only. Pass status="archived", "canceled", or "paused" to see those instead, or status="all" for every account regardless of status.

Returns account IDs, names, statuses, and any labels from the CTMMulti accounts configuration file.

search_callsA

Search calls across sub-accounts.

Pass account_ids as a comma-separated list, or omit to search all active sub-accounts. For large result sets, use per_page and page for pagination, or use narrow date ranges.

Only searches active sub-accounts by default. Pass account_status="archived", "canceled", "paused", or "all" to search other sub-accounts.

Each result line includes call_status/dial_status, the logged disposition (CTM's 'sale' outcome field, e.g. "wrong number", "no message"), source, tags, and (when present) the ad-platform campaign/keyword from CTM's per-call "paid" attribution object — no need to call get_call just to see the outcome or ad attribution of a call. Note campaign/keyword are frequently blank for non-paid traffic, and keyword specifically can be blank even for paid Search traffic (Google withholds it for some queries) — that omission from the line is expected, not a sign the field is missing from the API.

NOTE: the CTM calls-list API does not reliably filter server-side by status. This tool applies status and disposition as a best-effort client-side filter on top of whatever page is returned, so filtered counts only reflect the current page, not the full unfiltered total shown at the bottom of the output. For an accurate aggregate breakdown across all pages, use call_disposition_report instead of paging through search_calls with a filter.

If what's actually wanted is a row-level list of the matching calls themselves (not just counts) — e.g. "the calls answered over 60s yesterday with ID/Name/City/State" — use call_export instead of paging through search_calls page by page and manually filtering/collecting rows, and instead of looping get_call per call afterward to fill in name/city/state (those fields are already present on every call in this list, no per-call lookup needed). call_export filters across the full date range in one shot and returns ready-to-use CSV.

get_callA

Get details for a specific call.

By default returns the full payload, including call_path and transcript data — this is large (~100+ fields). If you only need a handful of fields (e.g. when checking several calls in a row), pass fields as a comma-separated list of top-level keys (e.g. "call_status,dial_status,duration,source,tracking_number,tag_list, sale,called_at,direction") to get back just those, which is much cheaper than the full payload. For bulk disposition analysis across many calls, prefer call_disposition_report instead of looping this.

list_numbersA

List tracking numbers and their routing across sub-accounts.

Shows which numbers exist, their type (toll-free/local), status, and current routing destination.

Fetches up to max_items numbers per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large number inventory; a truncation warning is included if any account had more than max_items.

Only queries active sub-accounts by default (this is about which accounts get searched, separate from status, which filters numbers by their own status). Pass account_status="archived", "canceled", "paused", or "all" to search other sub-accounts.

get_numberA

Get full details for a specific tracking number.

Pass fields as a comma-separated list of top-level keys to get back just those instead of the full payload — cheaper when you only need a couple of fields, e.g. when checking several numbers in a row.

list_contactsA

List contacts across sub-accounts.

Filter by name, email, or phone number substring match.

Fetches up to max_items contacts per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large contact list; a truncation warning is included if any account had more than max_items.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

get_contactA

Get full details for a specific contact.

Pass fields as a comma-separated list of top-level keys to get back just those instead of the full payload — cheaper when you only need a couple of fields, e.g. when checking several contacts in a row.

list_sourcesA

List tracking sources (channels, campaigns) across sub-accounts.

Fetches up to max_items sources per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large source list; a truncation warning is included if any account had more than max_items.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

get_sourceA

Get full details for a specific source.

Pass fields as a comma-separated list of top-level keys to get back just those instead of the full payload — cheaper when you only need a couple of fields, e.g. when checking several sources in a row.

list_queuesA

List call queues (ring groups, agent pools) across sub-accounts.

Fetches up to max_items queues per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large number of queues; a truncation warning is included if any account had more than max_items.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

get_queueA

Get full details for a specific call queue.

Pass fields as a comma-separated list of top-level keys to get back just those instead of the full payload — cheaper when you only need a couple of fields, e.g. when checking several queues in a row.

list_voice_botsA

List VoiceAI voice bots across sub-accounts.

Fetches up to max_items voice bots per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large number of bots; a truncation warning is included if any account had more than max_items.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

get_voice_botA

Get full details for a specific voice bot, including prompt and config.

Pass fields as a comma-separated list of top-level keys to get back just those instead of the full payload — cheaper when you only need a couple of fields, e.g. when checking several bots in a row.

list_voice_menusA

List IVR voice menus across sub-accounts.

Fetches up to max_items voice menus per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large number of menus; a truncation warning is included if any account had more than max_items.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

get_voice_menuA

Get full details for a specific voice menu, including keypress mappings.

Pass fields as a comma-separated list of top-level keys to get back just those instead of the full payload — cheaper when you only need a couple of fields, e.g. when checking several menus in a row.

list_schedulesA

List time-based schedules across sub-accounts.

Schedules control when routing rules are active (business hours, holidays, etc.).

Fetches up to max_items schedules per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large number of schedules; a truncation warning is included if any account had more than max_items.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

get_scheduleA

Get full details for a specific schedule, including time blocks.

Pass fields as a comma-separated list of top-level keys to get back just those instead of the full payload — cheaper when you only need a couple of fields, e.g. when checking several schedules in a row.

list_geo_routesA

List geo routers and conditional routers across sub-accounts.

Fetches up to max_items of each per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large number of routers; a truncation warning is included if any account had more than max_items of either type.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

get_geo_routeA

Get full details for a specific geo router.

Pass fields as a comma-separated list of top-level keys to get back just those instead of the full payload — cheaper when you only need a couple of fields, e.g. when checking several routes in a row.

list_usersA

List users (agents, admins) across sub-accounts.

Fetches up to max_items users per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large user list; a truncation warning is included if any account had more than max_items.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

get_userA

Get full details for a specific user.

Pass fields as a comma-separated list of top-level keys to get back just those instead of the full payload — cheaper when you only need a couple of fields, e.g. when checking several users in a row.

list_tagsA

List tags (labels) across sub-accounts.

Tags are used to categorize calls, contacts, numbers, etc.

Fetches up to max_items tags per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with a large number of tags; a truncation warning is included if any account had more than max_items.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

call_summary_reportA

Get aggregated call summary statistics across sub-accounts.

Returns call counts, average duration, total talk time, and breakdown by status/tag for each account and a combined total.

Use start_date/end_date (ISO format) or time_duration (e.g. 'today', 'yesterday', 'last7days', 'last30days').

Only queries active sub-accounts by default. Pass account_status="archived", "canceled", "paused", or "all" to query other sub-accounts.

call_disposition_reportA

Aggregate call outcomes/dispositions across sub-accounts in one call.

Only queries active sub-accounts by default. Pass account_status="archived", "canceled", "paused", or "all" to query other sub-accounts.

Paginates the calls-list endpoint server-side (concurrently, not one page at a time) and returns pre-aggregated counts — call_status/dial_status breakdown, the logged disposition breakdown (CTM's 'sale.name' outcome field, e.g. "wrong number", "no message", "offering services"), duration stats, top marketing sources (which doubles as "breakdown by source" for whatever duration range you asked for), top ad-platform campaigns and keywords (from CTM's per-call "paid" attribution object — real Google/Bing/Meta campaign & keyword data, distinct from the CTM tracking-source label used for "source" above), and call volume by day of week.

Note on campaign/keyword data: Google withholds keyword-level text for some Search traffic even when the call is clearly attributable, so "(not provided)" keywords are expected, not a bug. campaign_id is far more reliably populated than the human-readable campaign name — if campaign names come back mostly blank, use call_crosstab with rows="campaign_id" (or "ad_group_id") for a reliable grouping.

Pass min_duration/max_duration (seconds) to scope everything — including the source/disposition/status breakdowns — to calls in that duration range, e.g. min_duration=60 for "calls over a minute by source". This replaces manually paging through search_calls and grouping raw records by hand.

Pass status (matches call_status/status/dial_status, exact, case-insensitive) and/or source (substring match against the marketing source name, case-insensitive) to scope the whole report further, e.g. status="answered", source="Google". NOTE: like search_calls, this is applied client-side after fetching — the CTM calls-list API's own status filter does not reliably work, so filtering happens here instead, on the full fetched set (not just one page), which is more reliable than filtering via search_calls.

Use this instead of paging through search_calls or looping get_call — this is the tool to reach for when asked to analyze calls/dispositions over a date range; it replaces what would otherwise take one get_call round-trip per call, or a full manual page-by-page scan for a duration/source/status cut.

call_exportA

Export a filtered, row-level list of individual calls as CSV.

Use this — not search_calls, not a get_call loop — any time the ask is for actual call records matching a filter (e.g. "answered calls over 60s yesterday with ID/Name/City/State", "give me the calls from Google Ads last week with caller number and city"). It replaces two things people otherwise reach for and both are worse:

  1. Paging through search_calls with a status/disposition filter — that tool only filters within whatever single page it fetched, not across the full date range, so a "321 matching calls" answer from paging is unreliable; the total at the bottom of search_calls output is always the unfiltered count.

  2. Looping get_call once per matching call to read name/city/state — unnecessary. CTM's calls-list endpoint already returns name, city, and state on every call record; this tool fetches once (paginated server-side, same mechanism as call_disposition_report and call_crosstab) and reads those fields directly off the already-fetched payload. No per-call round trip.

Filters (all optional, AND together): min_duration/max_duration (seconds), status (matches call_status/status/dial_status, exact, case-insensitive — e.g. "answered"), source (substring match against the marketing source name, case-insensitive). These are applied client-side across the entire fetched set (bounded by max_calls), not per-page — this is what makes the count reliable, matching what call_disposition_report would report for the same filters. Cross-check against call_disposition_report's "Calls analyzed" count if you want a sanity check before trusting the row count here.

fields: comma-separated columns, in order, forming the CSV header. Supported: id, source, name, city, state, called_at, duration, status, dial_status, disposition, caller_number, tracking_number, receiving_number, agent, tag, day_of_week, campaign, campaign_id, keyword, ad_group, ad_group_id, medium, ad_network, ad_match_type, paid_source. The last several are CTM's per-call "paid" ad-attribution fields (see call_crosstab's docstring for caveats about campaign/keyword sometimes coming back "(not provided)").

sort: field to order rows by, prefix "-" for descending (default "-called_at", most recent first). Only "called_at" and "duration" are supported as sort keys; anything else leaves rows in fetch order.

Use start_date/end_date (ISO format) or time_duration (e.g. 'today', 'yesterday', 'wtd', 'last7days' — see call_crosstab's docstring for the full list of accepted values).

Returns raw CSV text — header row plus one row per matching call. Hand it straight to the user as a file, or paste into a spreadsheet. Rows are capped at max_calls fetched per account (raise it for high-volume accounts/date ranges); a truncation warning is included as a leading comment line if any account hit the cap.

call_crosstabA

Build a source × status crosstab matrix across sub-accounts.

Fetches calls for the given account_ids + date range and returns a matrix where rows are one dimension (default: source) and columns are another (default: status), with cell values = call counts.

Designed to answer "break down call volume by source and status for accounts X, Y, Z this week" in a single call instead of fanning out multiple filtered disposition reports.

Rows/cols dimensions: source, status, agent, tracking_number, receiving_number, tag, queue, day_of_week, campaign, campaign_id, keyword, ad_group, ad_group_id, ad_network, ad_match_type, medium, paid_source.

The campaign/keyword/ad_group dimensions read CTM's per-call "paid" attribution object (populated for Google/Bing/Meta click-through calls) — this is real ad-platform data, not CTM's own tracking-source label ("source"/"paid_source" above is that CTM label; "paid_source" pulls the ad platform itself, e.g. "google"). For Search traffic, Google sometimes withholds keyword-level text for privacy reasons even when the call is clearly attributable — campaign_id and ad_group_id are numeric IDs and much more reliably populated than the human-readable "campaign"/"keyword" names, so prefer those two when the readable names come back mostly "(not provided)".

Use start_date/end_date (ISO format) or time_duration (e.g. 'today', 'yesterday', 'wtd', 'last7days'). Increase max_calls for accounts with heavy volume.

Pass exclude_status (e.g. 'in progress') to omit in-flight calls for a point-in-time completed-calls view. Live calls that haven't finished ring as 'in progress' — they're counted by default since this is a real-time snapshot, but if you want only terminal states (answered, no answer, failed, etc.), pass exclude_status='in progress'.

account_ledgerA

Get billing/ledger data across sub-accounts.

Shows usage charges for the given date range.

Only queries active sub-accounts by default. Pass account_status="archived", "canceled", "paused", or "all" to query other sub-accounts.

account_summaryA

Get a high-level summary of each sub-account's configuration.

Shows account status, number counts, source counts, and active routing objects (queues, voice menus, schedules).

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

reports_seriesA

Get time-series call data aggregated by dimension across sub-accounts.

Uses the CTM Reports Series API to return call counts broken down by the requested dimension. This is the most flexible reporting endpoint — supports 40+ dimensions for slicing call data.

Required: start_date, end_date (ISO format, e.g. 2026-01-01) by: dimension to aggregate on (use reports_series_dimensions for the full list) interval: time granularity — hour, day (default), month, year

If the response comes back empty (items=0), the output includes the envelope keys so the request can be debugged without checking server logs.

Known limitation: this endpoint occasionally returns items=0 even for accounts with known call volume. When it works it's server-side fast; when it doesn't, fall back to call_disposition_report for the same data (client-side aggregation, works reliably).

Optional filters: direction: inbound, outbound, form, msg_inbound, msg_outbound multi_tracking_numbers + operator: filter by tracking number IDs multi_receiving_numbers + operator: filter by receiving number IDs ring_time/talk_time/duration + operator: filter by time thresholds multi_tags + operator: filter by tag names Operators: includes, excludes, less_than, less_than_equal, greater_than, greater_than_equal, equal

reports_series_dimensionsA

List available dimensions for the reports_series tool.

These are the values you can pass to the 'by' parameter.

list_textsA

List SMS/text messages across sub-accounts.

Useful for auditing text communication across all client accounts.

Fetches up to max_items texts per account, paging automatically (CTM caps per_page at ~100, so this walks as many pages as needed rather than returning just the first one) — raise max_items for accounts with heavy text volume or narrow start_date/end_date instead; a truncation warning is included if any account had more than max_items.

Defaults to active sub-accounts only. Pass status="archived", "canceled", "paused", or "all" to include others.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CTMJSON/ctm-multi-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server