- route_plan.py: drop `NULL AS context` from voicemail_pilot_css query. Informix rejected it as a syntax error; the column wasn't carrying any signal anyway, so the simpler SELECT works and matches the other reference-point queries. - README.md: tool table now covers all 16 tools (route_device_pool_route_groups, route_devices_using_css, route_filters were missing). - .gitignore: explicitly ignore .env. Already covered by ~/.gitignore_global, but worth being self-contained — anyone cloning without the global ignore shouldn't be one stray `git add` away from leaking AXL credentials.
134 lines
5.4 KiB
Markdown
134 lines
5.4 KiB
Markdown
# mcp-cucm-axl
|
|
|
|
Read-only MCP server for **Cisco Unified CM 15** AXL — built for LLM-driven
|
|
cluster auditing, with a particular focus on the **Route Plan Report**:
|
|
partitions, calling search spaces, route patterns, translation patterns,
|
|
called/calling party transformations, and digit-discard instructions.
|
|
|
|
## Why this exists
|
|
|
|
CUCM's admin UI is great for one-config-at-a-time work but painful for
|
|
audit/discovery questions like:
|
|
|
|
- "Which translation patterns rewrite the calling party number, and why?"
|
|
- "Which CSSs include the `Internal_PT` partition, in what order?"
|
|
- "Show me every route pattern targeting the SIP trunk to the carrier."
|
|
- "Are there partitions defined but unreachable from any CSS?"
|
|
|
|
This server gives an LLM SQL access to CUCM's Informix data dictionary,
|
|
plus focused tools that bake in the right joins for routing-audit work.
|
|
Pair it with the sibling [`mcp-cisco-docs`](../docs/) server and the LLM
|
|
gets vendor documentation alongside live cluster state — answering
|
|
"is our config consistent with Cisco's recommended baseline?" in a single
|
|
conversation.
|
|
|
|
## Read-only by structural guarantee
|
|
|
|
The server **never registers** AXL write methods. There is no
|
|
`executeSQLUpdate`, no `add*`/`update*`/`remove*`/`apply*`/`reset*`/
|
|
`restart*` tool. Read-only is enforced by *absence* of write operations,
|
|
not by runtime sanitization. Defense-in-depth: SQL queries are also
|
|
client-side validated to begin with `SELECT` or `WITH`.
|
|
|
|
## Setup
|
|
|
|
### 1. Configure environment
|
|
|
|
Edit `.env` (already gitignored):
|
|
|
|
```env
|
|
AXL_URL=https://cucm-pub:8443/axl
|
|
AXL_USER=AxlUser
|
|
AXL_PASS=...
|
|
AXL_VERIFY_TLS=false # CUCM ships self-signed certs; default off
|
|
AXL_CACHE_TTL=3600 # 1 hour; 0 disables caching
|
|
AXL_WSDL_PATH= # optional explicit WSDL location
|
|
CISCO_DOCS_INDEX_PATH= # optional override for prompt enrichment
|
|
```
|
|
|
|
### 2. Bootstrap the AXL WSDL
|
|
|
|
Download the **Cisco AXL Toolkit** from your CUCM admin UI:
|
|
|
|
> Application → Plugins → Find → "Cisco AXL Toolkit" → Download
|
|
|
|
Drop the resulting `axlsqltoolkit.zip` into the project directory. On first
|
|
launch, the server auto-extracts `schema/15.0/` into `~/.cache/mcp-cucm-axl/wsdl/15.0/`.
|
|
The zip is gitignored (Cisco-licensed; not redistributable).
|
|
|
|
Alternatives (in resolution order):
|
|
|
|
```bash
|
|
# A: explicit zip elsewhere
|
|
export AXL_WSDL_ZIP=/path/to/axlsqltoolkit.zip
|
|
|
|
# B: explicit WSDL file
|
|
export AXL_WSDL_PATH=/path/to/schema/15.0/AXLAPI.wsdl
|
|
|
|
# C: pre-populated cache directory
|
|
mkdir -p ~/.cache/mcp-cucm-axl/wsdl/15.0/
|
|
cp /path/to/schema/15.0/* ~/.cache/mcp-cucm-axl/wsdl/15.0/
|
|
```
|
|
|
|
### 3. Install + run
|
|
|
|
```bash
|
|
uv sync
|
|
uv run mcp-cucm-axl
|
|
```
|
|
|
|
Or via the bundled `.mcp.json`, automatically registered when Claude Code
|
|
opens this directory.
|
|
|
|
## Tool surface
|
|
|
|
### Foundational
|
|
|
|
| Tool | Purpose |
|
|
|---|---|
|
|
| `axl_version()` | Cluster version sanity check |
|
|
| `axl_sql(query)` | Execute a SELECT against Informix data dictionary |
|
|
| `axl_list_tables(pattern=None)` | Discover Informix tables |
|
|
| `axl_describe_table(name)` | Column metadata for one table |
|
|
| `cache_stats()`, `cache_clear(pattern=None)` | Cache plumbing |
|
|
|
|
### Route plan
|
|
|
|
| Tool | Purpose |
|
|
|---|---|
|
|
| `route_partitions()` | All partitions with pattern + CSS-member counts |
|
|
| `route_calling_search_spaces(name=None)` | CSS list with ordered partitions |
|
|
| `route_patterns(kind=None, partition=None, filter=None)` | Route Plan Report — patterns + transformations |
|
|
| `route_inspect_pattern(pattern, partition=None)` | Deep dive: transforms, route filter, reachable-from CSS, full destination chain (route list → groups → gateways) |
|
|
| `route_lists_and_groups(name=None)` | Route list → route group → gateway chain (annotates Local Route Group placeholders) |
|
|
| `route_translation_chain(number, css_name=None)` | Wildcard-aware pattern matcher: evaluates X / ! / [0-9] / @ / \\+ against the number and returns matches sorted by specificity |
|
|
| `route_digit_discard_instructions()` | DDI catalog |
|
|
| `route_device_pool_route_groups(device_pool_name=None)` | How each device pool resolves Local Route Group placeholders to actual gateway-bearing groups |
|
|
| `route_devices_using_css(css_name)` | Impact analysis: every reference to a CSS across line CFA/CFB/CFNA/CFUR/translation/MWI/shared, device-level CSSs, voicemail pilots, route lists |
|
|
| `route_filters(name=None)` | Route filter clauses + member rules (composed with @-pattern routes) |
|
|
|
|
## Prompts
|
|
|
|
Schema-grounded conversation seeds. They pull relevant chunks from the
|
|
sibling `cisco-docs` index and embed them inline:
|
|
|
|
- `route_plan_overview` — fresh audit conversation seed
|
|
- `investigate_pattern(pattern, partition=None)` — deep-dive a specific pattern
|
|
- `audit_routing(focus="full")` — comprehensive audit walkthrough
|
|
- `cucm_sql_help(question)` — catch-all for arbitrary SQL questions
|
|
|
|
## Cache
|
|
|
|
Responses are cached in SQLite at `~/.cache/mcp-cucm-axl/responses/axl_responses.sqlite`.
|
|
Cache survives restarts. Clear with `cache_clear()` after a known config change.
|
|
|
|
## Notes
|
|
|
|
- `route_translation_chain` does literal/prefix matching only. CUCM's actual
|
|
matcher evaluates wildcards (`X`, `!`, `[0-9]`, etc.) and selects the
|
|
longest match. Treat results as "patterns to investigate" rather than
|
|
"definitive route."
|
|
- Pattern type codes (`tkpatternusage`) used by `route_patterns(kind=...)` are
|
|
stable across CUCM versions but enumerated against the `typepatternusage`
|
|
table at query time, so any cluster-specific custom types still work.
|