Skip to main content
Glama
cfollette18

Ivanti MCP

by cfollette18
README.md
# Ivanti MCP

Production [FastMCP](https://gofastmcp.com) server for **Ivanti Neurons ITSM**. Tools call Ivanti's OData REST API. MCP is only the contract between a client (IDE, gateway, or agent) and this process.

Auth follows the same split used by Azure MCP and Atlassian Rovo:

1. **Inbound** — the MCP client authenticates to this server (HTTP only).
2. **Outbound** — this server authenticates to Ivanti with a tenant API key.

STDIO is for a local subprocess. HTTP is fail-closed: it will not start without `MCP_JWKS_URI` or `MCP_JWT_SECRET`.

Author: **Clinton Follette**.

## Tools

| Tool | Access | Notes |
|---|---|---|
| `get_incident` | read | Loads the incident by `RecId`. Maps `Subject` / `Symptom` (not Description). |
| `add_note` | write | Creates a journal (`Notes`, `Summary`, `ParentLink_RecID`). Hidden when `MCP_READ_ONLY=true`. |
| `resolve_incident` | write, destructive | Reads `Status` first; no-op if already closed. Hidden when `MCP_READ_ONLY=true`. |

Structured output is typed. Tool annotations set `readOnlyHint` / `destructiveHint` / `idempotentHint` so clients can skip confirmations on reads.

## Install (local STDIO)

Cursor / Claude Desktop / VS Code:

```json
{
  "mcpServers": {
    "ivanti": {
      "command": "mcp-ivanti",
      "env": {
        "IVANTI_BASE_URL": "https://your-tenant.ivanti.com",
        "IVANTI_API_KEY": "<rest-api-key>"
      }
    }
  }
}
```

```bash
pip install .
mcp-ivanti
```

## Remote HTTP

```bash
export MCP_TRANSPORT=http
export MCP_HOST=127.0.0.1
export MCP_PORT=8001
export MCP_JWKS_URI=https://login.example.com/.well-known/jwks.json
export MCP_JWT_ISSUER=https://login.example.com
export MCP_JWT_AUDIENCE=mcp-ivanti
mcp-ivanti
```

Endpoint: `http://127.0.0.1:8001/mcp`. Health: `GET /health`.

Internal machine-to-machine can use an HMAC JWT (`MCP_JWT_SECRET`, HS256) instead of JWKS. Do not put this process on the public internet without TLS in front of it.

## Outbound Ivanti configuration

| Variable | Required | Purpose |
|---|---|---|
| `IVANTI_BASE_URL` | yes | Tenant origin |
| `IVANTI_API_KEY` | yes | REST key. Sent as `Authorization: rest_api_key=...` (or `Bearer` if `IVANTI_AUTH_SCHEME=bearer`) |
| `IVANTI_RESOLVED_STATUS` | no | Default `Closed` |
| `IVANTI_CLOSE_VIA` | no | `patch_status` or `quick_action` |
| `IVANTI_CLOSE_ACTION_ID` | if quick action | Quick Action id |
| `IVANTI_JOURNAL_OBJECT` | no | Default `journal.notess` — confirm in `$metadata` |
| `MCP_READ_ONLY` | no | Hide write tools |

Tokens never go in git. Copy `.env.example` to `.env`.

## Security

- HTTP without inbound JWT configuration refuses to boot.
- `mask_error_details` is on. Vendor 401s do not echo keys.
- RecId values are rejected if they contain path characters.
- Prefer binding HTTP to loopback or an internal hostname; set `MCP_ALLOWED_HOSTS` to enable Host/Origin protection.

See [SECURITY.md](SECURITY.md).

## License

MIT. Copyright (c) 2026 Clinton Follette.

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: get_incident reads incident data, add_note writes to the journal, and resolve_incident changes status. There is no meaningful overlap between read and write operations.

Naming Consistency4/5

All tool names use lowercase snake_case with a verb-first pattern. However, add_note does not explicitly reference incidents like the other two tools, so using add_incident_note would make the naming more consistent.

Tool Count5/5

Three tools is at the lower end of the typical range but appropriate for a focused incident-handling server. Each tool is essential and earns its place without redundancy.

Completeness3/5

The set covers the common workflow of viewing an incident, adding a note, and resolving it. However, it lacks create, update, search/list, and other lifecycle operations, so it only partially covers the broader incident management domain.

Maintenance

ActivityMaintained
ResponsivenessNo issues