Metadata-Version: 2.4
Name: immersive-cre-mcp
Version: 0.3.0
Summary: MCP server for Immersive Labs Cyber Ranges
Keywords: mcp,model-context-protocol,immersive-labs,cyber-range,llm
Author: kevthehermit
Author-email: kevthehermit <kevin@immersivelabs.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Typing :: Typed
Requires-Dist: httpx>=0.28.1
Requires-Dist: mcp[cli]>=2.3
Requires-Dist: pydantic-settings>=2.15.0
Requires-Python: >=3.12
Project-URL: Homepage, https://github.com/Immersive-Labs-Public/immersive-cre-mcp
Project-URL: Repository, https://github.com/Immersive-Labs-Public/immersive-cre-mcp
Project-URL: Issues, https://github.com/Immersive-Labs-Public/immersive-cre-mcp/issues
Description-Content-Type: text/markdown

# immersive-cre-mcp

[![CI](https://github.com/Immersive-Labs-Public/immersive-cre-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/Immersive-Labs-Public/immersive-cre-mcp/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/Immersive-Labs-Public/immersive-cre-mcp/blob/main/LICENSE)

MCP server for **Immersive Labs Cyber Ranges** (CRE), built for **range authors**.
It covers the whole dashboard: scenarios, flags (with answers), briefing and walkthrough markdown,
documents, templates, labs, systems, networking, snapshots, VPN, events and users.

> This uses the same public API the CRE web dashboard calls: any registered account can reach
> it by signing in. It isn't formally documented or versioned (see [docs/API.md](https://github.com/Immersive-Labs-Public/immersive-cre-mcp/blob/main/docs/API.md) for
> the endpoints as observed), so a dashboard release can change it.

# Installation

Requires Python 3.12+. Run it without installing via `uvx`, or install it with `pipx` or `pip`:

```bash
uvx immersive-cre-mcp            # run on demand, nothing to install
pipx install immersive-cre-mcp   # or install the command globally
pip install immersive-cre-mcp    # or into an existing environment
```

### From git

To use a version that isn't on PyPI, install straight from the repository. Add `@<ref>` to pin
a tag, branch or commit; leave it off to get the latest `main`.

```bash
uvx --from git+https://github.com/Immersive-Labs-Public/immersive-cre-mcp@v0.3.0 immersive-cre-mcp
pipx install git+https://github.com/Immersive-Labs-Public/immersive-cre-mcp@v0.3.0
pip install "immersive-cre-mcp @ git+https://github.com/Immersive-Labs-Public/immersive-cre-mcp@<commit-sha>"
```

With `uvx`, pass the same `--from` in your client config (see [Add to a client](#add-to-a-client)):

```json
"command": "uvx",
"args": ["--from", "git+https://github.com/Immersive-Labs-Public/immersive-cre-mcp@v0.3.0", "immersive-cre-mcp"]
```

`uvx` caches the build, so a pinned tag or commit is fetched only once. For a branch, add
`--refresh` to the `uvx` arguments to pick up new commits.

## Configuration

Settings are read from environment variables, so set them in your MCP client's config
(or in a `.env` file in the server's working directory).

| Variable | Default | |
|---|---|---|
| `IMMERSIVE_CRE_USERNAME` / `IMMERSIVE_CRE_PASSWORD` | – | Immersive Labs platform login, or a standalone Cyber Ranges account (no API tokens exist) |
| `IMMERSIVE_CRE_AUTH` | `auto` | `platform` (Immersive Labs SSO), `cognito` (standalone CRE account, e.g. support) or `auto` (try platform, then standalone) |
| `IMMERSIVE_CRE_REGION` | `eu` | `eu` (immersivelabs.online) or `us` (us.immersivelabs.com); picks every host below |
| `IMMERSIVE_CRE_BASE_URL` | region's (`https://api4.eu.snaplabs.io` / `https://api4.snaplabs.io`) | Ranges API host |
| `IMMERSIVE_CRE_DASHBOARD_URL` | region's (`https://dashboard.immersivelabs.eu.snaplabs.io` / `https://dashboard.immersivelabs.snaplabs.io`) | Used for the OAuth state/referrer |
| `IMMERSIVE_CRE_IL_URL` / `IMMERSIVE_CRE_IL_API_URL` / `IMMERSIVE_CRE_HYDRA_URL` | region's | Immersive Labs sign-in hosts |
| `IMMERSIVE_CRE_HYDRA_CLIENT_ID` | region's | Fallback only - the OAuth URL normally comes from the ranges API |
| `IMMERSIVE_CRE_COGNITO_API_URL` | region's (`https://api.eu.snaplabs.io` / `https://api2.snaplabs.io`) | API host for standalone accounts |
| `IMMERSIVE_CRE_COGNITO_USER_POOL_ID` / `IMMERSIVE_CRE_COGNITO_CLIENT_ID` | region's | Cognito pool the standalone CRE dashboard signs in to |
| `IMMERSIVE_CRE_TOKEN_CACHE` | `~/.cache/immersive-cre-mcp/token` | Session cache (mode 0600; `-us` suffix for the US region), tied to the username; empty = memory only |
| `IMMERSIVE_CRE_READ_ONLY` | `false` | Only expose read tools |
| `IMMERSIVE_CRE_ENABLE_RAW` | `true` | Expose `raw_request` for endpoints without a tool |


## Add to a client

**Claude Code:**

```bash
claude mcp add immersive-cre \
  -e IMMERSIVE_CRE_USERNAME=you@example.com \
  -e IMMERSIVE_CRE_PASSWORD='...' \
  -- uvx immersive-cre-mcp
```

**Claude Desktop, Cursor, VS Code or any other MCP client** (JSON config):

```json
{
  "mcpServers": {
    "immersive-cre": {
      "command": "uvx",
      "args": ["immersive-cre-mcp"],
      "env": {
        "IMMERSIVE_CRE_USERNAME": "you@example.com",
        "IMMERSIVE_CRE_PASSWORD": "..."
      }
    }
  }
}
```

If you installed with `pipx` or `pip`, use `"command": "immersive-cre-mcp"` with no `args` instead.

Add `"IMMERSIVE_CRE_READ_ONLY": "true"` to `env` to explore safely without any write or delete tools.

The server also runs over HTTP with `immersive-cre-mcp --transport streamable-http`.

## Example usage

Once connected, ask your assistant in plain language. For example:

- *"List my scenarios and show the flags for the one called Ransomware Response."*
- *"Create a scenario called Phishing Triage with a short briefing, and add three flags:
  the sender's IP, the malicious domain, and the payload's SHA256."*
- *"Rewrite the student walkthrough for scenario 1234 to fix the typos and make step 3 clearer."*
- *"Reorder the flags in my Web App scenario so the easy ones come first, and add a hint to each."*
- *"In my AD Lab, add a DMZ subnet on 10.10.5.0/24 that accepts only TCP 80 and 443 from the
  attacker subnet, then add an Ubuntu web server on it at 10.10.5.10."*
- *"Give the web server a second interface on the internal subnet at 10.10.1.50 so it can reach
  the domain controller."*
- *"Lock down the internal subnet: allow RDP and SMB from the user subnet only and drop
  everything else inbound."*
- *"Set the lab's DHCP domain to corp.local with 10.10.1.10 as the DNS server, and push the same
  DNS settings to VPN users."*
- *"Add the Juice Shop on 10.10.3.59:3000 as an app participants can open from the lab page."*
- *"Which labs are running right now, and when do they shut down?"*
- *"Upload `network-diagram.pdf` as a document on the Phishing Triage scenario."*
- *"Show the scoreboard for event 42."*

## Tools (88)

| Area | Tools |
|---|---|
| Scenarios | `list_scenarios` `get_scenario` `create_scenario` `update_scenario` `publish_scenario` `delete_scenario` `set_scenario_image` `set_scenario_suggested_labs` `search_immersive_labs` |
| Flags (scenario or event) | `list_flags` `add_flag` `update_flag` `delete_flag` `reorder_flags` `replace_flags` |
| Markdown & documents | `get_markdown` `set_markdown` `delete_admin_markdown` `list_documents` `upload_document` `download_document` `delete_document` |
| Templates | `list_templates` `get_template` `create_template_from_lab` `edit_template` `share_template` `revoke_template_share` `delete_template` |
| Labs | `list_labs` `get_lab` `launch_lab` `launch_blank_lab` `launch_introductory_range` `wait_for_lab` `power_lab` `update_lab_settings` `delete_lab` `checkin` `get_lab_users` `manage_lab_users` `cache_lab_credentials` `download_lab_ssh_key` `get_launch_script_output` |
| Snapshots & VPN | `create_snapshot` `revert_snapshot` `delete_snapshot` `create_vpn` `download_vpn` `revoke_vpn` |
| Systems | `add_system` `update_system` `delete_system` `manage_system_interface` `get_system_console` `set_system_credentials` `create_image_from_system` `list_images` `get_image_info` `get_instance_pricing` `validate_ami` `get_playbook` `run_playbook` `get_playbook_jobs` |
| Network & apps | `manage_subnet` `update_dhcp` `set_lab_app` `connect_lab_app` |
| Events | `list_events` `get_event` `list_event_teams` `create_event` `update_event` `set_event_image` `delete_event` `manage_event_team` `manage_event_participant` `launch_event_lab` `get_event_scores` `submit_flag` |
| Account & users | `get_account` `list_users` `get_user` `invite_users` `update_user` `remove_users` `reinvite_user` `raw_request` |

Tools are annotated read / write / destructive, so clients can prompt before destructive calls.

Authoring notes:
- **Flags**: the API only saves the whole list. The flag tools read, modify and write it back, and
  generate `FlagId`s for new flags. Answers, hints and MITRE tags are always returned.
- **Markdown**: `set_markdown` uploads to S3, then waits (up to 30s) for the backend to register
  the new version, so a read straight after a write is current.
- **Costs**: launching or powering labs spends AWS money and counts against the account's lab limit.

# Development

Requires [uv](https://docs.astral.sh/uv/).

```bash
git clone https://github.com/Immersive-Labs-Public/immersive-cre-mcp.git
cd immersive-cre-mcp
uv sync
cp .env.example .env   # then fill in credentials
```

A `.env` in the project root is picked up whatever the working directory, so a client can run
your checkout directly:

```bash
claude mcp add immersive-cre -- uv run --project /path/to/immersive-cre-mcp immersive-cre-mcp
```

```json
{"mcpServers": {"immersive-cre": {"command": "uv", "args": ["run", "--project", "/path/to/immersive-cre-mcp", "immersive-cre-mcp"]}}}
```

To try tools interactively, use the MCP Inspector: `npx @modelcontextprotocol/inspector uv run immersive-cre-mcp`.
Set `LOG_LEVEL=DEBUG` for more logging.

## Checks

CI runs these on every push and pull request; run them locally before opening a PR:

```bash
uv run ruff check .   # lint
uv run mypy           # type check
uv run pytest         # unit tests (add --cov for coverage)
```

The unit tests mock all HTTP, so they need no credentials and never reach the live API. They
ignore your `.env`, and they don't touch the token cache.

## Live API test status

These were exercised against the test account over MCP stdio, using a throwaway scenario that was
deleted afterwards: all read tools, scenario create/update/delete, every flag operation,
student/admin markdown write and read, and document upload/list/download/delete.

These are wired to the payloads in the dashboard bundle but have **not been run**, because they
launch, alter or delete real labs and users: lab launch/power/delete, snapshots, VPN, systems,
subnets, apps, events (write), user management, template create/share/delete, publishing, and images.

## Layout

```
src/immersive_cre_mcp/
  client.py      auth (IL → Hydra OAuth → token cookie, or Cognito), GET/POST transport, S3 upload/download
  cognito.py     Cognito SRP sign-in for standalone CRE accounts
  config.py      settings (environment / .env)
  app.py         MCPServer instance, tool() decorator, shared helpers
  server.py      entry point (immersive-cre-mcp)
  tools/         one module per area (scenarios, flags, content, templates, labs, systems, events, account)
docs/API.md      endpoint reference (as observed from the dashboard)
tests/           unit tests (HTTP mocked with respx)
```

## License

[MIT](https://github.com/Immersive-Labs-Public/immersive-cre-mcp/blob/main/LICENSE)
