MCP Server & Claude Code Integration
SIP VAULT ships an MCP (Model Context Protocol) server that exposes call evidence and OpenSIPS configs to any AI agent. Pair it with the /troubleshoot-call skill in Claude Code and you get a senior-VoIP-engineer-in-a-box that diagnoses calls by reading the actual SIP dialog, RTCP stats, log tail, and config files — not vibes.
The loop: paste a Call-ID → Claude reads the call context + config bundle through MCP → prose diagnosis with the exact file + line number → structured diagnose(file, line, root_cause, fix) output.
What ships
| Component | What it does | Where it lives |
|---|---|---|
sipvault-mcp |
Python MCP server. Three tools: get_call_context, read_file, read_config_bundle. Speaks MCP over stdio. |
mcp/ in the repo |
sipvault-skill |
Claude Code skill: /troubleshoot-call <call-id>. Orchestrates the MCP tools and produces a structured diagnosis. |
skill/ in the repo |
Tools exposed over MCP
get_call_context(call_id, customer_id?)
Fetches everything SIP VAULT knows about a call:
- SIP messages — decoded, in order (INVITE, 100, 180, 200, ACK, BYE, etc.)
- Quality report — MOS, jitter, loss, RTT with per-direction breakdown, 5-second timeseries
sip_flow— endpoint topology and message arrows- Log excerpt — the tail of
opensips.logfiltered to the Call-ID - Config paths — the relevant files to read next (usually
/etc/opensips/opensips.cfg)
Response is capped at ~200 KB to stay inside the model's context window.
read_config_bundle(main_path)
Reads an OpenSIPS cfg file AND follows every #!include directive, returning all reachable files in one round-trip. Detects cycles. Caps at 50 files / 1 MB total. Prefer this over multiple read_file calls when you're walking a cfg tree.
read_file(path)
Raw text read for a single file. Allowlisted to /etc/opensips/, /etc/rtpproxy/, /var/log/opensips/ by default. Path-traversal hardened.
Install the MCP server
Run this on the same host as your SIP VAULT FastAPI (or anywhere that can reach it over HTTPS):
Verify:
Configure it
Environment variables:
| Variable | Required | Default | What it does |
|---|---|---|---|
SIPVAULT_MCP_API_URL |
yes | http://127.0.0.1:8000 |
Base URL of the SIP VAULT FastAPI |
SIPVAULT_MCP_SERVICE_TOKEN |
yes | — | JWT that authenticates MCP → FastAPI. Mint on the API side. |
SIPVAULT_MCP_CUSTOMER_ID |
yes | — | Default customer tenant for call lookups |
SIPVAULT_MCP_ALLOWED_PATHS |
no | /etc/opensips:/etc/rtpproxy:/var/log/opensips |
Colon-separated allowlist for read_file |
Mint the service token
On the FastAPI host, generate a service token and set it in the API's environment. The matching token goes into the MCP server's env.
# On the FastAPI host:
python -c "import secrets; print(secrets.token_urlsafe(48))"
# Copy the output.
# Set it on the API side (example for systemd):
sudo systemctl edit sipvault-api
# Add:
# [Service]
# Environment=SIPVAULT_MCP_SERVICE_TOKEN=<paste here>
sudo systemctl restart sipvault-api
Kill switch: unset SIPVAULT_MCP_SERVICE_TOKEN on the API side and restart. The MCP auth path is dead regardless of what token the client presents.
Wire into Claude Code
Claude Code reads MCP server configs from ~/.config/claude-code/mcp.json (or the platform equivalent). Add:
{
"mcpServers": {
"sipvault-mcp": {
"command": "sipvault-mcp",
"args": [],
"env": {
"SIPVAULT_MCP_API_URL": "https://your-sipvault-api.example.com",
"SIPVAULT_MCP_SERVICE_TOKEN": "<paste-the-token>",
"SIPVAULT_MCP_CUSTOMER_ID": "your-customer-id",
"SIPVAULT_MCP_ALLOWED_PATHS": "/etc/opensips:/etc/rtpproxy:/var/log/opensips"
}
}
}
}
Restart Claude Code. Verify the server is registered:
Install the /troubleshoot-call skill
Then in any Claude Code session:
The skill:
- Calls
get_call_contextfor the Call-ID. - Reads the config bundle at
/etc/opensips/opensips.cfg(following#!includes). - Reasons end-to-end: SIP dialog traces, RTCP direction asymmetry, log errors, config mismatches.
- Emits prose (Observed / Root cause / Fix) in under 200 words.
- Ends with a structured
diagnose(file, line, root_cause, fix)call that your tooling can consume.
Example session
> /troubleshoot-call F7FCEF17-AA99-433F-99A6-6CF81901D70F
[Claude reads get_call_context, sees 200 OK received but no RTP in UAC→UAS direction]
[Claude reads read_config_bundle(/etc/opensips/opensips.cfg)]
[Claude walks nat.cfg, finds route[NAT_REPLY] missing rtpproxy_answer()]
**Observed.** Dialog reached 200 OK. RTCP shows one-way audio: caller received
media but callee received zero packets. Log tail shows rtpproxy was engaged on
the INVITE but not on the reply.
**Root cause.** `nat.cfg:47` — `route[NAT_REPLY]` calls `fix_contact()` but
omits `rtpproxy_answer()`, so the SDP in the 200 OK keeps the caller's private
IP in the `c=` line.
**Fix.** Add `rtpproxy_answer();` inside `route[NAT_REPLY]` right after
`fix_contact()`, reload OpenSIPS.
diagnose(file="nat.cfg", line=47, root_cause="route[NAT_REPLY] missing rtpproxy_answer(), SDP in 200 OK leaks private IP", fix="add rtpproxy_answer() after fix_contact() in route[NAT_REPLY]")
Troubleshooting
sipvault-mcp: command not found
pip install -e . didn't put the console script on PATH. Try pip install --user -e . and add ~/.local/bin to PATH, or install inside a venv Claude Code can see.
401 invalid service token
The SIPVAULT_MCP_SERVICE_TOKEN on the MCP side doesn't match what the FastAPI is configured to accept. Regenerate, set on both sides, restart both processes.
call not found
The Call-ID didn't match any recording in the last 7 days under the configured customer_id. Verify the agent is running on the OpenSIPS box that handled the call and that customer_id matches the S3 bucket tenant.
MCP tools don't show up in Claude Code
claude mcp list should include sipvault-mcp. If not: Claude Code didn't parse your mcp.json. Validate JSON syntax (jq . ~/.config/claude-code/mcp.json), restart Claude Code, check the Claude Code logs for MCP startup errors.
Skill runs but never calls diagnose
The skill prompt requires diagnose as the final action. If Claude skips it, your MCP server is likely returning an error ({"error": "..."}) that's being handled as text. Check the MCP server's stderr for the specific error class.
Security model
- MCP-to-FastAPI auth is a shared JWT service token. Rotate by changing both env vars and restarting. No user identity is carried through — MCP calls run with the customer_id in its env, not per-user.
read_fileis allowlisted — path-traversal attempts return an error. You can narrow the allowlist per deployment.- No code execution — the MCP server is read-only. It never shells out, never writes to disk, never restarts OpenSIPS.
- Audit trail — the FastAPI logs every MCP request with the Call-ID. Route those logs to your SIEM like any other API.
See the Security Guide for the full threat model.