Skip to main content
Glama
MSPbotsAI

bvoip-mcp

by MSPbotsAI
README.md
# bvoip-mcp

MCP server for **Bvoip / 1Stream** — exposes the 1Stream `ClientAccess.svc` REST
API's call-reporting, phone-status and CRM-extension-mapping endpoints as MCP
tools.

> Naming note: MSPbots' own integration is registered as "Bvoip"
> (`subjectCode=BVOIP`); the underlying vendor platform/API is "1Stream"
> (`portal.1stream.com`). This MCP covers exactly the 6 GET endpoints
> MSPbots itself has configured for this integration — see **Known Gaps**
> below for why the scope stops there.

## Overview

- Stateless HTTP service. No credentials are ever persisted — each request
  supplies its own API key via a header, and it is 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) and `GET /health` (health check).
- Default port: `8080` (configurable via `MCP_HTTP_PORT`).

## Authentication

1Stream authenticates with a single static **API key**, created in the
1Stream portal (see "Creating API Keys in 1Stream" at
[docs.1stream.com](https://docs.1stream.com/apis/1stream-api)). 1Stream's own
integration convention sends this key as the raw value of the
`Authorization` header — **no `Bearer ` prefix** — and this server forwards
it exactly that way.

### HEADER 授权参数说明

| Header | 类型 | 是否必填 | 默认值 | 枚举值 | 字段描述 | Example |
|---|---|---|---|---|---|---|
| `X-Bvoip-Api-Key` | string | 是 | 无 | 无 | 1Stream 静态 API Key,原样转发为上游 `Authorization` 请求头(不加 `Bearer ` 前缀) | `a1b2c3d4e5f6...` |

Missing the header returns `401`:
```json
{
  "error": "Missing credentials",
  "message": "This server requires the X-Bvoip-Api-Key header",
  "required_headers": ["X-Bvoip-Api-Key"],
  "optional_headers": []
}
```

## Environment Variables

| Variable | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `MCP_HTTP_PORT` | int | 否 | `8080` | HTTP 监听端口 |
| `MCP_HTTP_HOST` | string | 否 | `0.0.0.0` | HTTP 监听地址 |
| `BVOIP_BASE_URL` | string | 否 | `https://portal.1stream.com/api/ClientAccess.svc` | 1Stream ClientAccess 基础 URL |

## MCP Endpoint

- `POST /mcp` — MCP protocol (streamable HTTP transport)
- `GET /health` — health check, returns `{"status": "ok", "service": "bvoip-mcp", "transport": "http"}`

## Tool List

All 6 tools are plain `GET` calls against `ClientAccess.svc` with **no
required parameters** — this matches exactly how MSPbots itself calls this
integration today. Each tool accepts an optional `extra_params` pass-through
dict for any additional query-string filters (e.g. a date range), since
1Stream's full filter reference is only published in their partner-gated
Postman collection (see **Known Gaps**).

| Tool | 功能 | 参数 |
|---|---|---|
| `bvoip_get_call_logs` | 列出通话详单(起止时间、方向、分机、队列/振铃组、通话时长、录音链接、关联 CRM 工单等) | `extra_params: dict[str,str] \| None` |
| `bvoip_get_phone_statuses` | 列出当前分机/队列状态(注册状态、登录/可用状态、队列坐席分配/可用/通话数、自定义状态等) | `extra_params: dict[str,str] \| None` |
| `bvoip_get_calls_by_hour` | 按小时统计通话量(呼入/呼出/总数/未接听) | `extra_params: dict[str,str] \| None` |
| `bvoip_get_calls_leaderboard` | 统计周期内的通话总量(呼入/呼出/总数/未接听) | `extra_params: dict[str,str] \| None` |
| `bvoip_get_calls_by_extension` | 按分机统计通话数据(呼入/呼出/总数、平均及总通话时长) | `extra_params: dict[str,str] \| None` |
| `bvoip_get_client_crm_user_extension_mappings` | 列出 1Stream 用户/分机与关联 CRM(如 ConnectWise)成员账号的映射(分机、CRM 成员 ID/用户名、角色、套餐等) | `extra_params: dict[str,str] \| None` |

## 测试示例

```bash
# 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-Bvoip-Api-Key: <your-1stream-api-key>" \
  -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": "bvoip_get_phone_statuses",
      "arguments": {}
    }
  }'
```

Expected: `200` with the phone-status list on a valid key; `401`/`403`
(surfaced by the tool as `Error: Bvoip API error 401/403: ...`) on an
invalid or revoked key.

## API Reference

- Overview: https://docs.1stream.com/apis/1stream-api
- Full REST/Postman API reference: **partner-gated** — 1Stream states "please
  reach out to our team at partners@bvoip.com to request the documentation,
  or if you're an active partner you can find it at Partners > Resources >
  Automation and APIs." No public Swagger/OpenAPI spec exists.
- A public `API Fields.xlsx` (linked from the overview page above) documents
  the response fields for the endpoints below, with no auth/parameter detail.

## Known Gaps

- **Scope is exactly MSPbots' 6 configured endpoints, not the vendor's full
  API surface** — unlike every other vendor tackled in this MCP program,
  1Stream's REST API documentation is fully partner-gated. There is no
  public reference beyond this overview page and the fields spreadsheet, so
  there was no larger public spec to weigh a broader scope against.
- The fields spreadsheet documents one additional endpoint,
  `GetCallSegmentLogs` (call-leg-level detail), that MSPbots does **not**
  currently call — intentionally left out of this server for the same
  reason; can be added on request if a use case emerges.
- Response field names/types below are sourced from the public `API
  Fields.xlsx`, not a formal schema — treat them as documentation, not a
  contract. Request-side filter parameters (e.g. date range) are not
  publicly documented at all; `extra_params` is provided so a caller who
  has partner-level API access can still pass them through.