Skip to main content

Read-only MCP server for Cisco Emergency Responder (CER) — unified facade over the v15su2 Configuration API and the legacy Read-Only API for E911 location and alert auditing.

Project description

mccer

PyPI Python License

Read-only MCP server for Cisco Emergency Responder (CER) — a unified facade over both of CER's administrative APIs (the v15su2 Configuration API and the older Read-Only API) for E911 location, alert, and license auditing.

Tested against CER 15.0.1. Compatible with CER 8.x+ (legacy API) and 14+ (Configuration API). Some /v2/* Configuration endpoints require 15SU2; mccer transparently falls back to legacy equivalents on older builds.

What it looks like

Invoke the e911_coverage_audit prompt in any MCP-aware LLM client. Sample findings the tool surfaces from a real cluster:

🔴 Smart License sync stalled. LastSynchronizationTime is Mar 5 2025; today is over a year later. LicenseStatus: Waiting. The cluster still operates on its cached authorization, but new phones beyond the licensed count may not get tracked at the next reboot. Investigate the Smart License agent's outbound HTTPS path.

🟡 CER↔CUCM CTI signaling configured plaintext. EnableSecureConn: false. Call-setup signaling between the two systems travels unencrypted on the management network. For HIPAA-relevant deployments, plan CAPF certificate enrollment + secure CTI migration.

🟡 Onsite-alert recipient email contains a typo. One named entry's OnsiteAlertEmail is missing a single letter from the surname relative to the entry's OnsiteAlertName field. 911 calls from that ERL produce no email notification to the intended recipient.

🟢 Two onsite-alert entries (Default, Operator) carry no contact. If any ERL points at these entries, 911 calls from that ERL trigger no internal notification at all. Confirm intentional vs incomplete config.

Each finding ties to specific tool calls (cer_e911_license, cer_cucm_clusters, cer_onsite_alerts) with severity + recommended action, not raw API output the operator has to interpret.

Scope and complement

mccer is intentionally narrow — read-only audit of CER configuration via both of its admin APIs. It does NOT cover:

  • CUCM-side configuration (dial plan, phones, registration) — use mcaxl
  • CUCM live operations (log tail, CDR, RIS, packet capture) — use mcsiphon
  • Write operations on CER (intentionally not exposed; see below)

The three projects compose well in the same MCP-aware LLM session for end-to-end UC audit narratives spanning ERL → phone → CUCM device → CDR.

Why this exists

CER's admin UI is great for one-config-at-a-time work but painful for the cross-cluster audit questions an E911 review actually needs to answer:

  • "Which phones are registered to CUCM but have no ERL match in CER?"
  • "Are CER's onsite-alert email addresses still pointing at active staff?"
  • "Did the Smart License agent ever stop syncing? When?"
  • "Is the CER↔CUCM CTI channel encrypted?"
  • "Which switches does CER even know about, via which SNMP version?"
  • "For every 911 call placed last quarter, which ELIN was sent to the PSAP?"
  • "Is the audit account I created actually scoped to read-only on the API surface I think it is?"

mccer queries those answers programmatically and ships curated prompts that orchestrate the tools into ready-to-act audit findings.

Read-only by structural guarantee

The Configuration API supports full CRUD; mccer exposes only its GETs. Both of mccer's HTTP clients implement only .get() — no .post(), .put(), .delete(). Tools are wrappers around those reads. Defense-in-depth: even if a future regression added a write helper, FastMCP would still need an explicit @mcp.tool decorator to expose it.

This means the CER API service account mccer uses can be scoped to a read-only audit role on CER. mccer is structurally incapable of mutating CER state regardless of what permissions the account is granted.

Install

# Run directly from PyPI:
uvx mccer

# Or as a pinned dev install:
pip install mccer

# Or via Claude Code's MCP registry:
claude mcp add cer -- uvx mccer

Configure

# .env (in project root or anywhere on dotenv's search path)
CER_HOST=cer-pub.example.com         # bare hostname → https; or full URL
CER_USERNAME=apiuser                  # CER local or remote-on-CUCM user
CER_PASSWORD=...

# Optional:
MCCER_VERIFY_TLS=false                # self-signed certs / SSH-tunneled access
MCCER_CACHE_TTL=300                   # response cache TTL in seconds (future)

CER user setup

Cisco's auth docs require the CER System Admin role for Configuration API access. The narrower CER Audit Admin role is not sufficient on the Configuration API — empirically (CER 15.0.1) those endpoints return {"status":"Account is locked..."} with audit-admin alone. The legacy Read-Only API has more permissive role gating but still uses Basic auth.

Cisco recommends a dedicated CER API account separate from the main admin so password rotations don't disrupt unrelated operations.

Reaching CER through an SSH tunnel

If your CER publisher isn't directly reachable from where mccer runs, the common pattern is an SSH local-port forward through a bastion:

ssh -fN -L 18443:cer-pub.example.com:443 your-bastion
# in .env:
CER_HOST=https://localhost:18443
MCCER_VERIFY_TLS=false   # cert won't match localhost

Tool surface (19 total)

Each tool returns Cisco's actual response shape — parsed from XML to dict on the legacy API, native JSON on the Configuration API. Empty-result responses come back in a distinct shape (e.g. {"message":"No Manual Config Phone Record Available","TrackingID":"..."}) and tools propagate as-is rather than normalizing.

Phone-bucket inventory (the four-bucket E911 partition)

Every CUCM-registered phone falls into exactly one of these buckets:

  • cer_phones_unlocated — registered but no ERL → 🔴 immediate 911 risk
  • cer_phones_tracked — successful auto-location (switchport / IP-subnet / AP)
  • cer_phones_nontracked — CER sees them but can't auto-locate
  • cer_phones_manualconfig — operator-set ERL override

Alert recipients (who gets notified on 911)

  • cer_onsite_alerts — email recipients per ERL/zone
  • cer_pager_alerts — pager addresses per ERL/zone

Network discovery (the auto-location chain)

  • cer_switchports — switchports CER probed via SNMP
  • cer_lan_switches — LAN switches in CER's inventory
  • cer_snmp_v2 / cer_snmp_v3 — SNMP credentials per target
  • cer_discovery_status — phone-tracking scan-cycle health

Configuration

  • cer_e911_license — Smart License tier + utilization
  • cer_cucm_clusters — CUCM clusters CER receives data from (fills a hole the Configuration API leaves: /cluster only supports POST/PUT/DELETE, no GET)
  • cer_call_history — retrospective 911 call log (caller / ERL / ELIN / time)

Admin user inventory

  • cer_list_users / cer_list_user_roles / cer_list_user_groups

Connectivity

  • cer_ping — verify both API surfaces are reachable + auth works
  • mccer_health — local introspection (no network call)

Resources (3)

URI-addressable read-only data the LLM ingests as ambient context (vs tools, which the LLM decides when to invoke):

  • cer://api-inventory — full 34-endpoint reference (static)
  • cer://overview — live cluster snapshot (license + clusters + alert recipients), composing several tool calls
  • cer://erls — live ERL definitions (the location reference data every audit-flavored reasoning step needs)

Prompts (4)

Multi-turn workflow templates that orchestrate tool calls into audit-ready findings:

  • whoami — orientation: what mccer is, what's available
  • e911_coverage_audit(focus="full") — full E911 readiness audit walkthrough, ranked findings (🔴/🟡/🟢) with evidence + recommended actions
  • alert_recipient_review — focused stale-recipient hunt for 911 contacts
  • admin_account_audit — CER admin/API user staleness + role bloat review

CER version compatibility

CER version What works
8.x+ Legacy Read-Only API (most tools)
14+ Configuration API GETs (users/roles/groups, ERLs, IPSubnet)
15SU1 / 15.0.1 base Above + most /v2/* endpoints; /v2/unlocatedphones and /v2/callhistorydetails 415 → mccer falls back to legacy /unlocatedphones/info and /callhistory/info automatically
15SU2+ Full Configuration API surface including all /v2/*

Falling back is silent — operators don't see a difference except slightly different response shapes between Config-API JSON and legacy-API XML→dict.

Caveats

  • Both APIs run on the CER Publisher only. There is no Subscriber-side read failover.
  • HTTPS required despite some legacy docs showing http:// — mccer hard-rejects plaintext at client construction.
  • No 429 Too Many Requests status from CER. Failure modes under load are 500 / 503 / TCP timeout. Retry logic should backoff on those.
  • Caching is recommended but not yet shipped. Cisco's "no enforced rate throttling" warning + Publisher-only deployment means client-side caching matters operationally. A future release will add the SQLite-backed cache pattern used by the sibling mcaxl.
  • Cisco lockout policy is real. Repeated bad-auth attempts will lock the CER user account; clear via the CER admin web UI (password reset / unlock user). If your API password contains shell- or .env-special characters (#, !, &, $, etc.), double-check the value reaching CER actually matches what's stored in .env — mismatch produces failed-auth attempts that trigger lockout, presenting as Account is locked in API responses.

Sibling projects

  • mcaxl — CUCM AXL/RIS audit (dial plan, phones, registration, partition/CSS analysis)
  • mcsiphon — CUCM serviceability + CDR (logs, real-time registration, control center, performance counters)

License

MIT — see LICENSE.

Source

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mccer-2026.5.8.1.tar.gz (94.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mccer-2026.5.8.1-py3-none-any.whl (30.5 kB view details)

Uploaded Python 3

File details

Details for the file mccer-2026.5.8.1.tar.gz.

File metadata

  • Download URL: mccer-2026.5.8.1.tar.gz
  • Upload date:
  • Size: 94.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"EndeavourOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for mccer-2026.5.8.1.tar.gz
Algorithm Hash digest
SHA256 af155eece7c2be9357cee5cc8c4778ee9df671d8849c9ac52ee2733eec86944f
MD5 e8d48e53bc1c49c7230ba23271c6790c
BLAKE2b-256 93f9bb6dfef5493cc8e91c32bee0249e5674b34bd91bba199a8e39c3aaf606b4

See more details on using hashes here.

File details

Details for the file mccer-2026.5.8.1-py3-none-any.whl.

File metadata

  • Download URL: mccer-2026.5.8.1-py3-none-any.whl
  • Upload date:
  • Size: 30.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"EndeavourOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for mccer-2026.5.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 65f227b3f52822719a6b45391d9b49ce8b16430dd1cf8982a7fb6e9e703da9dc
MD5 face0e2b84be5ff361e126c6b9750cdd
BLAKE2b-256 3a04df29fe29cdf2671fa9a23ccb2d7d795ebb40939aa29b45d1eee23f934246

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page