Skip to main content
Glama
wiesson

sipgate-mcp

by wiesson

sipgate-mcp

sipgate-mcp is an open-source, self-hosted Model Context Protocol server for inspecting and configuring a sipgate account. It exposes the sipgate REST API v2 as focused tools for agents such as Claude Code, Claude Desktop, and Codex.

Version 0.2 and later default to user-scoped access: tools are constrained to the authenticated sipgate user's resources. Account-wide access is an explicit administrator-only mode.

The server uses stdio only. It does not start an HTTP server or route credentials through a third-party service. It sends authentication only from the local MCP process directly to https://api.sipgate.com/v2.

Agent-assisted setup

Tell Codex or Claude:

Set up sipgate MCP by following https://raw.githubusercontent.com/wiesson/sipgate-mcp/main/SKILL.md

The linked, versioned SKILL.md tells the agent how to install and verify the matching package without asking for credentials in chat. Secret entry remains an interactive local Keychain step controlled by the user.

Related MCP server: Retell AI MCP Server

Requirements

  • Node.js 22 or newer

  • A sipgate account with a Personal Access Token (PAT)

  • An MCP client with stdio support

Install the command globally with any of the supported package managers:

npm install --global sipgate-mcp
pnpm add --global sipgate-mcp
vp install --global sipgate-mcp

On macOS, run the interactive setup once:

sipgate-mcp setup

The setup stores the PAT token ID and token in macOS Keychain without placing either value in shell history or an MCP configuration file. It registers every installed supported client (Codex and Claude Code) in user scope. An interactive setup asks whether to enable write tools; a non-interactive setup without a mode flag registers read-only. Those clients start and stop the stdio server automatically; sipgate-mcp does not run as a daemon and does not need to be started manually.

Use sipgate-mcp setup --client codex or --client claude to configure only one client. --allow-writes and --read-only pick the mode without being asked; write tools let the assistant place calls, send SMS/faxes, and configure routing, devices, phonelines, voicemail, greetings, recordings, faxlines, contacts, blocklists, call restrictions, history, portings, and sipgate.io. --dry-run prints the secret-free registration commands without changing the Keychain or client configuration. Repeated setup runs reuse existing Keychain credentials; use --replace-credentials only to rotate the stored PAT-ID and PAT.

During first setup, macOS calls both secure inputs password data. The setup labels the steps explicitly: enter the sipgate PAT-ID twice in step 1, then the sipgate PAT twice in step 2. Input remains hidden while typing.

Secure interactive storage currently supports macOS. Environment variables remain available for Linux, Windows, containers, CI, and password-manager wrappers. To avoid putting literal credentials in shell history, read them interactively:

printf "sipgate PAT token ID: "
IFS= read -r SIPGATE_TOKEN_ID
printf "sipgate PAT token: "
IFS= read -rs SIPGATE_TOKEN
printf "\n"
export SIPGATE_TOKEN_ID SIPGATE_TOKEN
export SIPGATE_MCP_SCOPE="user"
export SIPGATE_MCP_READONLY="1"

For clients that manage MCP commands on demand, npx -y sipgate-mcp remains supported without a global installation.

Create a Personal Access Token

  1. Open sipgate Personal Access Tokens.

  2. Select Add token, give the token a recognizable name, and select the scopes needed for the tools you intend to use.

  3. Copy both the token ID and token. sipgate displays the token itself only once.

  4. Run sipgate-mcp setup on macOS, or provide them as SIPGATE_TOKEN_ID and SIPGATE_TOKEN in the MCP process environment.

sipgate PAT authentication uses HTTP Basic Auth with token-id:token as the credential pair. sipgate-mcp constructs that header in memory. See sipgate's authentication guide.

Do not put either value in this repository, an MCP config committed to source control, shell command arguments, command output, or an issue report.

The separate API Clients screen in the sipgate account creates OAuth 2.0 client credentials for an application that redirects users through sipgate's authorization flow. Those client credentials are not PAT replacements and are not used by the local stdio setup. They are relevant to a future hosted/remote MCP, which would need a registered redirect URI, user consent, access-token refresh, and secure per-user token storage. See sipgate's OAuth authentication flow and API client management.

MCP access scopes

SIPGATE_MCP_SCOPE controls the resource boundary enforced by the MCP in addition to sipgate's own user role and PAT scopes:

Value

Behavior

user (default)

Resolves the authenticated user through /authorization/userinfo; returns only that user and their assigned numbers, notifications, faxlines, phonelines, voicemails, greetings, and attached devices; forces user-specific device, routing, restriction, and settings reads; constrains history reads, exports, and mutations to owned connections/entries; and validates every write target against owned numbers, phonelines, nested voicemail/forwarding/greeting resources, devices, faxlines, notifications, or emergency addresses associated with an owned device/number. Account-wide contact, blacklist, porting-cancellation, and sipgate.io writes require confirm_account_wide: true; their reads are allowed and clearly labelled account-wide.

account

Enables account-wide reads and writes. Startup fails unless /users/{authenticatedUserId} reports admin: true. Requires users:read for the administrator check.

Token scopes are permission ceilings, not role elevation. For example, numbers:write does not turn a regular sipgate user into an administrator. The effective permission is the intersection of the sipgate user role, PAT scopes, MCP access scope, and read-only mode.

Use account scope only when account-wide administration is intended:

export SIPGATE_MCP_SCOPE="account"
npx -y sipgate-mcp

Tools and PAT scopes

Every mode identifies the authenticated user with GET /authorization/userinfo. The table lists the non-all scopes named by sipgate's live Swagger document, including ownership checks performed in user scope and pre/post state reads. sipgate also exposes broader parent scopes such as sessions:write; select the listed specific and parent scopes offered by the PAT UI when in doubt.

Tool

Access

sipgate API calls

PAT scopes

account_info

Read

User: cached /authorization/userinfo; account: plus GET /account

Account: account:read (userinfo has no scope declaration in Swagger)

list_users

Read

User: GET /users/{self}; account: GET /users

users:read

list_numbers

Read

User: own phonelines, or owned devices plus paginated GET /numbers when phonelines are unavailable; account: GET /numbers

User: phonelines:read, phonelines:numbers:read; fallback: devices:read, numbers:read; account: numbers:read

list_devices

Read

User: GET /{self}/devices; account: GET /users, GET /{userId}/devices

devices:read; account also needs users:read when user_id is omitted

get_device

Read

Ownership GET /{self}/devices, then GET /devices/{deviceId}

devices:read

get_device_caller_id

Read

Device ownership read, then GET /devices/{deviceId}/callerid

devices:read, devices:callerid:read

get_device_local_prefix

Read

Device ownership read, then GET /devices/{deviceId}/localprefix

devices:read, devices:localprefix:read

get_device_tariff_announcement

Read

Device ownership read, then GET /devices/{deviceId}/tariffannouncement

devices:read, devices:tariffannouncement:read

get_device_single_row_display

Read

Device ownership read, then GET /devices/{deviceId}/singlerowdisplay

devices:read, devices:singlerowdisplay:read

get_device_contingents

Read

Device/user ownership reads, then GET /{userId}/devices/{deviceId}/contingents

devices:read

list_user_numbers

Read

GET /{userId}/numbers; this direct endpoint never uses phonelines

numbers:read

validate_quick_dial

Read

GET /numbers/quickdial/validation/{quickDialNumber}

numbers:read

list_addresses

Read

GET /addresses; user scope filters through owned device/number relationships

addresses:read; user ownership also needs devices:read, numbers:read and the applicable owned-number read scopes

get_address

Read

Address ownership reads, then GET /addresses/{addressId}

addresses:read; user ownership also needs devices:read, numbers:read and the applicable owned-number read scopes

list_address_numbers

Read

Address ownership reads, then GET /addresses/{addressId}/numbers

numbers:read, plus user ownership read scopes

get_routing

Read

User: own phonelines, numbers, and forwardings; account: also GET /numbers and GET /users

phonelines:read, phonelines:numbers:read, phonelines:forwardings:read; account also needs numbers:read and, when user_id is omitted, users:read

call_history

Read

User: ownership reads for own phonelines/devices, then filtered GET /history; account: GET /history

history:read; user also needs phonelines:read, devices:read

list_calls

Read

GET /calls; user scope filters calls to participants matching an owned device ID or phone number

rtcm:read; user ownership also needs devices:read, numbers:read and applicable owned-number scopes

list_notifications

Read

GET /{userId}/notifications

notifications:read

list_faxlines

Read

GET /{userId}/faxlines

faxlines:read

list_faxline_numbers

Read

User: faxline ownership read, then GET /{userId}/faxlines/{faxlineId}/numbers; account: direct GET

faxlines:read, faxlines:numbers:read

get_phoneline

Read

Owned-phoneline lookup, then GET /{userId}/phonelines/{phonelineId}

phonelines:read

get_phoneline_block_anonymous

Read

Owned-phoneline lookup, then GET /{userId}/phonelines/{phonelineId}/blockanonymous

phonelines:read, phonelines:blockanonymous:read

list_phoneline_devices

Read

Owned-phoneline/device filtering, then GET /{userId}/phonelines/{phonelineId}/devices

phonelines:read, phonelines:devices:read; user filtering also needs devices:read

list_parallel_forwardings

Read

Owned-phoneline lookup, then GET /{userId}/phonelines/{phonelineId}/parallelforwardings

phonelines:read, phonelines:parallelforwardings:read

list_phoneline_voicemails

Read

Owned-phoneline lookup, then GET /{userId}/phonelines/{phonelineId}/voicemails

phonelines:read, phonelines:voicemails:read

list_voicemail_greetings

Read

Owned phoneline/voicemail lookup, then GET /{userId}/phonelines/{phonelineId}/voicemails/{voicemailId}/greetings

phonelines:read, phonelines:voicemails:read, phonelines:voicemails:greetings:read

list_voicemails

Read

GET /voicemails; user scope filters by voicemail IDs discovered under owned phonelines

voicemails:read; user filtering also needs phonelines:read, phonelines:voicemails:read

get_voicemail

Read

Owned-voicemail lookup, then GET /voicemails/{voicemailId}

voicemails:read; user ownership also needs phonelines:read, phonelines:voicemails:read

list_autorecording_greetings

Read

Account scope only: GET /autorecordings/greetings; the account-global resource has no user ownership link

autorecording:greeting:read; sipgate also requires administrator privileges and activated call recording

get_autorecording_settings

Read

Owned phoneline/faxline extension lookup, then GET /autorecordings/{extension}/settings

devices:read; ownership also needs phonelines:read, faxlines:read

get_faxline_caller_id

Read

Owned-faxline lookup, then GET /{userId}/faxlines/{faxlineId}/callerid

faxlines:read

create_phoneline

Write/action

POST /{userId}/phonelines; 403/404 becomes a clean unavailable result

phonelines:write

update_phoneline_alias

Write

Owned-phoneline before/after reads and PUT /{userId}/phonelines/{phonelineId}

phonelines:read, phonelines:write

delete_phoneline

Write

Owned-phoneline before-state read and DELETE /{userId}/phonelines/{phonelineId}

phonelines:read, phonelines:write

set_phoneline_block_anonymous

Write

Owned-phoneline setting reads and PUT /{userId}/phonelines/{phonelineId}/blockanonymous

phonelines:read, phonelines:blockanonymous:read, phonelines:blockanonymous:write

attach_device_to_phoneline

Write/action

Owned phoneline/device reads, pre/post assignment reads, and POST /{userId}/phonelines/{phonelineId}/devices

phonelines:read, phonelines:devices:read, phonelines:devices:write, devices:read

detach_device_from_phoneline

Write

Owned phoneline/device reads, pre/post assignment reads, and DELETE /{userId}/phonelines/{phonelineId}/devices/{deviceId}

phonelines:read, phonelines:devices:read, phonelines:devices:write, devices:read

create_parallel_forwarding

Write/action

Owned-phoneline check, pre/post forwarding reads, and POST /{userId}/phonelines/{phonelineId}/parallelforwardings

phonelines:read, phonelines:write, phonelines:parallelforwardings:read, phonelines:parallelforwardings:write

update_parallel_forwarding

Write

Verify forwarding in the owned phoneline, pre/post reads, and PUT /{userId}/phonelines/{phonelineId}/parallelforwardings/{parallelForwardingId}

phonelines:read, phonelines:write, phonelines:parallelforwardings:read, phonelines:parallelforwardings:write

delete_parallel_forwarding

Write

Verify forwarding in the owned phoneline, pre/post reads, and DELETE /{userId}/phonelines/{phonelineId}/parallelforwardings/{parallelForwardingId}

phonelines:read, phonelines:write, phonelines:parallelforwardings:read, phonelines:parallelforwardings:write

update_voicemail

Write

Verify voicemail in the owned phoneline, pre/post voicemail reads, and PUT /{userId}/phonelines/{phonelineId}/voicemails/{voicemailId}

phonelines:read, phonelines:write, phonelines:voicemails:read, phonelines:voicemails:write

create_voicemail_greeting

Write/action

Verify owned voicemail, pre/post greeting reads, and POST /{userId}/phonelines/{phonelineId}/voicemails/{voicemailId}/greetings

phonelines:read, phonelines:write, phonelines:voicemails:read, phonelines:voicemails:write, phonelines:voicemails:greetings:read, phonelines:voicemails:greetings:write

update_voicemail_greeting

Write

Verify greeting under the owned voicemail, pre/post reads, and PUT /{userId}/phonelines/{phonelineId}/voicemails/{voicemailId}/greetings/{greetingId}

Same phoneline/voicemail/greeting read/write scopes as greeting creation

delete_voicemail_greeting

Write

Verify greeting under the owned voicemail, pre/post reads, and DELETE /{userId}/phonelines/{phonelineId}/voicemails/{voicemailId}/greetings/{greetingId}

Same phoneline/voicemail/greeting read/write scopes as greeting creation

set_voicemail_transcription

Write

Verify owned voicemail, pre/post voicemail reads, and PUT /{userId}/phonelines/{phonelineId}/voicemails/{voicemailId}/transcriptions

phonelines:read, phonelines:write, phonelines:voicemails:read, phonelines:voicemails:write

play_voicemail

Write/action

User: verify owned device and history/data entry; then POST /sessions/voicemail/play

sessions:write, sessions:calls:write; user ownership also needs devices:read, history:read and owned-connection scopes

record_voicemail_greeting

Write/action

User: verify owned device and target voicemail; then POST /sessions/voicemail/recording

sessions:write, sessions:calls:write; user ownership also needs devices:read, phonelines:read, phonelines:voicemails:read

create_autorecording_greeting

Write/action

Account scope only: pre/post GET /autorecordings/greetings, POST /autorecordings/greetings

autorecording:greeting:read, autorecording:greeting:write; sipgate requires administrator privileges and activated call recording

delete_autorecording_greeting

Write

Account scope only: before-state read, then DELETE /autorecordings/greetings/{greetingId}

autorecording:greeting:read, autorecording:greeting:write; sipgate requires administrator privileges and activated call recording

set_autorecording_settings

Write

Owned phoneline/faxline extension lookup, pre/post setting reads, and PUT /autorecordings/{extension}/settings

devices:read; ownership also needs phonelines:read, faxlines:read

create_faxline

Write/action

POST /{userId}/faxlines

faxlines:write

update_faxline_alias

Write

Owned-faxline pre/post list reads and PUT /{userId}/faxlines/{faxlineId}

faxlines:read, faxlines:write

delete_faxline

Write

Owned-faxline before-state read and DELETE /{userId}/faxlines/{faxlineId}

faxlines:read, faxlines:write

set_faxline_caller_id

Write

Owned faxline/number checks, pre/post caller-ID reads, and PUT /{userId}/faxlines/{faxlineId}/callerid

faxlines:read, faxlines:write, plus owned-number read scopes

set_faxline_tagline

Write

Owned-faxline pre/post list reads and PUT /{userId}/faxlines/{faxlineId}/tagline

faxlines:read, faxlines:write

get_settings

Read

GET /users[/userId], GET /{userId}/devices, GET /{userId}/phonelines[/phonelineId]

users:read, devices:read, phonelines:read

list_contacts

Read, account-wide

GET /contacts with phone, scope, and pagination filters

contacts:read

get_contact

Read, account-wide

GET /contacts/{contactId}

contacts:read

list_internal_contacts

Read, account-wide

Deprecated GET /contacts/internal compatibility route

contacts:read

export_contacts_csv

Read, account-wide

GET /contacts/csv and return CSV text

contacts:read

get_contacts_vcard

Read, account-wide

GET /contacts/vcard with structured-vCard filters

contacts:read

create_contact

Write/action, account-wide

POST /contacts; user scope requires confirm_account_wide: true

contacts:write

update_contact

Write, account-wide

Before/after GET /contacts/{contactId}, then PUT on the same path; confirmation required in user scope

contacts:read, contacts:write

delete_contact

Destructive write, account-wide

Before-state GET, then DELETE /contacts/{contactid}; confirmation required in user scope

contacts:read, contacts:write

delete_contacts

Destructive write, account-wide

Before-state contact reads, then DELETE /contacts; omitted filters delete all; confirmation required in user scope

contacts:read, contacts:write

import_contacts_csv

Destructive write/action, account-wide

Pre/post GET /contacts, then POST /contacts/import/csv; confirmation required in user scope

contacts:read, contacts:write

put_contacts_vcard

Write, account-wide

Pre/post GET /contacts/vcard, then PUT /contacts/vcard; supplied IDs are overwritten; confirmation required in user scope

contacts:read, contacts:write

list_incoming_blacklist

Read, account-wide

GET /blacklist/incoming

blacklist:read

add_incoming_blacklist

Write/action, account-wide

Pre/post blacklist reads, then POST /blacklist/incoming; confirmation required in user scope

blacklist:read, blacklist:write

remove_incoming_blacklist

Write, account-wide

Before-state blacklist read, then DELETE /blacklist/incoming/{phoneNumber}; confirmation required in user scope

blacklist:read, blacklist:write

list_call_restrictions

Read

User scope forces the authenticated ID in GET /callrestrictions; account scope accepts selected IDs

callrestrictions:read

set_call_restriction

Write

Pre/post restriction reads, then POST /{authenticatedUserId}/callrestrictions/{restriction}

callrestrictions:read, callrestrictions:write

list_restrictions

Read

GET /restrictions; user scope accepts only the authenticated user ID

Swagger declares the internal scope

export_history

Read

User: owned-connection-filtered GET /history/export; account: filtered or account-wide export

history:read; user ownership also needs phonelines:read, devices:read

set_history_read

Write

Owned-entry check, pre/post GET /history/{entryId}, then PUT /history/{entryId}/read

history:read, history:write; user ownership also needs connection read scopes

set_history_note

Write

Owned-entry check, pre/post entry reads, then PUT /history/{entryId}/note

history:read, history:write; user ownership also needs connection read scopes

set_history_archive

Write

Owned-entry check, pre/post entry reads, then PUT /history/{entryId}/archive

history:read, history:write; user ownership also needs connection read scopes

update_history_entry

Write

Owned-entry check, pre/post entry reads, then PUT /history/{entryId}

history:read, history:write; user ownership also needs connection read scopes

delete_history_entry

Destructive write

Owned-entry and before-state reads, then DELETE /history/{entryId}

history:read, history:write; user ownership also needs connection read scopes

update_history_entries

Write

Verify every entry, read before/after state, then PUT /history with fewer than 150 entries

history:read, history:write; user ownership also needs connection read scopes

delete_history_entries

Destructive write

DELETE /history; user scope expands omission to IDs enumerated through owned connection filters and never sends an unconstrained delete

history:read, history:write; user ownership also needs phonelines:read, devices:read

get_balance

Read, account-wide

GET /balance

balance:read

list_portings

Read, account-wide

GET /portings

portings:read

get_porting

Read, account-wide

GET /portings/{portingId}

portings:read

cancel_porting

Destructive write, account-wide

Before-state GET, then DELETE /portings/{portingId}; always requires confirm_account_wide: true

portings:read, portings:write

get_sipgateio_settings

Read, account-wide

GET /settings/sipgateio; 403/404 returns an unavailable result

settings:read, settings:sipgateio:read

update_sipgateio_settings

Write, account-wide

Pre/post settings reads, then PUT /settings/sipgateio; confirmation required in user scope

settings:read, settings:write, settings:sipgateio:read, settings:sipgateio:write

list_webhook_logs

Read, account-wide

GET /log/webhooks; 403/404 returns an unavailable result

log:webhooks:read

set_number_routing

Write

User: pre/post reads through own phonelines; account: pre/post GET /numbers; all modes: PUT /numbers/{numberId}

numbers:write; user also needs phonelines:read, phonelines:numbers:read; account needs numbers:read

set_forwarding

Write

User: phoneline ownership read; then pre/post forwarding reads and PUT

phonelines:read, phonelines:write, phonelines:forwardings:read, phonelines:forwardings:write

set_dnd

Write

User: device ownership read; then pre/post GET /devices/{deviceId} and PUT

devices:read, devices:write

update_device

Write

Device and optional emergency-address ownership reads; pre/post GET plus PUT /devices/{deviceId}

devices:read, devices:write; address ownership may also need numbers:read and owned-number read scopes

delete_device

Write

Device ownership and before-state reads, then DELETE /devices/{deviceId}

devices:read, devices:write

set_device_alias

Write

Device ownership read; pre/post device reads and PUT /devices/{deviceId}/alias

devices:read, devices:write

set_device_caller_id

Write

Device and caller-number ownership reads; pre/post caller-ID reads and PUT /devices/{deviceId}/callerid

devices:read, devices:write, devices:callerid:read, devices:callerid:write, plus owned-number read scopes

set_device_local_prefix

Write

Device ownership read; pre/post setting reads and PUT /devices/{deviceId}/localprefix

devices:read, devices:write, devices:localprefix:read, devices:localprefix:write

set_device_tariff_announcement

Write

Device ownership read; pre/post setting reads and PUT /devices/{deviceId}/tariffannouncement

devices:read, devices:write, devices:tariffannouncement:read, devices:tariffannouncement:write

set_device_single_row_display

Write

Device ownership read; pre/post setting reads and PUT /devices/{deviceId}/singlerowdisplay

devices:read, devices:write, devices:singlerowdisplay:read, devices:singlerowdisplay:write

set_external_device_target_number

Write

Device ownership read; pre/post device reads and PUT /devices/{deviceId}/external/targetnumber

devices:read, devices:write

set_external_device_incoming_call_display

Write

Device ownership read; pre/post device reads and PUT /devices/{deviceId}/external/incomingcalldisplay

devices:read, devices:write

change_device_password

Write/action

Device ownership/before-state reads, then POST /devices/{deviceId}/credentials/password; the response is redacted

devices:read, devices:write

create_register_device

Write/action

POST /{userId}/devices/register

devices:write

create_mobile_device

Write/action

POST /{userId}/devices/mobile

devices:write

create_external_device

Write/action

POST /{userId}/devices/external

devices:write

create_quick_dial

Write/action

POST /numbers/quickdial

numbers:write

update_quick_dial

Write

Owned-number before/after reads and PUT /numbers/quickdial/{quickdialId}

numbers:read, numbers:write, plus applicable owned-number read scopes

delete_quick_dial

Write

Owned-number before-state read and DELETE /numbers/quickdial/{numberId}

numbers:read, numbers:write, plus applicable owned-number read scopes

update_address

Write

Address ownership and pre/post address reads, then PUT /addresses/{addressId}

addresses:read, addresses:write, plus user ownership read scopes

send_sms

Write/action

GET /{userId}/sms, pre/post GET /history, POST /sessions/sms

sms:read, history:read, sessions:write, sessions:sms:write

initiate_call

Write/action

User: device/number ownership reads, then POST /sessions/calls; account: pre/post GET /calls plus POST

sessions:write, sessions:calls:write; user also needs devices:read, phonelines:read, phonelines:numbers:read; account needs rtcm:read

create_call_email_notification

Write/action

User: endpoint ownership reads; all modes: pre/post GET /{userId}/notifications, POST /{userId}/notifications/call/email

notifications:read, notifications:write; user also needs devices:read or phonelines:read

create_call_sms_notification

Write/action

User: endpoint ownership reads; all modes: pre/post notification reads, POST /{userId}/notifications/call/sms

notifications:read, notifications:write; user also needs devices:read or phonelines:read

create_fax_email_notification

Write/action

User: faxline ownership read; all modes: pre/post notification reads, POST /{userId}/notifications/fax/email

notifications:read, notifications:write; user also needs faxlines:read

create_fax_sms_notification

Write/action

User: faxline ownership read; all modes: pre/post notification reads, POST /{userId}/notifications/fax/sms

notifications:read, notifications:write; user also needs faxlines:read

create_fax_report_notification

Write/action

User: faxline ownership read; all modes: pre/post notification reads, POST /{userId}/notifications/fax/report

notifications:read, notifications:write; user also needs faxlines:read

create_sms_email_notification

Write/action

Pre/post notification reads, POST /{userId}/notifications/sms/email

notifications:read, notifications:write

create_voicemail_email_notification

Write/action

Pre/post notification reads, POST /{userId}/notifications/voicemail/email

notifications:read, notifications:write

create_voicemail_sms_notification

Write/action

Pre/post notification reads, POST /{userId}/notifications/voicemail/sms

notifications:read, notifications:write

delete_notification

Write

User: verify the nested ID in GET /{userId}/notifications; all modes: before/after notification reads and DELETE /{userId}/notifications/{notificationId}

notifications:read, notifications:write

hangup_call

Write

User: participant ownership read; all modes: before/after GET /calls, DELETE /calls/{callId}

rtcm:read, rtcm:write; user also needs owned-device/number read scopes

set_call_hold

Write

User: participant ownership read; before/after GET /calls, PUT /calls/{callId}/hold

rtcm:read, rtcm:write; user also needs owned-device/number read scopes

set_call_muted

Write

User: participant ownership read; before/after GET /calls, PUT /calls/{callId}/muted

rtcm:read, rtcm:write; user also needs owned-device/number read scopes

set_call_recording

Write

User: participant ownership read; before/after GET /calls, PUT /calls/{callId}/recording

rtcm:read, rtcm:write; user also needs owned-device/number read scopes

transfer_call

Write/action

User: call-participant and optional caller-ID ownership reads; before/after GET /calls, POST /calls/{callId}/transfer

rtcm:read, rtcm:write; user also needs owned-device/number read scopes

send_call_dtmf

Write/action

User: participant ownership read; before/after GET /calls, POST /calls/{callId}/dtmf

rtcm:read, rtcm:write; user also needs owned-device/number read scopes

start_call_announcement

Write/action

User: participant ownership read; before/after GET /calls, POST /calls/{callId}/announcements

rtcm:read, rtcm:write; user also needs owned-device/number read scopes

send_fax

Write/action

User: faxline ownership read; POST /sessions/fax

sessions:write, sessions:fax:write; user also needs faxlines:read

resend_fax

Write/action

User: required faxline ownership read; POST /sessions/fax/resend

sessions:write, sessions:fax:write; user also needs faxlines:read

Every write tool returns a JSON object with before and after. Where a resource can be read, the tool reads current state first and reads it back after the change. Fax send/resend, voicemail playback/recording, and contact creation use before: null and return an explicit no-read-back note where sipgate exposes no synchronous identity/state; deletes return the previous state and a deletion marker. SMS history can update asynchronously, and /calls only contains established calls.

Tool notes

  • list_devices resolves devices through users because the documented account-wide route is GET /{userId}/devices; the live v2 Swagger document does not define GET /devices.

  • list_user_numbers calls the documented direct GET /{userId}/numbers endpoint and never uses phonelines. Ownership checks retain the device-based fallback required by accounts without a phoneline layer.

  • Every phoneline-dependent tool treats sipgate HTTP 403/404 as feature absence. On accounts where numbers hang directly from a device, reads return phonelinesAvailable: false and writes return changed: false without attempting the mutation. An available but empty phoneline list still denies every supplied phoneline ID.

  • User scope establishes nested ownership from the documented collections: parallel forwardings under an owned phoneline, voicemails under an owned phoneline, greetings under an owned voicemail, and attached devices that are independently owned. Global /voicemails results are filtered to those discovered IDs.

  • Voicemail playback requires an owned device and an owned history/data entry in user scope. The live Swagger request field is spelled datadId; the MCP exposes the clearer data_id and maps it without changing the API payload. Voicemail greeting recording requires an owned device and target voicemail in user scope.

  • Automated recording settings accept only an extension found in the authenticated user's phonelines or faxlines. The automated-recording greeting is account-global and has no user ownership relationship, so its read/create/delete tools fail closed in user scope and require administrator account scope. sipgate additionally requires activated call recording.

  • User scope never calls account-wide GET /users. It calls paginated account GET /numbers only for the device-based ownership fallback when phonelines are unavailable.

  • User-scoped number-routing snapshots are also resolved through owned phonelines, and user-scoped Click2Dial deliberately omits account-wide /calls snapshots.

  • User-scoped list_calls and every live-call mutation read the account-wide /calls feed but expose or operate on a call only when at least one participant's participantId matches an owned device or phoneNumber matches an owned phone number. A missing, unknown, or unreadable match fails closed. sipgate's Swagger does not expose a separate call-owner user or device field.

  • Notification IDs live inside the nested email/SMS/report target arrays returned by GET /{userId}/notifications; deletion verifies that nested ID before sending the request. Call-notification endpoints are checked against owned devices/phonelines, and fax notifications against owned faxlines.

  • Fax send and resend actions incur charges. In user scope resend_fax requires faxline_id even though sipgate marks it optional, because omitting it leaves no documented ownership relationship that can be verified before the chargeable action.

  • Contacts and the incoming blacklist are account-wide sipgate resources. Their reads remain available in user scope, but every write requires confirm_account_wide: true; CSV import and contact/history deletion are described as destructive. Porting cancellation always requires the same explicit confirmation and is irreversible through v2.

  • Every single-entry history mutation verifies connectionIds against the authenticated user's owned device/phoneline IDs. User-scoped bulk updates verify every entry. An omitted ID list on bulk deletion is expanded by paging both archived and unarchived history through owned connection filters, then deleting only those IDs; an unconstrained DELETE /history is never sent in user scope.

  • set_call_restriction never accepts a user ID: the backend resolves /authorization/userinfo and posts only to /{authenticatedUserId}/callrestrictions/{restriction}. list_call_restrictions and list_restrictions reject foreign users in user scope.

  • Balance, portings, global sipgate.io settings, and webhook logs are account-wide reads that remain visible in user scope. Updating global sipgate.io settings requires account-wide confirmation in user scope. sipgate.io settings/log endpoints translate 403/404 into explicit unavailable results.

  • Call and automated recording can incur charges and are legally sensitive. In Germany the caller is responsible for obtaining consent from every participant; changing or disabling an announcement does not remove that responsibility. Voicemail playback/recording initiates a call and may also incur charges.

  • Address IDs are exposed as integers because sipgate declares every address path parameter as int32. In user scope an address is visible or mutable only when an owned device references it, an owned number contains its addressId, or /addresses/{addressId}/numbers contains an owned number.

  • Device creation can affect billing, and changing an address can deactivate associated telephone numbers depending on country. Every write-tool description advertises the account change and potential charges.

  • Device password rotation intentionally redacts the complete credential container, including sipgate's one-time password response.

  • Number routing uses sipgate's documented endpointId. Obtain existing IDs from the read tools; a phoneline ID such as p0 is the documented example.

  • set_forwarding replaces the complete phoneline forwarding list. Pass forwardings: [] to remove all forwardings. A timeout of 0 represents immediate forwarding.

  • send_sms refuses to post unless GET /{userId}/sms returns the requested (or first available) SMS extension.

  • sipgate documents POST /sessions/calls as the classic-PBX Click2Dial route. Live established-call reads and controls use /calls; starting a new Neo PBX call through the separate POST /calls shape is outside this batch.

Read-only mode

Set SIPGATE_MCP_READONLY=1 to register only the 47 read tools. Write tools are absent from tools/list, rather than merely failing when called.

export SIPGATE_MCP_READONLY=1
export SIPGATE_MCP_SCOPE=user
npx -y sipgate-mcp

MCP client configuration

The recommended macOS path is sipgate-mcp setup. The following manual examples are useful for other platforms and custom launchers. Set SIPGATE_TOKEN_ID and SIPGATE_TOKEN in the environment that launches the MCP client; the examples keep secret values out of configuration files.

Claude Code

Claude Code expands ${VAR} references in MCP environment entries. Single quotes below prevent your shell from replacing the references before Claude stores them:

claude mcp add \
  --env 'SIPGATE_TOKEN_ID=${SIPGATE_TOKEN_ID}' \
  --env 'SIPGATE_TOKEN=${SIPGATE_TOKEN}' \
  --env SIPGATE_MCP_SCOPE=user \
  --transport stdio \
  --scope user \
  sipgate -- npx -y sipgate-mcp

Add --env SIPGATE_MCP_READONLY=1 before --transport for read-only mode. Replace the scope with account only for deliberate administrator access. Verify the connection with claude mcp get sipgate. See the official Claude Code MCP documentation.

Claude Desktop

Ensure the Claude Desktop process inherits SIPGATE_TOKEN_ID and SIPGATE_TOKEN, then add this entry to claude_desktop_config.json:

{
  "mcpServers": {
    "sipgate": {
      "command": "npx",
      "args": ["-y", "sipgate-mcp"]
    }
  }
}

Restart Claude Desktop after editing the file. Do not paste PAT values into the JSON. If the app was launched from a desktop shell rather than a terminal, configure the variables in that app's launch environment first.

Codex

Codex can forward named variables from its local environment without storing their values. Add this to ~/.codex/config.toml (or a trusted project's .codex/config.toml):

[mcp_servers.sipgate]
command = "npx"
args = ["-y", "sipgate-mcp"]
env_vars = ["SIPGATE_TOKEN_ID", "SIPGATE_TOKEN", "SIPGATE_MCP_SCOPE", "SIPGATE_MCP_READONLY"]

Export the variables before starting Codex, then use /mcp or codex mcp list to confirm the server. The env_vars forwarding form is documented in the official OpenAI MCP documentation.

Manual smoke test with MCP Inspector

This test makes real sipgate API calls. Start in user/read-only mode with a PAT containing phonelines:read and phonelines:numbers:read, plus the required environment variables:

export SIPGATE_TOKEN_ID="your-token-id"
export SIPGATE_TOKEN="your-token"
export SIPGATE_MCP_SCOPE="user"
export SIPGATE_MCP_READONLY=1
npx @modelcontextprotocol/inspector npx -y sipgate-mcp

The current Inspector v2 may require a more recent Node 22 minor release than the server itself. In the Inspector web UI:

  1. Connect to the stdio server.

  2. Open Tools and run account_info with {}.

  3. Run list_numbers with {"offset": 0, "limit": 100}.

  4. Confirm that the responses contain account/user metadata and numbers with endpointId assignments, and that no token or Authorization header is displayed.

The Inspector's ad-hoc stdio syntax is documented in its server configuration guide.

Architecture

The MCP layer depends only on the backend interface:

MCP stdio server
  -> validated tool definitions (Zod)
    -> user/account access policy
      -> TelephonyBackend
        -> SipgateBackend
          -> SipgateClient
            -> native fetch -> https://api.sipgate.com/v2

TelephonyBackend contains the stable, provider-neutral operations. SipgateBackend is the only v1 implementation, so a future second telephony provider can reuse the same MCP tool surface.

Security

  • PAT values are read from SIPGATE_TOKEN_ID and SIPGATE_TOKEN, or from the current user's macOS Keychain when both variables are absent.

  • sipgate-mcp setup delegates secret entry directly to the macOS Keychain prompt. Secret values are never passed as command-line arguments and are not written to Codex or Claude configuration.

  • User scope is the default and validates user IDs plus number, phoneline, nested voicemail/greeting/forwarding, device, faxline, call, recording- extension, and history ownership before delegation. Bulk history deletion is expanded to owned entry IDs, and account-wide writes require explicit confirmation where documented above.

  • Account scope fails startup unless the authenticated sipgate user reports admin: true.

  • The Basic Auth header exists only in memory and is sent only to the fixed sipgate API base URL.

  • API error bodies are discarded. User-facing errors never include request headers, response bodies, or credentials.

  • Potentially sensitive response properties such as credentials, password, token, and secret are redacted before tool output.

  • The server writes no application logs to stdout; stdout is reserved for MCP stdio frames.

  • .env*, fetched research data, build output, and package tarballs are ignored by Git.

  • Write tools clearly identify account changes and possible charges in their descriptions. Prefer read-only mode until write access is needed.

Development

npm install
npm run build
npm test

Tests use node:test and mocked fetch; they never call the real sipgate API. The suite includes client authentication/error behavior, user/account access-policy enforcement, exact critical write payloads, credential redaction, one test per MCP tool, and read-only registration.

Releases

Normal CI tests Node.js 22 and 24. Publishing a GitHub Release whose tag matches the version in package.json triggers an npm publish from a GitHub-hosted runner. The release workflow uses npm Trusted Publishing with OpenID Connect, contains no long-lived npm token, and produces npm provenance automatically. Stable GitHub Releases publish under npm's latest tag; GitHub prereleases use next.

Maintainer setup and the one-time first-publish procedure are documented in RELEASING.md.

API provenance and limitations

The endpoint paths, query parameters, request bodies, response models, and scope names were checked against sipgate's live public REST API v2 Swagger document and Swagger UI on 2026-08-30. PAT Basic Auth was checked against sipgate's public authentication guide. No authenticated production account was available during development, so real-account behavior remains to be confirmed with the smoke test above—especially product-specific availability, eventual history updates, and classic versus Neo PBX calling.

Roadmap

  • v0.1: local self-hosted stdio server and sipgate REST API tools

  • v0.2: user-scoped access by default plus explicit administrator-only account scope

  • Future: optional remote deployment, including a Cloudflare Workers backend, without changing the MCP tool surface

  • Additional TelephonyBackend implementation(s)

  • Product-aware Click2Dial behavior for classic and Neo PBX accounts

License

MIT © 2026 Arne Wiese. See LICENSE.

Available Tools

12 tools
account_infoA
Read-onlyIdempotent

Return sipgate account data and the authenticated user's identity.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the operation read-only, idempotent, non-destructive, and open-world, so the description does not need to restate those. It adds no behavioral detail beyond what the annotations and basic return statement convey, but it does not contradict them either.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence with no filler. Every word contributes to defining the tool's return value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-parameter read-only tool with comprehensive annotations, the description is largely sufficient. The only gap is that 'account data' is not enumerated, and there is no output schema to clarify the return shape, but the identity mention provides reasonable context for an agent to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there is no parameter meaning for the description to add. Per the rubric, the no-parameter case receives a baseline of 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a clear verb ('Return') and identifies the resource: sipgate account data plus the authenticated user's identity. 'Account data' is somewhat broad, but the identity clause makes the tool's purpose distinct from siblings like list_users and get_settings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is given about when to use this tool versus alternatives such as list_users or get_settings. The intended use is implied by the description, but there are no explicit context signals, exclusions, or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

call_historyA
Read-onlyIdempotent

List paginated call history with optional direction, time-range, number, and connection filters.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNoInclusive ISO 8601 end date-time
fromNoInclusive ISO 8601 start date-time
limitYes
offsetYes
directionsNo
phone_numberNoOnly calls to or from this phone number
connection_idsNoOptional sipgate extension IDs

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already communicate readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds that the result is paginated and that filters are optional, but it does not disclose ordering, response shape, rate limits, or authentication requirements. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with the verb front-loaded, the core resource named, and the optional filters summarized. Every word earns its place; no redundant or vague filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list operation, the description plus the detailed schema provide enough to select and invoke the tool correctly: required offset/limit are in the schema, optional filters are summarized, and annotations cover safety. The main missing context is the response shape and default behavior when no time range is provided, but that does not block correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 57%, and the description adds value by grouping filters (direction, time-range, number, connection) that map to directions, from/to, phone_number, and connection_ids. However, it does not clarify limit, offset, or the directions enum values, so it only partially compensates for missing schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'List paginated call history', and enumerates the optional filter dimensions (direction, time-range, number, connection). This clearly identifies what the tool does and distinguishes it from siblings like send_sms, initiate_call, and list_users by its unique resource.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The intended use is implied by the phrase 'List paginated call history', so an agent can infer this is the read-only history lookup tool. However, there is no explicit guidance about when to use it versus alternatives, nor any exclusions or routing to sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_routingA
Read-onlyIdempotent

Return number-to-endpoint routing plus each user's phonelines, assigned numbers, and active or timeout forwardings.

ParametersJSON Schema
NameRequiredDescriptionDefault
user_idNoLimit phoneline forwarding details to one sipgate user ID

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint, idempotentHint, non-destructive), so the description does not need to restate it. It adds useful context about the response scope, including that forwardings can be active or timeout, but does not disclose return format, pagination, or how the optional user_id affects the routing portion. This is modest added context, not a rich behavioral profile.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence front-loads the action ('Return') and packs the full scope into a compact list. There is no filler or repetition of annotation details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description is the primary source for return-value semantics, and it enumerates the main data categories: routing, phonelines, assigned numbers, and forwardings. It stops short of explaining terms like 'endpoint' or the exact behavior when user_id is omitted, but for a read-only retrieval tool with annotations covering safety, this is nearly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter, user_id, is already fully documented in the schema with a clear description ('Limit phoneline forwarding details to one sipgate user ID'), so schema coverage is 100%. The tool description does not add further parameter semantics; the baseline 3 applies because the schema carries the burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the explicit verb 'Return' followed by a specific composite resource: number-to-endpoint routing, per-user phonelines, assigned numbers, and active/timeout forwardings. This content clearly distinguishes it from sibling tools like list_numbers, list_users, and set_number_routing, which cover narrower or mutating operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the tool is for retrieving routing and forwarding configuration, but it never states when to choose it over get_settings, list_numbers, or list_users, nor does it provide exclusions or conditions. The usage context is inferable but not explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_settingsA
Read-onlyIdempotent

Return relevant user reachability settings, device availability/DND state, and phoneline voicemail activation and timeout settings.

ParametersJSON Schema
NameRequiredDescriptionDefault
user_idNoLimit settings to one sipgate user ID

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the tool read-only, idempotent, open-world, and non-destructive, so the description's 'Return' aligns with these. The description adds useful scoping about which settings are included, but does not disclose extra behaviors such as response variability or authorization requirements. With rich annotations, this is adequate but not exceptional.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One dense, well-structured sentence that front-loads the verb and lists the three distinct setting categories. Every phrase adds value, and there is no repetition of schema or annotation information. It is concise without omitting important scope.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only tool with one optional parameter and no output schema, the description covers the key return categories and lets the agent decide whether it needs this data. The openWorldHint annotation partially accounts for an unspecified response shape, and the sibling list provides enough context to differentiate it. It could enumerate some concrete field names, but that is not essential for selection and invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single optional user_id parameter has 100% schema description coverage ('Limit settings to one sipgate user ID'), so the schema carries the parameter semantics. The tool description does not add parameter-specific detail, but none is needed given full schema coverage. A baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'Return' and names a clear resource: user reachability settings, device availability/DND state, and voicemail settings. This distinguishes it from sibling tools like set_dnd (which mutates DND) and get_routing (which returns routing config). The scope is concrete and agent-actionable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context on what settings are returned, so an agent can infer when to call this tool versus alternatives like set_dnd or list_devices. It does not explicitly state exclusions or name alternatives, but the specificity of the returned categories provides sufficient guidance for read-only settings lookups.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

initiate_callA
Destructive

CHANGES THE SIPGATE ACCOUNT AND MAY INCUR CHARGES: start a Click2Dial call. Reads established calls before and after and returns the new session; ringing calls may not appear immediately.

ParametersJSON Schema
NameRequiredDescriptionDefault
calleeYes
callerYessipgate device ID or caller phone number
caller_idNoOptional number displayed to the callee
device_idNoRequired by sipgate when caller is a phone number instead of a device ID

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description adds crucial behavioral detail: it may incur charges, it reads established calls before and after, returns the new session, and warns that ringing calls may not appear immediately. This goes well beyond the structured annotation fields and helps the agent anticipate side effects and timing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence that front-loads the most important warning, states the core action, and then adds essential timing behavior. There is no redundant phrasing or filler, and every clause contributes actionable information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description still covers what happens before, during, and after the call: account changes, potential charges, the returned session, and the eventual visibility of ringing calls. Combined with the annotations, this provides a sufficiently complete mental model for correctly invoking the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is high at 75%, so the schema already documents most parameters. The description does not add additional meaning about caller, callee, caller_id, or device_id beyond what the schema provides. It stays at the baseline because it neither harms nor significantly enriches parameter understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action, 'start a Click2Dial call', on a specific resource (the SIPGATE account), and explicitly warns that it changes the account. This clearly distinguishes it from read-only siblings like call_history and account_info, and from other communication tools like send_sms.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes it clear the tool is for initiating a call, which implies its primary use case. However, it does not explicitly state when to use this tool over alternatives such as send_sms or set_forwarding, and it offers no exclusion criteria or conditional guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_devicesA
Read-onlyIdempotent

List phones and devices with owner, active routing, DND, and online/register status. Without user_id, all users are queried.

ParametersJSON Schema
NameRequiredDescriptionDefault
typesNoOptional sipgate device-type filters
user_idNoLimit results to one sipgate user ID, for example w0

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so the safety profile is covered. The description adds useful behavioral context beyond annotations: the default all-users behavior and the specific status fields returned. This exceeds a baseline score.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences with no wasted words. The primary action and resource are front-loaded, followed by the most important behavioral qualifier about scoping.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple, read-only list operation with two optional parameters and no output schema, the description is complete. It states what the tool returns, how the optional user_id affects scope, and annotations cover safety and idempotency.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented in the schema. The description adds meaningful semantics for user_id by explaining the default behavior when it is omitted, which goes beyond the schema's brief 'Limit results to one sipgate user ID'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('List') and resource ('phones and devices'), and enumerates the meaningful attributes returned (owner, active routing, DND, online/register status). This clearly differentiates it from sibling tools like list_users and list_numbers, which target different resources.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context on scope: without user_id, all users are queried, implying that user_id narrows the result to one user. It does not explicitly name sibling alternatives or state when not to use this tool, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_numbersA
Read-onlyIdempotent

List sipgate phone numbers and their current endpoint assignments.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitYesMaximum number of phone numbers
offsetYesZero-based pagination offset

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint false, so the safety profile is covered. The description adds context about returning current endpoint assignments, but does not disclose return format, ordering, or pagination behavior beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one concise sentence that front-loads the primary action and resource, then adds the distinguishing endpoint-assignment detail. Every word contributes meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list operation with comprehensive annotations, required parameters documented in the schema, and no output schema required, this description is sufficient. It tells the agent exactly what the tool lists and provides enough context to select and invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the limit and offset parameters are fully documented in the input schema. The description does not add parameter-level details, but it does not need to given the schema's completeness.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'List' with a clear resource, 'sipgate phone numbers', and adds the meaningful detail 'current endpoint assignments'. This clearly distinguishes it from sibling tools like list_users and list_devices.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes clear this tool is for phone numbers and their endpoint assignments, so an agent can infer when to choose it over siblings. However, it does not explicitly state when not to use it or name alternative tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_usersA
Read-onlyIdempotent

List all users in the sipgate account, including IDs used by other tools.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already communicate that this is a read-only, idempotent, non-destructive operation. The description adds the useful return-context detail that IDs are included for use by other tools, but it does not disclose pagination, ordering, or access requirements. This is adequate but not rich behavioral disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, compact sentence that front-loads the core action and resource, then adds the one extra fact agents need (IDs for reuse). No words are wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless list tool with strong annotations, the description is complete. It names the resource, the scope, and the key output element (IDs), which is sufficient for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the description has no parameter meanings to clarify. Baseline 4 is appropriate because no parameter documentation burden exists.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List'), a clear resource ('all users in the sipgate account'), and adds the useful detail that it returns IDs usable by other tools. This distinguishes it clearly from siblings like list_numbers and list_devices.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies a usage context: use this tool when you need user IDs for other tools. However, it does not explicitly state when to choose this over account_info or other list tools, nor does it mention any exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

send_smsA
Destructive

CHANGES THE SIPGATE ACCOUNT AND MAY INCUR CHARGES: send an SMS after verifying an SMS-capable extension. Reads and returns the relevant before/after history snapshot; history can update asynchronously.

ParametersJSON Schema
NameRequiredDescriptionDefault
sms_idNoSMS extension ID; the first available extension is used when omitted
messageYes
send_atNoOptional Unix timestamp in seconds
user_idYesOwner of the SMS extension
recipientYes

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already indicate destructive/read-only/idempotent hints, and the description adds material context beyond them: charges may be incurred, the account is changed, verification is required, and the returned history can update asynchronously. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences, front-loaded with the most decision-relevant warning about charges and state changes before the action. Every clause adds information and no schema details are repeated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter destructive tool with no output schema, it covers prerequisites, side effects, costs, and the async return behavior. It could specify message/recipient expectations or failure semantics explicitly, but the schema plus warning make it reasonably complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 60% schema coverage, the schema leaves message and recipient undocumented except for the recipient pattern. The description adds no per-parameter meaning beyond the generic 'send an SMS' and the SMS-capable extension hint, so it does not compensate for the gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'send an SMS' on the SIPGATE account, with an added constraint 'after verifying an SMS-capable extension'. The action is unambiguous and naturally distinguished from siblings like initiate_call and set_dnd.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context for when to invoke: send an SMS after verifying an SMS-capable extension. It also signals prerequisites and cost/state-change implications, but it does not name alternatives or explicit when-not-to-use scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_dndA
DestructiveIdempotent

CHANGES THE SIPGATE ACCOUNT: enable or disable Do Not Disturb for one device. Reads and returns the device's before/after state.

ParametersJSON Schema
NameRequiredDescriptionDefault
enabledYes
device_idYesDevice ID returned by list_devices

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate mutability and destructiveness, but the description adds valuable behavioral context: it explicitly says the tool 'Reads and returns the device's before/after state,' which informs the agent about side effects and return behavior beyond the raw annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences long, front-loads the core action, and includes the key behavioral detail about returning before/after state. Every sentence adds value with no redundant filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter tool with annotations covering safety and idempotency, the description is largely complete. It covers the operation scope and observable output. The only notable gap is lack of usage guidance relative to sibling tools, which is already penalized separately.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50%, but the description compensates by mapping 'enabled' to the enable/disable action, making the boolean parameter's meaning explicit. The schema also provides a helpful description for device_id ('Device ID returned by list_devices'), so both parameters are adequately semantically grounded.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a clear verb ('CHANGES') and specifies the exact resource and operation ('enable or disable Do Not Disturb for one device'). It distinguishes itself from sibling routing/forwarding tools by naming DND specifically, though 'THE SIPGATE ACCOUNT' is somewhat broad given the scope is a single device.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states what the tool does but provides no guidance on when to use it versus alternatives like set_forwarding or set_number_routing. It does not mention any prerequisites, exclusions, or conditions that would help an agent decide between sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_forwardingA
DestructiveIdempotent

CHANGES THE SIPGATE ACCOUNT: replace all forwardings for a phoneline, including timeout routing. Pass an empty forwardings array to delete all forwardings. Reads and returns before/after state.

ParametersJSON Schema
NameRequiredDescriptionDefault
user_idYesOwner user ID, for example w0
forwardingsYesComplete replacement list; [] removes every forwarding
phoneline_idYesPhoneline ID, for example p0

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag this as destructive and non-read-only, but the description adds valuable specifics: the operation replaces all forwardings, an empty array deletes all, and the tool reads and returns before/after state. This goes well beyond the structured hints and gives the agent a clear mental model of side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler, and the core action is front-loaded. The empty-array deletion case and the before/after return behavior are both essential and included without extra words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema, the description covers the destructive scope, the deletion edge case, timeout routing, and the return value nature. Combined with fully documented parameters and relevant annotations, an agent has enough context to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, with each parameter already described in the input schema, so the description is not required to repeat parameter details. It reinforces the semantics of forwardings ('replacement list', '[] removes every forwarding') but does not add meaningful new meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('replace') and a clear resource ('all forwardings for a phoneline'), and further clarifies scope with 'including timeout routing' and the empty-array deletion case. This makes it readily distinguishable from sibling tools like get_routing, set_dnd, and set_number_routing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool: whenever a complete replacement of forwardings is desired, and explicitly documents the deletion use case with an empty forwardings array. However, it does not name or contrast any sibling tool, so guidance about when not to use it or which alternative to choose is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_number_routingA
DestructiveIdempotent

CHANGES THE SIPGATE ACCOUNT: route a phone number to a sipgate endpoint ID (for example a phoneline). Reads and returns the number's before/after state.

ParametersJSON Schema
NameRequiredDescriptionDefault
number_idYesPhone-number ID returned by list_numbers
endpoint_idYesDestination endpoint ID accepted by sipgate, for example p0

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already signal readOnly=false and destructiveHint=true, and the description reinforces this with 'CHANGES THE SIPGATE ACCOUNT'. It adds useful behavioral detail beyond annotations by explaining that the tool reads and returns the number's before/after state, which is not present in the annotations or schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with no filler. The most important intent ('CHANGES THE SIPGATE ACCOUNT') is front-loaded, then the action and return behavior are stated compactly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With full schema coverage, annotations covering safety, and a description that explains the mutation and return value, the definition is mostly complete. It could optionally mention that number_id comes from list_numbers, but the schema already covers that, so nothing critical is missing for this simple two-parameter tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%: both number_id and endpoint_id are already documented with meaningful descriptions. The tool description adds no additional parameter semantics, so the baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action: route a phone number to a sipgate endpoint ID, and clearly identifies the affected resource. The explicit 'CHANGES THE SIPGATE ACCOUNT' framing distinguishes it from sibling get_routing, and the before/after state note clarifies what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes clear this is a mutation tool for setting routing, contrasting with the sibling get_routing. It provides clear context for when to use it, though it does not explicitly name alternatives or state when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A3.9/5.0
Disambiguation3/5

Several read tools overlap heavily—list_numbers and get_routing both expose number-to-endpoint routing, list_devices and get_settings both report DND/availability, and get_routing/set_forwarding both touch forwardings. The descriptions do add enough qualifiers to disambiguate primary purposes, but an agent may still struggle to choose among the state-reading tools.

Naming Consistency3/5

The set uses a consistent lowercase snake_case style and mostly verb_noun names, but account_info and call_history break the verb pattern and verbs are split among list/get/set/send/initiate. This is readable but not fully predictable.

Tool Count5/5

12 tools is squarely in the well-scoped range for a telephony/account-management MCP; each tool covers a meaningful operation or resource without bloat. No tool feels superfluous.

Completeness4/5

The surface covers the core sipgate workflow: account/user/device/number reads, routing/DND/forwarding writes, plus call history, SMS, and Click2Dial. Missing update operations for settings/users/numbers and outbound call control are minor gaps that agents can work around, so not a full 5.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables integration with JustCall APIs through function calling for managing telephony and communication services. Allows users to interact with JustCall's phone system capabilities through natural language using secure API authentication.
    25
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI agents to manage SimRelay SIMs: list, lock, release, read SMS history, and stream incoming messages in real-time via WebSocket.
    11
    11
    ISC

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/wiesson/sipgate-mcp'

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