Skip to main content
MCP Servers / Tenable OT Security MCP Server

Tenable OT Security MCP Server

Contributed

Tenable OT Security asset, vulnerability, event and policy tools, with an opt-in dry-run-by-default write layer.

Authoraqamahn
Transportboth
Runtimepython
LicenseApache-2.0
AddedAug 1, 2026

Compatible Clients

Claude DesktopClaude Code

Integrations

Tenable

Tools (59)

  1. tenable_ot_status

    Check Tenable OT connectivity

  2. query_assets

    Query OT assets

  3. get_asset

    Get one OT asset

  4. get_asset_vulnerabilities

    Get vulnerabilities for one asset

  5. list_custom_fields

    List configured custom fields

  6. get_manual_asset_upload_status

    Get manual asset-upload processing status

  7. query_attack_pathways

    Query attack-pathway data (relational, not computed)

  8. query_vulnerability_clusters

    Query vulnerability clusters (relational join, not computed)

  9. query_temporal_patterns

    Query temporal patterns (event sequence, not motif analysis)

  10. get_asset_intelligence

    Get asset intelligence bundle (joined data, not narrative)

  11. query_events

    Query OT events

  12. get_event

    Get one OT event

  13. export_assets

    Bulk export assets

  14. export_plugin_definitions

    Bulk export plugin definitions

  15. export_findings

    Bulk export findings

  16. query_plugin_definitions

    Query plugin (vulnerability) definitions

  17. get_plugin_definition

    Get one plugin definition

  18. list_detection_policies

    List detection policies

  19. get_policy

    Get one policy's full configuration

  20. query_policy_findings

    Query policy findings

  21. get_schema_enums

    Introspect the Tenable OT GraphQL schema

  22. list_sensors

    List sensors

  23. summarize_environment

    Summarize the OT environment

  24. list_segments_and_zones

    List network segments and zones

  25. get_communication_paths

    Get communication paths for an asset

  26. query_vulnerabilities

    Query OT vulnerabilities

  27. get_vulnerability

    Get one vulnerability

  28. list_asset_groups

    List asset groups (active)

  29. list_archived_asset_groups

    List archived asset groups

  30. get_asset_group

    Get an asset group by id

  31. list_email_groups

    List email groups

  32. get_email_group

    Get an email group by id

  33. find_email_groups_using_smtp_server

    Find email groups that route through a given SMTP server

  34. list_schedule_groups

    List schedule groups

  35. list_archived_schedule_groups

    List archived schedule groups

  36. get_schedule_group

    Get a schedule group by id

  37. list_tag_groups

    List tag groups

  38. get_tag_group

    Get a tag group by id

  39. list_eligible_tags

    Discover tags eligible for a tag group

  40. list_rule_groups

    List rule groups

  41. list_archived_rule_groups

    List archived rule groups

  42. get_rule_group

    Get a rule group by id

  43. list_port_groups

    List port groups

  44. list_archived_port_groups

    List archived port groups

  45. get_port_group

    Get a port group by id

  46. list_protocol_groups

    List protocol groups

  47. list_archived_protocol_groups

    List archived protocol groups

  48. get_protocol_group

    Get a protocol group by id

  49. list_user_groups

    List user groups (ICP-level)

  50. list_archived_user_groups

    List archived user groups (ICP-level)

  51. get_user_group

    Get a user group by id (ICP-level)

  52. list_em_user_groups

    List user groups (Enterprise Manager level)

  53. list_em_archived_user_groups

    List archived user groups (Enterprise Manager level)

  54. get_em_user_group

    Get a user group by id (Enterprise Manager level)

  55. list_active_scans

    List active scans

  56. get_active_scan

    Get one active scan

  57. get_active_scan_executions

    Get past executions of an active scan

  58. list_network_config

    Read what the appliance is configured to monitor

  59. list_policy_relationships

    Check what references an object before changing it

Tags

mcp-serverot-securityicsscadaasset-inventoryvulnerability-managementaudit-logging

An MCP server that connects any MCP client — Claude Desktop, Claude Code, or another — to a Tenable OT Security deployment, exposing OT/ICS asset inventory, vulnerabilities, events, detection policies and policy findings as read tools, plus an opt-in write layer for asset edits, group and policy management, scan definitions and finding resolution.

Because this server talks to industrial control systems, its safety model is structural rather than advisory: writes are invisible until explicitly enabled, every write previews before it acts, destructive operations need a second confirm flag, and every write attempt is recorded to an append-only audit log.

Not an official Tenable product. Copyright (c) 2026 Tenable, Inc., released under Apache 2.0, but shipped with no SLA, no warranty and no support commitment, and not covered by Tenable’s product security or vulnerability-disclosure processes.

What it does

59 read tools, always available. Asset inventory with identity, IPs/MACs, Purdue level, segment and backplane membership and aggregate risk; fleet-wide and per-asset vulnerability search with CVE, CVSS and exploit/KEV flags; OT events; detection policies and their per-asset findings; the plugin (vulnerability) definition catalog; and bulk exports of assets, findings and plugin definitions via pyTenable.

Beyond raw inventory it covers the environment’s shape and its dependencies: network segments and zones as observed, per-asset communication paths, sensor inventory, and list_network_config — what the appliance is configured to watch, which flags disabled subnets as monitoring blind spots and is the usual answer to “why is this asset missing”. list_policy_relationships answers “what breaks if I change this?” before a write lands, which matters because Tenable OT’s policy mutations are full replaces, not patches. summarize_environment gives a one-call orientation on an unfamiliar deployment, and get_schema_enums introspects the appliance’s own GraphQL schema.

71 write tools, only when TENABLE_OT_WRITE_TOOLS_ENABLED=1. Asset lifecycle (hide/restore, bulk variants, removal by address, merge, risk recalculation, manual file upload), asset properties and custom-field schema, detection policy enable/disable/archive and full policy editing, finding resolution, group management across asset / email / schedule / tag / rule / port / protocol / user groups, sensor management, and scan definition create/edit.

Nothing in the codebase runs a scan. There is no run, start, or execute mutation anywhere in it — definitions can be written, and enable_active_scan sets whether a definition participates in runs, but only a human starting a scan from the Tenable OT UI ever launches one against live equipment.

How it works

A Python 3.12+ server on the MCP SDK, wrapping Tenable OT’s GraphQL API directly with httpx for everything Tenable doesn’t officially cover, and bridging to pyTenable for the bulk-export surface. Most paginated read tools are declared as data — a ConnectionSpec record naming a query and a field projection — and one registrar turns specs into tools, so the pagination and projection plumbing exists and is tested once rather than being re-implemented per tool. Composite tools that fan out or join across queries stay hand-written. Queries whose availability varies by appliance are marked unconfirmed and return an actionable error envelope naming what to introspect, instead of raising.

The four safety properties are enforced in the architecture, not by convention:

  1. Write tools are absent, not merely refused. Without the opt-in environment variable the write modules are never imported, so no write tool name appears in the MCP tools/list response. A client cannot call — or discover — an operation that wasn’t enabled.
  2. Every write defaults to dry_run=True, returning the exact payload that would be sent without sending it, so the operator approves a concrete preview before anything changes.
  3. Destructive operations require a second explicit flag. dry_run=false alone is insufficient; delete_custom_field, for instance, is rejected without confirm_wipes_values=True.
  4. Every write call is audited — dry-run, live, or failed — as one JSON line recording timestamp, tool, parameters, dry-run flag, outcome and error. The audit writer fails closed: if it cannot record, the call raises rather than proceeding silently.

Credentials come from the environment only. The API key is read from TOT_API_KEY, held privately by the client, and is never logged, never written to disk by the server, and never included in an audit entry; uploaded file contents are never audited either, only filename and byte size.

Ships with a Dockerfile and compose file. The container entrypoint fixes bind-mount ownership for the audit directory and proves the target uid can actually write there before permanently dropping from root via setpriv — a failure mode that otherwise surfaces late, only on the first write. The test suite runs entirely against a mocked client with no network, appliance or credentials, covering dry-run paths, live paths, audit-entry assertions and confirm-flag rejection paths.