Skip to main content
Glama
README.md
# cx-agent-mcp

A small MCP server for a telecom support assistant. The assistant can look up customers, check balance and orders, suspend a lost SIM and open tickets, all through a REST backend. It also has a tool that reads a SIP trace and tells you why a call failed.

I spent a few years in VoIP support before moving to backend work, and most "the bot is broken" tickets I saw were really telephony or integration problems. So this project focuses on those two parts: calling backend APIs safely, and reading SIP traces.

## What's inside

```
backend/api.py              mock telecom backend (FastAPI)
mcp_server/api_client.py    HTTP client: auth, timeouts, retries, idempotency keys
mcp_server/server.py        MCP tools, one resource, one prompt
mcp_server/sip_analyzer.py  SIP trace parser and rules
agent/chat.py               terminal chat client (Claude + the MCP server over stdio)
samples/trace_488.txt       example failed call
tests/                      pytest
```

## Tools

| Tool | Kind | Notes |
|---|---|---|
| `lookup_customer` | read | accepts `010...`, `0020...` or `+20...` |
| `get_line_status` | read | balance, data left, line status |
| `get_order_status` | read | validates the order id before calling the API |
| `suspend_line` | write | refuses unless `customer_confirmed` is true; idempotent |
| `create_ticket` | write | handover note for the human agent; idempotent |
| `analyze_sip_trace` | local | ladder, codecs, media IPs, likely cause |

Resource: `policy://escalation`. Prompt: `support_agent`.

## How API calls are handled

- API key header on every request
- 3s timeout (configurable). A support bot can't keep a customer waiting
- Retries with backoff only on 429/502/503/504 and network errors
- 4xx errors are never retried
- Writes are retried only when they carry an `Idempotency-Key`, so a retry can't suspend a line twice or open two tickets
- Tools never raise. On failure they return `ok: false`, a sentence the bot can say, and a next step (`offer_human_agent` or `ask_customer_to_check_input`)

You can see this working by starting the backend with `BACKEND_FAIL_RATE=0.3`. About a third of the calls return 503 and the tools still answer.

## SIP analyzer

Paste a text trace from an SBC, sngrep or Wireshark. It builds the ladder and checks for:

- 4xx/5xx final responses with what to look at (488 codec/SRTP mismatch, 403, 404 number format, 503...)
- 200 OK with no ACK (the call that drops after ~30 seconds)
- private IPs in the SDP `c=` line (one way audio behind NAT)
- only compressed codecs offered (bad for speech recognition)
- no `telephone-event` (DTMF won't reach the bot)
- more than one Call-ID (B2BUA legs)

## Running it

```bash
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -r requirements.txt

# terminal 1
uvicorn backend.api:app --port 8000     # swagger at http://127.0.0.1:8000/docs

# terminal 2, pick one
npx @modelcontextprotocol/inspector python -m mcp_server.server
python -m agent.chat                     # needs ANTHROPIC_API_KEY
```

Settings are read from environment variables, see `.env.example`.

### Claude Desktop

```json
{
  "mcpServers": {
    "cx-agent": {
      "command": "C:\\path\\to\\cx-agent-mcp\\.venv\\Scripts\\python.exe",
      "args": ["-m", "mcp_server.server"],
      "env": {
        "PYTHONPATH": "C:\\path\\to\\cx-agent-mcp",
        "BACKEND_URL": "http://127.0.0.1:8000",
        "BACKEND_API_KEY": "dev-secret-key"
      }
    }
  }
}
```

Things to try:

- "my number is 01001234567, how much balance do I have?"
- "where is ORD-5001?"
- "I lost my phone, stop my line"
- paste `samples/trace_488.txt` and ask why the call failed

## Tests

```bash
pytest -q
```

The tool tests route httpx straight into the FastAPI app, so no server has to be running.

## Next

- streamable HTTP transport
- OAuth2 client credentials instead of a static key
- FAQ search tool
- Arabic replies
- Genesys Cloud data action pointing at the backend