oitvoip-mcp
oitvoip-mcp
MCP server for Oitvoip (hosted VoIP/UCaaS reseller platform, built on
NetSapiens — API host pattern is {tenant-pbx-host}/ns-api/). Exposes
the NetSapiens ns-api's domain, reseller, device, subscriber, and CDR
methods as MCP tools.
Naming note: MSPbots' own integration is registered as "Oitvoip" (
subjectCode=NS— short for NetSapiens); the underlying API and all official documentation reference "NetSapiens" / "ns-api". This MCP covers exactly the 5 methods MSPbots itself has configured.
Overview
Stateless HTTP service. No credentials are ever persisted — each request supplies its own credentials via headers, used only for the lifetime of that single request.
Supports concurrent requests; per-request credential isolation is done via Python
contextvars, not a global/shared client instance.Entry points:
POST /mcp(MCP protocol) andGET /health(health check).Default port:
8080(configurable viaMCP_HTTP_PORT).
Authentication
NetSapiens uses a standard OAuth2 password grant:
POST https://{site}/ns-api/oauth2/token/
grant_type=password&client_id=...&client_secret=...&username=...&password=...
-> {"access_token": "...", "expires_in": 3600, "token_type": "Bearer", ...}The resulting access_token is valid for 1 hour, but this server
re-authenticates fresh on every single tool call rather than caching it
across MCP requests — nothing is cached or persisted. Every real ns-api
call then sends Authorization: Bearer <access_token>.
HEADER 授权参数说明
Header | 类型 | 是否必填 | 默认值 | 枚举值 | 字段描述 | Example |
| string | 是 | 无 | 无 | 租户 PBX 主机名(不含协议前缀) |
|
| string | 是 | 无 | 无 | NetSapiens OAuth2 API Client ID |
|
| string | 是 | 无 | 无 | NetSapiens OAuth2 API Client Secret |
|
| string | 是 | 无 | 无 | Subscriber 登录名(含域名后缀) |
|
| string | 是 | 无 | 无 | 对应密码 |
|
Missing any header returns 401:
{
"error": "Missing credentials",
"message": "This server requires the X-Oitvoip-Site, X-Oitvoip-Client-Id, X-Oitvoip-Client-Secret, X-Oitvoip-Username, X-Oitvoip-Password headers",
"required_headers": ["X-Oitvoip-Site", "X-Oitvoip-Client-Id", "X-Oitvoip-Client-Secret", "X-Oitvoip-Username", "X-Oitvoip-Password"],
"optional_headers": []
}An invalid credential or an authenticated-but-under-scoped subscriber
account surfaces as a tool-level unauthorized error envelope (message
includes the vendor's own detail, e.g. Invalid Scope [APP001]), not an
HTTP-level error from this server — see Known Gaps.
Environment Variables
Variable | 类型 | 是否必填 | 默认值 | 说明 |
| int | 否 |
| HTTP 监听端口 |
| string | 否 |
| HTTP 监听地址 |
MCP Endpoint
POST /mcp— MCP protocol (streamable HTTP transport)GET /health— health check, returns{"status": "ok"}(pure local probe, does not call the vendor API)
Tool List
Tool | 功能 | 参数 |
| 列出该 reseller 账号下所有已开通的域名(租户) | 无 |
| 获取指定域名的 reseller 级别详情 |
|
| 列出指定域名下已注册的 SIP 设备/终端 |
|
| 列出指定域名下的用户/分机 |
|
| 获取指定域名、指定日期范围内的通话详单(CDR) |
|
Responses are the vendor's JSON (array or object depending on the method),
serialized compactly (no indentation, ensure_ascii=False). If a response
would exceed ~20,000 characters, the largest list field is truncated and
the result includes truncated: true plus the original count, rather than
returning an unbounded blob. All 5 tools are read-only (readOnlyHint) —
there are no write/delete tools in this service.
On error, tools return a structured JSON error envelope instead of raising:
{"error": {"code": "unauthorized", "message": "...", "retryable": false}}code is one of not_configured / unauthorized / not_found /
invalid_argument / rate_limited / upstream_error; retryable
indicates whether the Agent may safely retry (true for rate_limited and
upstream_error).
测试示例
# Health check
curl -s http://localhost:8080/health
# Call a tool via the MCP protocol (streamable HTTP) — requires an
# initialize handshake first per the MCP spec; abbreviated example below
# shows the tool-call request body only:
curl -s -X POST http://localhost:8080/mcp \
-H "X-Oitvoip-Site: pbx.example.com" \
-H "X-Oitvoip-Client-Id: 58900.mspbot" \
-H "X-Oitvoip-Client-Secret: <your-client-secret>" \
-H "X-Oitvoip-Username: 1000@example" \
-H "X-Oitvoip-Password: <your-password>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: <session-id-from-initialize>" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "oitvoip_get_subscribers",
"arguments": {"domain": "example.58900.service"}
}
}'Live-verified (2026-07-30) against a real tenant, all 5 tools called
end-to-end through this running server: oitvoip_get_subscribers returned
real subscriber/extension records; oitvoip_get_devices returned real
registered SIP devices (Polycom endpoints, live registration state);
oitvoip_get_cdr2 returned real call detail records for the given date
range. oitvoip_get_domains and oitvoip_get_resellers correctly reached
the API and surfaced a clean, expected 401 Invalid Scope [APP001]
tool-level error — the provided test credentials are a subscriber-level
account (scope: "Office Manager"), which does not carry domain/reseller
admin privileges on this particular NetSapiens deployment; see Known Gaps.
API Reference
Public, no login required: https://api.ucaasnetwork.com/ns-api/apidoc/ (full ns-api reference, including OAuth2, Domain, Reseller, Device, Subscriber, and CDR objects)
Known Gaps
Scope is exactly MSPbots' 5 configured endpoints, not the vendor's full API surface — ns-api also covers Callqueue, Agent, Phonenumber, Dialplan, Contacts, Presence, Call Queue Report/Stat, real-time Call control, and more (per the public docs' own object list); those are out of scope here.
oitvoip_get_domainsandoitvoip_get_resellerscould not be fully live-verified with real data — the provided test account authenticates successfully (proving the OAuth2 flow and this implementation are correct) but is scoped as a subscriber-level "Office Manager" role, which NetSapiens rejects for these two admin-level objects with401 Invalid Scope [APP001]. This is a credential-privilege limitation of the specific test account, not a bug in this server —oitvoip_get_ subscribers,oitvoip_get_devices, andoitvoip_get_cdr2all succeeded with real data using the exact same access token from the exact same login.CDR date range fields (
start_date/end_date) are unvalidated strings — passed through to the vendor as-is inYYYY-MM-DD HH:MM:SSformat, matching MSPbots' own stored usage; no client-side date parsing is performed.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/MSPbotsAI/oitvoip-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server