Metadata-Version: 2.5
Name: netlicensing-mcp
Version: 0.1.11
Summary: MCP server for the Labs64 NetLicensing license management API
Project-URL: Homepage, https://github.com/Labs64/NetLicensing-MCP
Project-URL: Repository, https://github.com/Labs64/NetLicensing-MCP
Project-URL: Issues, https://github.com/Labs64/NetLicensing-MCP/issues
License: Apache-2.0
License-File: LICENSE
Keywords: fastmcp,labs64,license-management,mcp,netlicensing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.12
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp[cli]<2.0.0,>=1.7.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: dev
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: pip-audit; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Description-Content-Type: text/markdown

<p align="center"><img src="https://raw.githubusercontent.com/Labs64/NetLicensing-MCP/refs/heads/master/assets/banner.jpg"></p>

# NetLicensing MCP Server
 
<!-- mcp-name: io.github.Labs64/netlicensing-mcp -->
 
[![CI](https://github.com/Labs64/NetLicensing-MCP/actions/workflows/netlicensing-ci.yml/badge.svg)](https://github.com/Labs64/NetLicensing-MCP/actions/workflows/netlicensing-ci.yml)
[![PyPI](https://img.shields.io/pypi/v/netlicensing_mcp)](https://pypi.org/project/netlicensing-mcp/)
[![GHCR](https://img.shields.io/github/v/release/Labs64/NetLicensing-MCP?label=ghcr.io%2Flabs64%2Fnetlicensing-mcp&logo=docker&logoColor=white&style=flat-square)](https://github.com/Labs64/NetLicensing-MCP/pkgs/container/netlicensing-mcp)
[![Docker Hub](https://img.shields.io/docker/v/labs64/netlicensing-mcp?logo=docker&logoColor=white&label=Docker%20Hub&color=2496ED)](https://hub.docker.com/r/labs64/netlicensing-mcp)
[![MCP Registry](https://img.shields.io/badge/MCP_Registry-netlicensing--mcp-blue?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyek0xMSAxN3YtNkg5bDMtNCAzIDRoLTJ2NmgtMnoiLz48L3N2Zz4=&style=flat-square)](https://registry.modelcontextprotocol.io/?q=netlicensing-mcp)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/)
[![License](https://img.shields.io/badge/license-Apache%202.0-green.svg)](LICENSE)

**The official [Labs64 NetLicensing](https://netlicensing.io) MCP Server** — a natural language interface that lets AI agents manage software licenses, customers, and entitlements through conversational commands.
 
Works with Claude Desktop, GitHub Copilot (Agent mode), VS Code, JetBrains / IntelliJ IDEA, and any other MCP-compatible client.
 
---
 
## Why use this?
 
- **Natural Language Licensing** — Ask your AI assistant to create products, issue licenses, validate entitlements, and generate shop URLs without touching the NetLicensing UI or writing API calls.
- **Full API coverage** — Various tools spanning the entire NetLicensing [REST API](https://netlicensing.io/wiki/restful-api): products, modules, templates, licensees, licenses, bundles, tokens, transactions, and payment methods.
- **Built-in audit prompts** — Five ready-to-run prompt templates for account audits, expiry sweeps, anomaly detection, and cleanup workflows.
- **Safe by default** — All delete operations expose a `force_cascade` option; nothing is silently cascaded.
- **Zero-dependency quick start** — Run with `uvx` or Docker without a local Python install.
 
---
 
## What can you ask?
 
Once connected, you can talk to NetLicensing in plain language:
 
- *"List all products in my NetLicensing account."*
- *"Create a new licensee for `customer@example.com` under product PTEST."*
- *"Validate the license for licensee L001 — does it pass?"*
- *"Generate a shop URL for licensee L001 so they can self-serve their renewal."*
- *"Which licenses are expiring in the next 30 days?"*
- *"Find any licensees with no active licenses — flag them for cleanup."*
- *"Transfer all licenses from licensee L001 to L002."*
- *"Create an API key token scoped to read-only access."*
- *"Show me all transactions from the last month."*
 
---
 
## Features
 
| Area | Tools |
|---|---|
| **Products** | list, get, create, update, delete |
| **Product Modules** | list, get, create, update, delete |
| **License Templates** | list, get, create, update, delete |
| **Licensees** | list, get, create, update, delete, validate, transfer |
| **Licenses** | list, get, create, update (activate/deactivate), delete |
| **Bundles** | list, get, create, update, delete, obtain |
| **Tokens** | list, get, create shop URL, create API token, revoke |
| **Transactions** | list, get, create, update |
| **Payment Methods** | list, get, update |
| **Utilities** | list licensing models, list license types |
| **Audit Prompts** | full account, single customer, expiry sweep, cleanup, anomaly detection |
| **Delete Safety** | `force_cascade` option on all delete tools |
| **Redaction** | secrets (`apiKey`, `licenseeSecret`, `nodeSecret`, …) masked in all responses and logs |

---

## Security defaults

The server is designed to be safe by default:

- **No silent credential fallback** — if `NETLICENSING_API_KEY` is not set and `NETLICENSING_ALLOW_DEMO` is not explicitly enabled, the server refuses to start (stdio) or returns `503` (HTTP) rather than silently using demo credentials.
- **Redaction layer** — every tool response passes through a redaction filter. Sensitive fields (`apiKey`, `licenseeSecret`, `nodeSecret`, `password`, `secret`) are masked to a partial form (e.g. `s3c****ecret`). The set is extendable via `MCP_REDACT_FIELDS`.
- **One-time credentials** — `create_api_token` and `create_shop_token` tag their response with `"shown_once": true` so clients know the credential will not be visible in full again. Subsequent `get_token` / `list_tokens` calls return masked values.
- **Delete confirmation** — all destructive operations require a two-step confirmation token flow; nothing is silently cascaded.
 
---
 
## Quick Start
 
### Option A — uvx (no install required)
 
```bash
NETLICENSING_API_KEY=your_key uvx netlicensing-mcp
```
 
### Option B — pip
 
```bash
pip install netlicensing-mcp
NETLICENSING_API_KEY=your_key netlicensing-mcp
```
 
### Option C — Docker

#### stdio (default) — for Claude Desktop / VS Code
```bash
docker run -i --rm \
  -e NETLICENSING_API_KEY=your_key \
  ghcr.io/labs64/netlicensing-mcp:latest
```

#### HTTP mode — for remote/shared deployments
```bash
docker run -d -p 8000:8000 \
  -e NETLICENSING_API_KEY=your_key \
  ghcr.io/labs64/netlicensing-mcp:latest http
```

#### Verbose logging (any mode)
```bash
# CLI flag
docker run -i --rm \
  -e NETLICENSING_API_KEY=your_key \
  ghcr.io/labs64/netlicensing-mcp:latest -v

# Or via env var
docker run -i --rm \
  -e NETLICENSING_API_KEY=your_key \
  -e MCP_VERBOSE=true \
  ghcr.io/labs64/netlicensing-mcp:latest
```

#### Demo / sandbox mode (no API key)
```bash
docker run -i --rm \
  -e NETLICENSING_ALLOW_DEMO=true \
  ghcr.io/labs64/netlicensing-mcp:latest
```

> **No API key?** Set `NETLICENSING_ALLOW_DEMO=true` to run against NetLicensing's built-in
> sandbox with demo credentials — no account required.
> The server will tag every response with `"demo_mode": true` and emit a periodic warning
> so it is always clear you are not using a real account.

---
 
## Configuration
 
### Environment Variables
 
| Variable | Required | Default | Description |
|---|---|---|---|
| `NETLICENSING_API_KEY` | **Yes*** | — | NetLicensing API key. Required unless `NETLICENSING_ALLOW_DEMO=true` is set. |
| `NETLICENSING_ALLOW_DEMO` | No | `false` | Set to `true` to explicitly opt in to sandbox demo mode when no API key is configured. Every tool response is tagged with `"demo_mode": true` and a warning is logged every 60 seconds. **Never set this in production.** |
| `NETLICENSING_BASE_URL` | No | `https://go.netlicensing.io/core/v2/rest` | Override the NetLicensing REST API base URL (e.g. for on-prem deployments). |
| `MCP_TRANSPORT` | No | `stdio` | Transport mode: `stdio` (default) or `http`. Can also be passed as a CLI argument. |
| `MCP_HOST` | No | `127.0.0.1` | Host address to bind the HTTP server (HTTP mode only). |
| `MCP_PORT` | No | `8000` | Port to bind the HTTP server (HTTP mode only). |
| `MCP_VERBOSE` | No | `false` | Enable verbose debug logging (`true`, `1`, or `yes`). Logs raw API requests/responses **with sensitive fields automatically redacted**. Can also be set via `-v` CLI flag. |
| `MCP_REDACT_FIELDS` | No | — | Comma-separated list of additional field names to redact from all tool responses and log output (e.g. `MCP_REDACT_FIELDS=ssn,phone`). Extends the built-in default set: `apiKey`, `licenseeSecret`, `nodeSecret`, `password`, `secret`. |

> **\* `NETLICENSING_API_KEY` and demo mode:** If neither `NETLICENSING_API_KEY` nor `NETLICENSING_ALLOW_DEMO=true` is set, the server will **refuse to start** (stdio mode) or return `503 Service Unavailable` for all tool calls (HTTP mode). This prevents accidental use of demo credentials in production.

> **Note on HTTP deployments (e.g. AWS):** When running in HTTP mode over a network, you can skip setting `NETLICENSING_API_KEY` on the server. The MCP server will automatically extract the key per-request if the connecting client provides it via the `X-NetLicensing-API-Key` HTTP header, `Authorization: Bearer <key>` header. Query-parameter keys are not supported, because URLs are logged by proxies and load balancers.

---
 
### Claude Desktop
 
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
 
```json
{
  "mcpServers": {
    "netlicensing": {
      "command": "uvx",
      "args": ["netlicensing-mcp"],
      "env": {
        "NETLICENSING_API_KEY": "your_key_here"
      }
    }
  }
}
```
 
Or use the official Docker image:

#### stdio (default) — for Claude Desktop / VS Code
```json
{
  "mcpServers": {
    "netlicensing": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "NETLICENSING_API_KEY=your_key_here",
        "ghcr.io/labs64/netlicensing-mcp:latest"
      ]
    }
  }
}
```

#### HTTP mode — for remote/shared deployments
```json
{
  "mcpServers": {
    "netlicensing": {
      "command": "docker",
      "args": [
        "run", "-d",
        "-p", "8000:8000",
        "-e", "NETLICENSING_API_KEY=your_key_here",
        "ghcr.io/labs64/netlicensing-mcp:latest",
        "http"
      ]
    }
  }
}
```

### VS Code / GitHub Copilot
 
The repo ships a `.vscode/mcp.json` that auto-configures Copilot Agent mode.
Set `NETLICENSING_API_KEY` in your shell environment or a `.env` file, then click
**Start** in the editor banner that appears above `mcp.json`.
 
### JetBrains / IntelliJ IDEA
 
In Copilot Chat → Agent mode → Tools icon → **Add More Tools…** — paste the
same JSON block shown in the Claude Desktop section above.
 
---
 
## Audit Prompt Templates
 
Five built-in prompts accessible in Copilot Agent and Claude Desktop:
 
| Prompt | Purpose |
|---|---|
| `audit_full` | End-to-end account audit for a product |
| `audit_customer` | Deep-dive on a single licensee |
| `audit_expiry` | Find licenses expiring within N days and generate renewal URLs |
| `audit_cleanup` | Identify inactive / orphaned licenses for cleanup |
| `audit_anomaly` | Detect unusual usage patterns across all customers |
 
---
 
## Troubleshooting
 
**Check MCP server logs**
 
```bash
# macOS / Claude Desktop
tail -f ~/Library/Logs/Claude/mcp-server-netlicensing.log
 
# Windows
Get-Content "$env:APPDATA\Claude\Logs\mcp-server-netlicensing.log" -Wait
```
 
**Run the MCP Inspector** (browser UI at `http://localhost:5173`)
 
```bash
mcp dev src/netlicensing_mcp/server.py
```
 
**Common issues**
 
| Symptom | Likely cause | Fix |
|---|---|---|
| `401 Unauthorized` responses | Invalid or expired API key | Regenerate your key at [ui.netlicensing.io](https://ui.netlicensing.io) |
| Server not listed in Claude | Config file JSON syntax error | Validate with `python -m json.tool claude_desktop_config.json` |
| `uvx: command not found` | `uv` not installed | `pip install uv` or see [docs.astral.sh/uv](https://docs.astral.sh/uv) |
| Server exits immediately / `503` on all calls | `NETLICENSING_API_KEY` not set and demo mode not enabled | Set `NETLICENSING_API_KEY`, or set `NETLICENSING_ALLOW_DEMO=true` for sandbox testing |
| Demo data instead of live data | `NETLICENSING_API_KEY` not set; `NETLICENSING_ALLOW_DEMO=true` active | Ensure `NETLICENSING_API_KEY` is exported in the shell that starts the client and unset `NETLICENSING_ALLOW_DEMO` |
 
---
 
## Development
 
```bash
git clone https://github.com/Labs64/NetLicensing-MCP
cd NetLicensing-MCP

# Create a virtual environment
python -m venv .venv
source .venv/bin/activate       # Windows: .venv\Scripts\activate

# ... and install dependencies
pip install -e ".[dev]"
pip install hatch hatch-vcs

# Add your API key to a .env file (or export it in your shell)
cp .env.example .env
 
# Run the MCP Inspector
mcp dev src/netlicensing_mcp/server.py
 
# Run tests
pytest tests/ -v

# Clean previous builds
rm -rf dist/

# Build a wheel for local testing
hatch build --target wheel

# Build the Docker image locally
docker build -t ghcr.io/labs64/netlicensing-mcp:latest .
```

### HTTP mode (for remote / shared deployments)

```bash
python -m netlicensing_mcp.server http
# Server listens on MCP_HOST:MCP_PORT (default: 127.0.0.1:8000)
```

Use `ngrok` or a reverse proxy to expose the HTTP endpoint to remote MCP clients:

```bash
ngrok http 8000
# Then point your client at the generated HTTPS URL
```

### Cloud Deployment (AWS)

Deploy the MCP server to AWS for a **public HTTPS endpoint** that remote AI agents can connect to:

| Option | Best for | Scale-to-zero | Setup |
|---|---|---|---|
| **ECS Fargate** | Production, consistent traffic | No | ALB + Fargate |
| **App Runner** | Low-traffic, development | ✅ Yes | Auto-provisioned HTTPS |

#### Quick deploy with the helper script

```bash
cd deploy/aws

# Option A — ECS Fargate
# Deploy (with optional HTTPS via ACM certificate)
./deploy.sh fargate \
    --certificate-arn arn:aws:acm:us-east-1:123456789:certificate/your-cert-id

# Option B — App Runner (mirror image to ECR first)
./deploy.sh mirror --ecr-repo 123456789.dkr.ecr.us-east-1.amazonaws.com/netlicensing-mcp
./deploy.sh apprunner \
    --ecr-image 123456789.dkr.ecr.us-east-1.amazonaws.com/netlicensing-mcp:latest
```

#### Connect MCP clients to the public URL

To use a shared, remote deployment, do not bake the `NETLICENSING_API_KEY` into the remote server settings. Instead, pass the API key from the client side in an HTTP header.

For example, in your MCP client configuration:

```json
{
  "mcpServers": {
    "netlicensing": {
      "url": "https://your-endpoint.us-east-1.elb.amazonaws.com/mcp",
      "headers": { "X-NetLicensing-API-Key": "YOUR_API_KEY" }
    }
  }
}
```

You can alternatively send `Authorization: Bearer YOUR_API_KEY`.

📖 Full instructions, architecture diagrams, and cost estimates: **[deploy/aws/README.md](deploy/aws/README.md)**

---
 
## Contributing
 
Contributions are welcome! Please open an issue or pull request on [GitHub](https://github.com/Labs64/NetLicensing-MCP).
 
For significant changes, open an issue first to discuss the approach.

---
 
## License
 
Apache 2.0 — see [LICENSE](LICENSE)

---

[![NetLicensing-MCP MCP server](https://glama.ai/mcp/servers/Labs64/NetLicensing-MCP/badges/card.svg)](https://glama.ai/mcp/servers/Labs64/NetLicensing-MCP)
