Skip to content

FAQ

Last update: June 4, 2026


Frequently asked questions about AI-Bridge for Cisco UC, organized by topic.


General

What is AI-Bridge for Cisco UC?

AI-Bridge for Cisco UC is an on-premises MCP (Model Context Protocol) server that bridges AI agents β€” Claude Desktop, GitHub Copilot, Cursor, or any MCP-compatible tool β€” to your Cisco Unified Communications infrastructure.

It is not a cloud service. It runs entirely on a Linux VM inside your network, exposes a secure HTTPS MCP endpoint to AI agents, and communicates with Cisco UC nodes using AXL, RIS, and SSH. No data leaves your environment through AI-Bridge.

Does it require internet access?

No. AI-Bridge is fully air-gapped capable. It has no telemetry, no cloud dependency, and no phone-home behavior. All connectivity is strictly between:

  • Your AI agent client β†’ AI-Bridge (HTTPS/MCP)
  • AI-Bridge β†’ Your Cisco UC nodes (AXL/HTTPS, RIS/HTTPS, SSH)

Even license verification is performed offline β€” the license file is a signed JWT validated locally against the server's hostname.

Which AI agents are compatible?

Any agent that supports the MCP Streamable HTTP transport protocol. For example:

  • Claude Desktop
  • VS Code with the MCP extension
  • Cursor
  • OpenCode
  • Custom LLM-based tools using the MCP SDK

AI-Bridge uses the standard MCP Streamable HTTP transport β€” any MCP-compliant client will work.

Can I use it with a cloud-hosted LLM?

Yes. The LLM (OpenAI, Anthropic Claude API, etc.) and the AI agent can be entirely cloud-hosted. The only connection that uses your internal network is the agent's MCP call to AI-Bridge.

Importantly, no Cisco UC data reaches the cloud LLM directly. The AI agent receives tool results from AI-Bridge and synthesizes them locally before sending any prompt to the LLM. You control exactly which tools and data the agent can access via RBAC profiles.

Is it compatible with local LLMs?

Yes. When paired with a local LLM (Ollama, LM Studio, llama.cpp, etc.) and a locally running AI agent, the entire chain operates without any internet connectivity. This is ideal for highly regulated environments where no data may leave the internal network.


Licensing

How do I get a license?

Contact contact@sourdeau.com to order a license. Once issued, you will receive a license.jwt file. Copy it to secrets/license.jwt and restart the server.

cp license.jwt secrets/license.jwt
docker compose restart
What happens when my license expires?

License expiry follows a two-phase model:

  1. Grace period (default: 30 days after expiry): the server continues to operate normally. A renewal reminder is logged at startup and emitted on the /status endpoint.
  2. Post-grace: product modules are disabled. The Infra and Common modules remain available, so you can still query server status and manage reports.

Plan ahead

Monitor your license expiry via infra_get_license_info or GET /status. Renewing before the grace period ends ensures zero service interruption.

Can I use the same license on a different server?

No. Licenses are hostname-bound β€” each license is issued for a specific server hostname. Running the same license on a different hostname will result in an INVALID state.

Contact contact@sourdeau.com for re-issuance when migrating to a new server.

Is the license version-agnostic?

Yes. A valid license continues to work across all software upgrades β€” there is no per-version licensing. Once issued, your license is valid until its expiry date regardless of how many times you upgrade.

What is a demo license?

A time-limited license for evaluation purposes. It grants full access to all product modules for a fixed trial period. Available on request at contact@sourdeau.com.

What server attribute is the license bound to?

The license is bound to the server hostname (hostname -f). The hostname is embedded in the license JWT at issuance time and verified at every startup. Any hostname change β€” VM rename, migration, DNS update β€” will invalidate the license.

Contact contact@sourdeau.com for re-issuance if the hostname changes.

How do I check the current license status?

Use the dedicated script:

python scripts/license_checker.py

This displays the license state, bound hostname, expiry date, licensed products, and the grace period status β€” without requiring the MCP server to be running.

Alternatively, use the infra_get_license_info MCP tool or GET /status when the server is running.


Installation & Setup

What Linux distributions are supported?

AI-Bridge should run on any modern Linux distribution that supports Python 3.11+ and systemd. The following distributions are actively tested and recommended for production use:

Distribution Versions
Ubuntu LTS 22.04, 24.04
RHEL / AlmaLinux 9.x, 10.x
Debian 12, 13

Other distributions (Fedora, openSUSE, Arch, etc.) are not officially tested but should work provided the Python and system dependencies are met.

Can I run it in Docker?

Yes. Docker deployment is fully supported. See the Getting Started guide for Docker installation instructions.

# Edit .env β€” configure AUTH_CLIENTS and other settings
docker compose up -d

The Docker setup includes a multi-stage build (Python 3.13), non-root user (mcpadmin), read-only filesystem, and health checks. All runtime data is persisted via bind-mount volumes.

Can I run multiple instances?

Yes. You can run multiple AI-Bridge instances on separate Linux hosts, each with its own hostname-bound license. This is the recommended approach for separating environments (e.g., production vs. lab) or serving multiple teams with isolated audit trails.

What if the RSA-PSS signature check fails during installation?

Do not proceed with the installation. A signature verification failure means either:

  • The archive was corrupted during download (retry the download and verify SHA-512)
  • The archive has been tampered with

Contact contact@sourdeau.com before proceeding. Never run software that fails its integrity check.

How do I reconfigure after installation?

Edit .env directly, then recreate the container:

nano .env
docker compose up -d
How do I change the listening port (e.g. 8443 β†’ 9443)?
  1. Edit .env and change the port value:

    MCP_SERVER_PORT=9443
    
  2. If you use transport security, update the allowed hosts and origins to reflect the new port:

    MCP_SERVER_SECURITY_ALLOWED_HOSTS=localhost:*,127.0.0.1:*,mcp.domain.com:*
    MCP_SERVER_SECURITY_ALLOWED_ORIGINS=https://localhost:9443,https://127.0.0.1:9443,https://mcp.domain.com:9443
    
  3. Recreate the container (port mapping is updated automatically from .env):

    docker compose up -d
    
  4. Update the endpoint URL in all AI agent configurations to use the new port.

  5. If applicable, update your firewall rules to allow the new port.

Tip

The docker-compose.yml port mapping uses ${MCP_SERVER_PORT:-8443} β€” it reads the value from .env automatically. No need to edit docker-compose.yml.

How do I completely uninstall AI-Bridge?

To fully remove AI-Bridge from a server, follow these steps:

1. Stop and remove the container:

docker compose down

2. Remove the Docker image:

# List AI-Bridge images
docker images | grep ai-bridge

# Remove the image
docker rmi ai-bridge-for-cisco-uc:latest

# Remove any dangling images
docker image prune -f

3. Delete the installation directory:

rm -rf ~/ai-bridge

After these steps, no AI-Bridge artefacts remain on the server.


Authentication & Clients

How many AI clients can I have simultaneously?

The number of active clients is limited by the max_clients field in your license. Each client is a separate entry in AUTH_CLIENTS in .env. Contact contact@sourdeau.com if you need to increase your client limit.

How do I add a new client?

Add an entry to AUTH_CLIENTS in .env and restart the server:

AUTH_CLIENTS='alice:sub-alice:admin,bob:sub-bob:operator,carol:sub-carol:auditor'

At the next startup, a new client directory is created and credentials (JWT token or OAuth secret) are generated automatically. Distribute the token from clients/<name>/secrets/.token to the new user.

How do I remove a client?

Remove the client's entry from AUTH_CLIENTS in .env and restart the container (docker compose up -d). The client's directory β€” including all reports, tokens, and stored credentials β€” is purged automatically.

Data loss warning

Export any reports or data you wish to retain before removing a client entry and restarting.

How do I revoke a client token without removing the client?

Delete the client's credential files and restart the server β€” they are regenerated automatically:

rm clients/<name>/secrets/.secret
rm clients/<name>/secrets/.secret_hash
rm clients/<name>/secrets/.token
docker compose restart

After restart, a new token (JWT mode) or a new secret (OAuth mode) is generated automatically. Retrieve the new values from clients/<name>/secrets/.token and .secret before distributing them.

Note

The POST /revoke endpoint is an alternative for token-only invalidation without a restart. The files-and-restart method is more thorough: it forces full credential regeneration.

What is the difference between JWT and OAuth 2.1 mode?
JWT Mode OAuth 2.1 Mode
Token type Static, long-lived (default: 365 days) Dynamic, short-lived (default: 1 hour)
Issuance Pre-generated at startup On-demand via POST /token
Client secret None bcrypt-hashed, one-time plaintext
Best for Interactive AI agents (simple setup) Automated pipelines, CI/CD, stricter security
Revocation POST /revoke POST /revoke

Both modes are equally secure in terms of transport and signature. OAuth 2.1 limits the window of exposure if a token is compromised due to its short lifetime.

What happens to tokens after an RSA key rotation?

All existing JWT tokens are immediately invalidated β€” they were signed with the old private key and cannot be verified against the new one.

At the next startup, new tokens are automatically regenerated for all clients and written to clients/<name>/secrets/.token. You must redistribute the new tokens to all AI agent users.

OAuth client secrets (bcrypt-based) are unaffected by key rotation.

How do I configure the MCP server in OpenCode with OAuth authentication?

In OAuth 2.1 mode, OpenCode handles the authentication flow natively β€” no bearer token needs to be hard-coded in the configuration file.

Edit opencode.json and declare the server without an Authorization header:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "cisco-uc-mcp-server": {
      "type": "remote",
      "url": "https://mcp.domain.com:8443/mcp/",
      "enabled": true
    }
  }
}

Before starting the OpenCode desktop client, run the following CLI command to authenticate:

opencode mcp auth cisco-uc-mcp-server

OpenCode will open a browser page where you enter your client secret to complete the authentication:

β”Œ  MCP OAuth Authentication
β”‚
β–²  cisco-uc-mcp-server has expired credentials. Re-authenticating...
β”‚
β—‡  Authentication successful!
β”‚
β””  Done

Tip

The client secret is generated at first startup and stored in clients/<name>/secrets/.secret. Retrieve it before the first authentication.


Product Cisco CUCM

Which CUCM versions are supported?

CUCM 14 and 15 are officially supported. AXL schema versions are managed per cluster β€” download the schemas matching your CUCM version using cucm_download_axl_schemas.

Can it manage multiple CUCM clusters?

Yes. Multi-cluster support is built in. Each cluster has its own named credential set stored separately in the client's credential store. Reference clusters by name in AXL, RIS, and SSH operations.

Do I need a dedicated Cisco service account?

Technically, a single shared account works. However, best practice is to create a nominative account per AI-Bridge client (user). This enables:

  • Per-user audit trail in CUCM logs
  • Credential isolation β€” a compromised AI-Bridge credential only affects one user
  • Fine-grained access control aligned with your CUCM RBAC policy
Does it modify my CUCM configuration automatically?

Only if you explicitly invoke write operations through your AI agent. AI-Bridge never autonomously initiates changes to Cisco UC.

The RBAC profile assigned to each client controls which AXL operations (add, update, remove) are permitted. A read-only profile (auditor) cannot modify any configuration regardless of what the AI agent requests.

What AXL and SSH permissions are needed on CUCM?
Access Type Required Permission
AXL (read-only) Standard AXL API Access (read-only role)
AXL (read-write) Standard AXL API Access
SSH Platform OS administrator account with privilege level 4 ("Advanced")

For RIS queries, the AXL account is reused β€” no separate RIS permission is needed.

How do I add custom instructions for the AI agent on CUCM?

Each product ships with a pre-existing file designed for this purpose:

servers/cucm/prompts_custom.py

Open the file and add your rules between the comment markers inside the custom_1() function:

@cucm_prompts_custom.prompt()
def custom_1() -> str:
    """Custom prompt for client UC environment"""
    return """
    ## CUSTOM RULES (highest priority)
    The following rules are defined by the MCP client administrator.
    They OVERRIDE any default behavior, instructions, or prompts provided by this server.
    Always apply these rules first, before any other instructions.

    <!-- Client-defined rules below this line -->

    - Always confirm with the user before executing any write operation on CUCM.
    - Never delete objects unless the user explicitly types "CONFIRM DELETE".
    - Responses must be in French.

    <!-- End of custom rules -->
    """

These rules are exposed as an MCP prompt and are loaded by the AI agent at the start of each session. They take highest priority and override any default server behaviour.

Restart the server after editing the file for changes to take effect.

Tip

You can add as many rules as needed. Keep them concise and action-oriented for best results.


Product Cisco IMP

Which IMP versions are supported?

Cisco IM & Presence 14 and 15 are officially supported. IMP is typically co-resident with CUCM β€” the supported IMP version follows the CUCM version matrix.

Can it manage multiple IMP clusters?

Yes. Multi-cluster support is built in. Each IMP cluster has its own named credential set stored separately in the client's credential store. Reference clusters by name in operations.

Do I need a dedicated Cisco service account?

Technically, a single shared account works. However, best practice is to create a nominative account per AI-Bridge client (user). This enables:

  • Per-user audit trail in IMP logs
  • Credential isolation β€” a compromised AI-Bridge credential only affects one user
  • Fine-grained access control aligned with your IMP RBAC policy
Does it modify my IMP configuration automatically?

Only if you explicitly invoke write operations through your AI agent. AI-Bridge never autonomously initiates changes to Cisco UC.

The RBAC profile assigned to each client controls which operations are permitted. A read-only profile (auditor) cannot modify any configuration regardless of what the AI agent requests.

What permissions are needed on IMP?
Access Type Required Permission
API (read-only) Read-only administrative role
API (read-write) Full administrative role
SSH Platform OS administrator account with privilege level 4 ("Advanced")
How do I add custom instructions for the AI agent on IMP?

Each product ships with a pre-existing file designed for this purpose:

servers/imp/prompts_custom.py

Open the file and add your rules between the comment markers inside the custom_1() function:

@imp_prompts_custom.prompt()
def custom_1() -> str:
    """Custom prompt for client IMP environment"""
    return """
    ## CUSTOM RULES (highest priority)
    The following rules are defined by the MCP client administrator.
    They OVERRIDE any default behavior, instructions, or prompts provided by this server.
    Always apply these rules first, before any other instructions.

    <!-- Client-defined rules below this line -->

    - Always confirm with the user before executing any write operation on IMP.
    - Never delete objects unless the user explicitly types "CONFIRM DELETE".
    - Responses must be in French.

    <!-- End of custom rules -->
    """

These rules are exposed as an MCP prompt and are loaded by the AI agent at the start of each session. They take highest priority and override any default server behaviour.

Restart the server after editing the file for changes to take effect.

Tip

You can add as many rules as needed. Keep them concise and action-oriented for best results.


Product Cisco CUC

Which CUC versions are supported?

Cisco Unity Connection 14 and 15 are officially supported. CUC exposes its provisioning API through CUPI (REST at https://<host>:8443/vmrest/) β€” there is no AXL/SOAP toolkit and no WSDL schema to download.

Can it manage multiple CUC nodes?

Yes. CUC has no cluster abstraction in AI-Bridge β€” credentials and operations are scoped per host. Add as many CUC hosts as needed via cuc_store_credentials (CUPI) and cuc_os_store_credentials (SSH); each host is stored separately in the client's credential store.

Do I need a dedicated Cisco service account?

Technically, a single shared account works. However, best practice is to create a nominative account per AI-Bridge client (user). This enables:

  • Per-user audit trail in CUC logs
  • Credential isolation β€” a compromised AI-Bridge credential only affects one user
  • Fine-grained access control aligned with your CUC RBAC policy
Does it modify my CUC configuration automatically?

Only if you explicitly invoke write operations through your AI agent. AI-Bridge never autonomously initiates changes to Cisco UC.

The RBAC profile assigned to each client controls which CUPI verbs (POST / PUT / DELETE) and which /vmrest/ paths are permitted. A read-only profile (auditor) is restricted to GET /vmrest/ and cannot modify any configuration regardless of what the AI agent requests.

What CUPI and SSH permissions are needed on CUC?
Access Type Required Permission
CUPI (read-only) Unity Connection administrator with the "System Administrator" role
CUPI (read-write) Unity Connection administrator with a role template covering the targeted endpoints (users, call handlers, schedules, etc.)
SSH Platform OS administrator account with privilege level 4 ("Advanced")
How do I add custom instructions for the AI agent on CUC?

Each product ships with a pre-existing file designed for this purpose:

servers/cuc/prompts_custom.py

Open the file and add your rules between the comment markers inside the custom_1() function:

@cuc_prompts_custom.prompt()
def custom_1() -> str:
    """Custom prompt for client CUC environment"""
    return """
    ## CUSTOM RULES (highest priority)
    The following rules are defined by the MCP client administrator.
    They OVERRIDE any default behavior, instructions, or prompts provided by this server.
    Always apply these rules first, before any other instructions.

    <!-- Client-defined rules below this line -->

    - Always confirm with the user before executing any write operation on CUC.
    - Never delete objects unless the user explicitly types "CONFIRM DELETE".
    - Responses must be in French.

    <!-- End of custom rules -->
    """

These rules are exposed as an MCP prompt and are loaded by the AI agent at the start of each session. They take highest priority and override any default server behaviour.

Restart the server after editing the file for changes to take effect.

Tip

You can add as many rules as needed. Keep them concise and action-oriented for best results.


Security

Where are Cisco UC credentials stored?

Credentials are encrypted on disk, per client, using Fernet encryption (AES-128-CBC + HMAC-SHA256). The Fernet key is derived per-client via PBKDF2-SHA512 with 600,000 iterations, seeded from a stable UUID unique to each client (clients/<name>/secrets/.uuid).

Credentials are never stored in plaintext in .env, logs, or any other file.

Can the server read its own backups?

No. Backups are encrypted using the RSA public key (RSA-4096 OAEP). The server can create backups without the private key, but decryption requires the RSA private key explicitly. This is intentional β€” it limits blast radius if the server process is compromised.

How does the audit log work?

Every auth event, tool call, credential operation, and security anomaly is written to audit.log as a structured JSON object. The log is append-only β€” entries are never modified after being written.

Log rotation creates compressed archives, preserving the complete history. For long-term retention and SIEM integration, forward audit.log to your log aggregation infrastructure.

What happens if someone tampers with the server files?

The integrity watchdog runs an SHA-512 manifest check against all project files at startup and every 24 hours thereafter. The manifest is signed with RSA-PSS (RSA-4096) and cannot be forged without the editor signing key.

If tampering is detected at startup, the server refuses to start and logs the affected files at CRITICAL level in app.log and audit.log.

If tampering is detected during a periodic check (while running):

  • The affected files and hash mismatches are logged to app.log and audit.log at CRITICAL level
  • The integrity failure is prominently surfaced in /status and Prometheus metrics

React to integrity failures immediately

An integrity alert is a serious security event. Isolate the server, investigate the affected files, and restore from a known-good backup.

How do I report a security vulnerability?

Email security@sourdeau.com privately with a description of the vulnerability. Do not open a public GitHub issue for security findings β€” responsible disclosure protects all users.

You will receive an acknowledgment within 48 hours.


Troubleshooting

Product modules are not loaded β€” what should I check?

Check the license state using the infra_get_server_status tool or GET /status. Common causes:

State Cause Resolution
INVALID secrets/license.jwt missing, tampered, or hostname mismatch Verify the file exists and the server hostname matches the license
EXPIRED License past grace period Renew via contact@sourdeau.com
GRACE Within grace period Renew soon β€” modules still loaded

If the MCP server does not start at all, check the license manually with:

python scripts/license_checker.py

This runs independently of the server and shows the full license state, bound hostname, and error details.

My AI agent cannot connect to AI-Bridge β€” what should I check?

Work through this checklist in order:

  1. Endpoint URL and port β€” verify the agent is configured with the correct URL (e.g., https://mcp.domain.com:8443/mcp)
  2. Bearer token validity β€” confirm the token in clients/<name>/secrets/.token matches what the agent is using
  3. TLS certificate trust β€” the AI agent must trust AI-Bridge's TLS certificate. Either trust the self-signed cert in the agent's trust store, or replace it with a CA-signed certificate
  4. Network / firewall β€” confirm TCP port 8443 is reachable from the agent host to the AI-Bridge host
Authentication fails with HTTP 401 β€” what are the possible causes?
Cause Resolution
Token expired Retrieve a fresh token from clients/<name>/secrets/.token (after a restart it is renewed)
Token revoked Token was explicitly revoked via POST /revoke. A new token is generated on the next startup.
RSA key rotated All JWT tokens are invalidated after key rotation. Retrieve the new token generated post-rotation.
Wrong token format Ensure the Authorization header uses Bearer <token> format exactly
My IP is blocked and I receive HTTP 429 β€” what do I do?

The Fail2Ban mechanism has blocked your IP after repeated authentication failures. The blacklist is in-memory only β€” it is not persisted to a file and is automatically cleared on server restart.

Options:

  • Wait for the blacklist duration to expire (default: 15 minutes, configured in AUTH_BLACKLIST_DURATION_SECONDS)
  • Restart the server to immediately clear all blacklist entries (docker compose restart)

To see which IPs were blocked and why, search audit.log for AUTH_BLOCKED events:

grep AUTH_BLOCKED logs/audit.log | tail -20

After unblocking, resolve the root cause of the authentication failures before reconnecting.

The license shows INVALID β€” what should I verify?

Check these three things in order:

  1. File exists β€” ls -la secrets/license.jwt β€” the file must be present and readable
  2. Hostname match β€” the server's hostname (hostname -f) must exactly match the hostname in the license. A VM rename or migration will break this.
  3. File integrity β€” if the file was transferred via a tool that may have altered line endings or encoding, re-transfer it in binary mode
OAuth token request fails with 401 invalid_client β€” what happened?

The most common cause: the plaintext .secret file was auto-deleted after the client's first successful authentication, and the .secret_hash no longer matches what is being sent.

To regenerate OAuth credentials for a client:

  1. Delete clients/<name>/secrets/.secret_hash
  2. Restart the server β€” new credentials are generated automatically
  3. Retrieve the new plaintext secret from clients/<name>/secrets/.secret before first use
My OpenCode client cannot connect (error ERR_TLS_CERT_ALTNAME_INVALID) β€” what should I check?

This error means the TLS certificate presented by the server does not contain the server's FQDN in the Subject Alternative Name (SAN) extension.

Node.js v17+ (and all modern TLS clients) require the SAN extension β€” the CN field alone is no longer accepted for hostname validation (RFC 6125).

To fix it, regenerate the certificate with a proper SAN using the built-in CSR generator (the server must be running):

docker compose exec ai-bridge python scripts/certificate_generate_csr.py

Then sign the generated CSR with your internal CA using the openssl x509 command printed by the script, and redeploy the new certificate. Ensure TLS_CA_SIGNED_CERT_FILE and TLS_CA_SIGNED_KEY_FILE in .env point to the new files, then restart the server.

Tip

If your CA is not trusted by OpenCode's Node.js runtime, also set NODE_EXTRA_CA_CERTS=/path/to/ca.crt in your environment (or export it from ~/.bashrc).