voipms
A CLI and MCP server for managing a VoIP.ms account: DIDs, SMS and MMS, call routing, voicemail, fax, CDRs, sub accounts and reseller clients.
Every one of the 226 documented API methods is reachable from both surfaces. The method list, its parameters and which ones are required are generated from the official API documentation into an embedded catalogue, so the CLI commands and the MCP tools are never out of step with each other.
Install
go install github.com/maxdubrinsky/voipms@latest
Setup
API access is off by default on a VoIP.ms account. In the portal, go to Main Menu > SOAP and REST/JSON API and do all three of:
- Set an API password. This is separate from your portal login password.
- Enable the API.
- Add this machine's IP address to the allowlist. Calls from any other address are rejected.
Then store the credentials and confirm they work:
voipms auth init
voipms auth check
auth check reports the IP that VoIP.ms sees you from, which is the address to put on the allowlist.
Credentials live in ~/.config/voipms/config.toml (mode 0600). VOIPMS_USERNAME and VOIPMS_PASSWORD override the file, which is what MCP client configs and CI should use.
CLI
Methods are grouped by feature, and each takes its API parameters as flags:
voipms general get-balance
voipms dids get-dids-info --did 5551234567
voipms messaging send-sms --did 5551234567 --dst 5551234568 --message "on my way"
voipms cdr get-cdr --date_from 2026-08-01 --date_to 2026-08-22 --timezone -5
Parameter names come straight from the API docs, and both --date_from and --date-from work.
Finding your way around:
voipms methods # every method
voipms methods --group voicemail # one group
voipms methods --search forward # search names and descriptions
voipms describe getCDR # parameters, which are required, what it costs
voipms call reaches any method by its API name, including one VoIP.ms has added since the catalogue was last generated:
voipms call getServersInfo
voipms call getCDR -p date_from=2026-08-01 -p date_to=2026-08-22 -p timezone=-5
Output is JSON by default. --output table renders list results as a table, and --fields narrows wide responses, which matters for things like getDIDsInfo that return 35 columns per row:
voipms dids get-dids-info --output table --fields did,description,routing,sms_enabled
--dry-run prints the method and parameters that would be sent without calling the API.
MCP
voipms mcp
The server exposes three tools rather than 226, so the full API stays reachable without every method costing space in the model's context:
| Tool |
Purpose |
voipms_list_methods |
Group index, or the methods in a group, or a search |
voipms_describe_method |
A method's parameters, which are required, and what it costs |
voipms_call |
Invoke a method |
Client configuration:
{
"mcpServers": {
"voipms": {
"command": "voipms",
"args": ["mcp"],
"env": {
"VOIPMS_USERNAME": "you@example.com",
"VOIPMS_PASSWORD": "your-api-password"
}
}
}
}
What the server will and will not do
It is read-only unless told otherwise. A model can read the whole account by default but cannot change or spend anything by accident.
| Flag |
Reads |
Config changes |
Costs money |
| (none) |
yes |
refused |
refused |
--allow-writes |
yes |
yes |
refused |
--allow-writes --allow-billable |
yes |
yes |
yes |
Every method is classified in the catalogue as read, write or destructive, and separately flagged if it spends money: ordering DIDs, sending SMS, MMS or faxes, provisioning E911, and posting charges or payments to a reseller client. Refusals name the CLI command to run instead, so the model can hand the action back to you.
A method that is not in the catalogue is assumed to both write and spend, so reaching one VoIP.ms has added since the catalogue was last generated needs --allow-billable. Nothing is known about a new method, and the ones most likely to be added are the ones that order and send. Regenerating the catalogue restores its real classification.
Refused calls never reach VoIP.ms, and parameters are validated against the documented signature before any call goes out. Credentials are stripped from errors before they leave the server: VoIP.ms authenticates with query parameters, and Go quotes the request URL in connection errors, so an unredacted timeout would put the API password in the model's context.
Regenerating the catalogue
The catalogue is generated from the API documentation page. That page sits behind a Cloudflare challenge and requires a logged-in portal session, so it cannot be fetched automatically: open https://voip.ms/m/apidocs.php in a browser, save it, and run:
go run ./cmd/gen-catalog -in apidocs.html -out internal/catalog/methods.json
go test ./...
The generator fails rather than silently dropping methods whose names it does not recognise, and the tests check that no two methods in a group collide on a command name.
Notes on the API
Some behaviour is worth knowing about, because it shapes the client:
- Everything is a GET. The endpoint routes any POST to its SOAP handler and answers with a SOAP fault, so parameters go in the query string even when the docs suggest otherwise. Very large values, such as base64 media for
sendMMS, can run into URL length limits.
- Failures come back as HTTP 200. The body carries
"status": "invalid_credentials" or similar, so the HTTP status alone tells you nothing. This client keys off status and turns anything other than success into an error.
ip_not_enabled is the usual first failure, and it means the allowlist, not the credentials. getIP is the one method that does not authenticate by IP, which is why auth check can tell you the address to add.
Development
go test ./...
go build .
Licence
MIT, in LICENSE.
One carve-out, in NOTICE: the embedded catalogue reproduces the method and parameter descriptions VoIP.ms publishes in its API documentation, which are theirs rather than this project's to license. They are included so the client can validate a call against its documented signature and explain it. This is an independent client and is not affiliated with or endorsed by VoIP.ms.