Metadata-Version: 2.4
Name: mcaxl
Version: 2026.4.27.1
Summary: Read-only MCP server for Cisco Unified Communications Manager (CUCM) — AXL SOAP API + RisPort70 registration state — purpose-built for LLM-driven dial-plan and configuration auditing.
Project-URL: Homepage, https://git.supported.systems/mcp/mcaxl
Project-URL: Source, https://git.supported.systems/mcp/mcaxl
Project-URL: Issues, https://git.supported.systems/mcp/mcaxl/issues
Project-URL: Changelog, https://git.supported.systems/mcp/mcaxl/src/branch/main/CHANGELOG.md
Author-email: Ryan Malloy <ryan@supported.systems>
License: MIT
License-File: LICENSE
Keywords: audit,axl,cisco,cucm,mcp,risport,sip,telephony,voip
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: System Administrators
Classifier: Intended Audience :: Telecommunications Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Telephony
Classifier: Topic :: System :: Networking :: Monitoring
Requires-Python: >=3.11
Requires-Dist: fastmcp>=3.2
Requires-Dist: numpy>=1.26
Requires-Dist: platformdirs>=4.9
Requires-Dist: python-dotenv>=1.0
Requires-Dist: zeep>=4.3
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.24; extra == 'test'
Requires-Dist: pytest>=8.0; extra == 'test'
Description-Content-Type: text/markdown

# mcaxl

Read-only MCP server for **Cisco Unified Communications Manager (CUCM)** —
exposes the AXL SOAP API and RisPort70 real-time registration state to
LLMs for dial-plan analysis, configuration auditing, and impact analysis.

> Tested against CUCM 15.0(1). Should work on any CUCM 12.5+.

## 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 our PSTN carrier."*
- *"Are there partitions defined but unreachable from any CSS?"*
- *"Which phones are configured but not currently registered?"*

`mcaxl` gives an LLM SQL access to CUCM's Informix data dictionary,
schema-aware joins for common audit questions, and RisPort70
cross-reference for live registration state. Then a set of curated
prompts orchestrates the tools toward audit *findings*, not just data.

## 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`.

For operations that require write access (service control, packet capture,
log download, perfmon, etc.), install
[`@calltelemetry/cisco-cucm-mcp`](https://github.com/calltelemetry/cisco-cucm-mcp)
alongside this server. The two are complementary — `mcaxl` answers
"what does the config say?", `cisco-cucm-mcp` answers "what's happening
right now?".

## Install

```bash
# Run directly from PyPI:
uvx mcaxl

# Or as a pinned dev install:
pip install mcaxl

# Or via Claude Code's MCP registry:
claude mcp add cucm-axl -- uvx mcaxl
```

## Configure

Set these env vars (most operators use a `.env` file in the working directory):

```env
AXL_URL=https://cucm-pub.example.com:8443/axl/
AXL_USER=your-axl-service-account
AXL_PASS=your-password

# Optional:
AXL_VERIFY_TLS=false           # CUCM ships self-signed certs; default off
AXL_CACHE_TTL=3600             # response cache TTL in seconds; 0 disables
AXL_RATE_LIMIT_RETRIES=3       # 502/503/504 retry count with backoff
AXL_WSDL_PATH=                 # explicit WSDL location override
AXL_WSDL_ZIP=                  # explicit toolkit zip path
CISCO_DOCS_INDEX_PATH=         # for prompt enrichment (see Prompts section)
```

The AXL service account needs the **`Standard AXL Read Only API Access`**
role at minimum. It does *not* need the full `Standard AXL API Access`
role (read-write) — `mcaxl` is structurally incapable of using write
permissions even if granted.

## AXL WSDL bootstrap

CUCM's AXL toolkit is Cisco-licensed and not redistributable, so it's
not bundled. Download from your CUCM admin UI:

> Application → Plugins → Find → "Cisco AXL Toolkit" → Download

Drop the resulting `axlsqltoolkit.zip` into your working directory. On
first launch, the server auto-extracts `schema/15.0/` (or whichever
version matches your cluster) into `~/.cache/mcaxl/wsdl/15.0/`.

Alternative resolution paths (in order):
```bash
export AXL_WSDL_ZIP=/path/to/axlsqltoolkit.zip       # explicit zip
export AXL_WSDL_PATH=/path/to/schema/15.0/AXLAPI.wsdl  # explicit WSDL
# Or pre-populate the cache:
mkdir -p ~/.cache/mcaxl/wsdl/15.0/
cp /path/to/schema/15.0/* ~/.cache/mcaxl/wsdl/15.0/
```

## Tool surface (19 total)

### 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 |
| `health()` | Subsystem self-check (cache / AXL / docs / RisPort init state) |

### 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 |
| `route_translation_chain(number, css_name=None)` | Wildcard-aware pattern matcher |
| `route_digit_discard_instructions()` | DDI catalog |
| `route_device_pool_route_groups(device_pool_name=None)` | Local Route Group resolution |
| `route_devices_using_css(css_name)` | Impact analysis across 71 known fk-CSS columns |
| `route_filters(name=None, include_members=False)` | Route filter clauses + member rules |

### Real-time device registration (RisPort70)

| Tool | Purpose |
|---|---|
| `device_registration_status(device_class, status, name_filter, page_size)` | Page through CUCM's RisPort `selectCmDevice` for live registration state |
| `device_registration_summary()` | Cluster-wide breakdown across Phone, Gateway, SIPTrunk, HuntList, etc. |

## Prompts (10 total)

Each prompt orchestrates multiple tool calls toward a specific
audit narrative. They appear in Claude Code's slash menu under
`/mcp__cucm-axl__<name>`:

- `route_plan_overview` — fresh audit conversation seed
- `investigate_pattern(pattern, partition=None)` — single-pattern deep dive
- `audit_routing(focus="full")` — comprehensive walkthrough with checklist
- `cucm_sql_help(question)` — catch-all SQL helper
- `sip_trunk_report(name_filter=None)` — SIP trunk inventory + findings
- `phone_inventory_report(filter=None)` — phone fleet aggregates with anomaly findings (cross-references RisPort)
- `user_audit(focus="full")` — end users + app users + role assignments
- `inbound_did_audit()` — XFORM-Inbound-DNIS inventory + screening pipeline
- `hunt_pilot_audit()` — hunt pilots, queue settings, line group membership
- `whoami(userid=None)` — single-user role chain (defaults to AXL service account)

### Optional: schema-grounded prompt enrichment

Set `CISCO_DOCS_INDEX_PATH` to a directory containing `chunks.jsonl`
and `index_meta.json` (produced by the
[`mcp-cisco-docs`](https://github.com/...) indexer or any compatible
embedding pipeline) to have prompts pull relevant Cisco documentation
chunks inline. Without this, prompts gracefully degrade to a fallback
notice instructing the LLM to use the sibling cisco-docs server's
`search_docs` tool.

## Cache

Responses are cached in SQLite at
`~/.cache/mcaxl/responses/axl_responses.sqlite`. The cache is
**cluster-isolated** by SHA-256 of `AXL_URL` — pointing the server
at a different cluster never serves stale data from a previous one.
Cache survives restarts. Clear with `cache_clear()` after a known
config change.

## Caveats

- `route_translation_chain` evaluates CUCM wildcards (`X`, `!`, `[0-9]`,
  `@`, `\+`) but does *not* model route-filter constraints on `@`
  patterns. Use as guidance, not authoritative.
- The package's `recordingprofile` / `usageprofile` / `vipre164transformation`
  reference categories were schema-verified against CUCM 15. If a future
  CUCM version adds new `fkcallingsearchspace_*` columns,
  `route_devices_using_css`'s coverage will lag until the package is
  updated. The
  `test_complete_schema_coverage_against_known_columns` test enforces
  the current snapshot — failing red surfaces the drift loudly.

## License

MIT. See `LICENSE`.

## Source

- Repo: [git.supported.systems/mcp/mcaxl](https://git.supported.systems/mcp/mcaxl)
- Issues: [git.supported.systems/mcp/mcaxl/issues](https://git.supported.systems/mcp/mcaxl/issues)
- Changelog: [`CHANGELOG.md`](./CHANGELOG.md)
