# Tenable MSSP Portal MCP Server

> Draft · awaiting review.

> MCP server that runs Tenable queries and hosted Hexa AI MCP tools across the child containers of a Tenable MSSP Portal.

- Badge: `reach 3 · not run yet`
- Type: MCP server; tier: not run yet
- Tasks: Vulnerability prioritization; mission: Defensive; works with: Any MCP client, Claude Code, Codex, Gemini CLI
- Source: https://github.com/andrewspearson/tenable-mcp-mssp, pinned to `eeb26b5` (v1.0.1), licence MIT
- Last checked: 2026-10-21; next check: 2027-01-19; method v0.1, reach-v0.1

## At a glance

- **What it is:** An MCP server that orchestrates Tenable MSSP child container workflows, used to make bulk queries and take bulk actions across child containers. An MCP server is a program that gives your AI client extra tools; the client's model decides when to call them.
- **Made for:** Lets one MCP client use Tenable Hexa AI MCP Server tools across the child containers of an MSSP Portal through a scoped orchestration layer. +2 more
- **Runs:** On your machine, started by your AI client.
- **Sends data to:** Tenable MSSP Portal API (always), Tenable hosted MCP server (by default), Tenable Vulnerability Management exports (by default). Other connections not ruled out: read in the documentation and the cited code, not searched in full.
- **Can change things:** Changes, runs commands, according to the capabilities read.
- **Needs:** Tenable MSSP Portal API keys with Administrator privileges · Child containers licensed with hexa for the Hexa AI MCP Server tools · Child containers licensed with vm for the bulk_vm_cve_query tool · +3 more

Profile read at commit `eeb26b5` on 2026-10-25; every fact cites a file and line at that commit.

## What it does

An MCP server that orchestrates Tenable MSSP child container workflows, used to make bulk queries and take bulk actions across child containers. (README.md#L8)

Made for (the author says):

- Lets one MCP client use Tenable Hexa AI MCP Server tools across the child containers of an MSSP Portal through a scoped orchestration layer. (README.md#L14)
- Queries one or more CVEs across eligible in-scope child containers and produces a CSV report of the findings. (README.md#L15)
- Lists all child containers of the MSSP Portal with their license information. (README.md#L18)

Documented uses:

- Query CVEs across the child containers connected to an MSSP Portal and compile the findings into a CSV report. [Vulnerability prioritization] (README.md#L103)
- Apply a tested sequence of Hexa AI MCP tool calls to many hexa-licensed child containers in one batch. (README.md#L134)
- Experiment with one official Tenable MCP tool on one child container licensed for hexa. (AGENTS.md#L16)
- Review all MSSP child accounts as returned by Tenable, including their license data. (README.md#L129)

## What it can do

| Group | What it covers | Effect | On by default |
|---|---|---|---|
| list_mssp_child_accounts | Lists the raw Tenable MSSP child account objects, including license data. (tenable_mcp_mssp/server.py#L51-60) | reads | yes |
| list_available_tenable_mcp_tools | Discovers the Tenable Hexa AI MCP Server tool catalog for one child container licensed for hexa. (README.md#L130) | reads | yes |
| get_child_container_scope | Shows the configured child container allowlist scope for action tools. (README.md#L131) | reads | yes |
| run_tenable_mcp_tool_for_child | Runs one Tenable Hexa AI MCP Server tool on one child container licensed for hexa. (README.md#L132) | reads, changes | yes |
| run_tenable_mcp_recipe_for_child | Validates a known sequence of Tenable Hexa AI MCP Server tool calls on one child container licensed for hexa. (README.md#L133) | reads, changes | yes |
| run_tenable_mcp_recipe_across_child_containers | Runs a known official Tenable MCP recipe across a list of hexa-licensed child containers. (tenable_mcp_mssp/server.py#L120-125) | reads, changes | yes |
| bulk_vm_cve_query | Runs the bulk VM CVE export by starting the module tenable_mcp_mssp.bulk_vm_cve_query_worker as a Python subprocess with a raw output file path. (tenable_mcp_mssp/bulk_vm_cve_query.py#L367-372) | reads, runs commands | yes |
| get_bulk_vm_cve_query_status / _result | Checks the status of a server-managed bulk_vm_cve_query run and reads its final summary and artifact paths. (README.md#L136-137) | reads | yes |

## How it runs

The server creates a FastMCP client that reaches Tenable's hosted MCP server over a streamable HTTP transport and sends the access and secret keys in an API keys header. (tenable_mcp_mssp/tenable_mcp_client.py#L30-39)

- Starts: On your machine, started by your AI client. Codex, Claude, Gemini CLI or another MCP client attaches to tenable-mcp-mssp as a STDIO server. (README.md#L87)
- Your AI client: **MCP client registration**: Client entry added with the client's mcp add command that launches the venv Python with -m tenable_mcp_mssp.server. (README.md#L91)
- Your machine: **tenable_mcp_mssp.server**: Server entry point main() that configures logging, loads the child container scope and runs the FastMCP server. (tenable_mcp_mssp/server.py#L191-197)
- Your machine: **bulk_vm_cve_query_worker**: Subprocess worker that runs the VM CVE export for one child container. (tenable_mcp_mssp/bulk_vm_cve_query_worker.py#L1)
- Your machine: **.env file**: Optional .env file that can supply the parent MSSP Portal credentials instead of real environment variables. (AGENTS.md#L7)
- Outside your machine: **Tenable MSSP Portal and child container APIs**: Tenable MSSP Portal API endpoint mssp/accounts, which returns the child accounts. (tenable_mcp_mssp/mssp_accounts.py#L13)
- Outside your machine: **Tenable Hexa AI MCP Server**: Tenable's hosted MCP server at https://cloud.tenable.com/mcp/. (tenable_mcp_mssp/tenable_mcp_client.py#L13)
- Sends data to Tenable MSSP Portal API (vendor API, always): Requests temporary API keys for a child container from the MSSP endpoint mssp/accounts/mssp-child-keys. (tenable_mcp_mssp/child_api_keys.py#L13)
- Sends data to Tenable hosted MCP server (vendor API, by default): Connects to Tenable's hosted MCP server over streamable HTTP and sends the access and secret keys in an API keys header. (tenable_mcp_mssp/tenable_mcp_client.py#L33-38)
- Sends data to Tenable Vulnerability Management exports (vendor API, by default): The bulk worker requests a vulnerability export filtered by the given CVE IDs and iterates over the returned findings. (tenable_mcp_mssp/bulk_vm_cve_query_worker.py#L64)

## What you need

- Credentials: Tenable MSSP Portal API keys with Administrator privileges. (README.md#L26)
- Account: Child containers licensed with hexa for the Hexa AI MCP Server tools. (README.md#L27)
- Account: Child containers licensed with vm for the bulk_vm_cve_query tool. (README.md#L28)
- Runtime: Python 3.14 or newer. (README.md#L29)
- Other tools: uv or pip for the local installation. (README.md#L30)
- Setting: The parent keys must be set as TENABLE_MSSP_PORTAL_ACCESS_KEY and TENABLE_MSSP_PORTAL_SECRET_KEY in the environment or the .env file. (tenable_mcp_mssp/config.py#L14-15)
- Installer: The documented download is a git clone of the repository's default branch, without a tag or commit in the command. (README.md#L37)
- Installer: Copies .env.example to .env inside the clone and sets it to mode 600 before the portal keys are entered. (README.md#L68-72)
- Installer: Registers the server with claude mcp add, pointing at the clone's .venv Python and the module tenable_mcp_mssp.server. (README.md#L93-95)

## Limits and risks

- Each tool that acts on a child container generates temporary API keys for that child through the MSSP Portal when no unexpired key is cached, and holds them in process memory. (tenable_mcp_mssp/child_credentials.py#L180-188)
- call_tenable_mcp_tool forwards the caller's tool name and arguments to Tenable's hosted MCP server through call_tool. (tenable_mcp_mssp/tenable_mcp_client.py#L80-82)
- The rule to run bulk_vm_cve_query only on explicit request is written in the tool description; the handler starts the export on any call. (tenable_mcp_mssp/server.py#L151-160)
- The child container allowlist is optional; when TENABLE_MCP_MSSP_CHILD_CONTAINER_SCOPE_FILE is unset or blank, all otherwise eligible child containers are allowed. (README.md#L109)
- bulk_vm_cve_query builds its child list from every child account the MSSP account lister returns and counts all of them as queued. (tenable_mcp_mssp/bulk_vm_cve_query.py#L246-252)
- Bulk runs write raw JSONL findings per child and an aggregate CSV under results/bulk-vm-cve-query/<run-id>/; run state in memory is lost on restart, the files stay on disk. (AGENTS.md#L25)
- The server reads .env from its current working directory, which is the directory the MCP client starts it in. (tenable_mcp_mssp/config.py#L13)
- Action tools block expired containers, malformed expiration data, missing child accounts and licenseType ao containers, also when they are on the allowlist. (README.md#L119)
- Multi-child fan-out runs at a fixed concurrency of 10 child containers, and each child run times out after 600 seconds. (AGENTS.md#L23)
- The child container allowlist is loaded once and cached with lru_cache for the life of the server process. (tenable_mcp_mssp/child_container_scope.py#L54-55)
- When the configured scope file cannot be read, scope loading stops with a ConfigurationError. (tenable_mcp_mssp/child_container_scope.py#L69-75)
- The author's design rule is that generated child keys stay in memory only and are never logged, returned, written or persisted. (AGENTS.md#L7)

## Rights in plain language

- Declared: files 1 (reads outside the project), network 1 (talks only to declared hosts), secrets 2 (reads broad tokens or the environment), persistence 3 (adds autostart, users or keys).
- Code: reach 3 (privileged): secrets 2 (reads broad tokens or the environment), persistence 3 (adds autostart, users or keys).
- Lab: not run yet.

Why three columns? Declarations are often incomplete and scanners can be bypassed, so we run each tool once and compare.

## Privilege Reach

Reach level 3 (privileged).

| Right | Declared | Code | Lab |
|---|---|---|---|
| Files: where does it read and write? | 1 reads outside the project | 1 reads outside the project | not run yet |
| Network: whom does it talk to? | 1 talks only to declared hosts | 1 talks only to declared hosts | not run yet |
| Execution: what does it run? | not declared | 1 runs only declared programs | not run yet |
| Secrets: which credentials does it touch? | 2 reads broad tokens or the environment | 2 reads broad tokens or the environment | not run yet |
| Persistence: what survives the run? | 3 adds autostart, users or keys | 3 adds autostart, users or keys | not run yet |
| Approval: does it ask before acting? | not declared | 0 asks each time | not run yet |

0 contained · 1 scoped · 2 open · 3 privileged · ? no evidence · 0 never means safe

## Install

### Upstream

Quoted from `README.md#L37-95` at the pinned commit (not a command to copy): `git clone https://github.com/andrewspearson/tenable-mcp-mssp.git
cd tenable-mcp-mssp
uv venv
uv pip install .
cp .env.example .env
chmod 600 .env
claude mcp add tenable-mcp-mssp -- /path/to/tenable-mcp-mssp/.venv/bin/python -m tenable_mcp_mssp.server`


### Run it with least privilege

- note: `derived from the code, not tested in the lab; limit action tools with the child-container allowlist file, pass the portal keys through the environment rather than a .env file, and call bulk_vm_cve_query only on explicit request`

- derived, not tested: proposed from the code analysis

## Lab runs

Not run yet.

## Questions and answers

**Why compare declared, code and lab?**

Declarations are often incomplete and scanners can be bypassed, so we run each tool once and compare.

**What rights does Tenable MSSP Portal MCP Server declare?**

files 1 (reads outside the project), network 1 (talks only to declared hosts), secrets 2 (reads broad tokens or the environment), persistence 3 (adds autostart, users or keys).

**What does its code suggest?**

reach 3 (privileged): secrets 2 (reads broad tokens or the environment), persistence 3 (adds autostart, users or keys).

**What did it use when it ran in the lab?**

not run yet.

**Was it tried, and when?**

Not yet (tier listed).

**What changed since the last check?**

Upstream last pushed 2026-06-23; 0 release(s) since the pinned version.

**How do I run it with least privilege?**

Derived, not tested: note: derived from the code, not tested in the lab; limit action tools with the child-container allowlist file, pass the portal keys through the environment rather than a .env file, and call bulk_vm_cve_query only on explicit request

Method: https://readbeforerun.ai/method/
