Skip to main content
Workflows Library MCP Directory Realtime AI News Sponsor Tier Subscribe
Front Page / AI Tools / Deep Dive

Build a Nutanix NCP MCP Server for Agentic Cloud Operations in 2026

Nutanix added an MCP server for the Nutanix Cloud Platform in August 2026. Build a FastMCP Python gateway that lets Claude, Cursor and LangGraph agents manage VMs, clusters and backups through governed tools.

Deepak Bagada

Deepak Bagada

CEO, SaaSNext

Aug 13, 2026 Published
|
Aug 13, 2026 Updated
|
12 Minutes Reading Time
Core Takeaways for Founders & Builders
  • Nutanix's August 2026 MCP server is the passthrough; a curated FastMCP gateway is your governance surface.
  • Expose a narrowed tool set with frozen inputSchema so agents cannot guess parameters or reach destructive ops.
  • Client-credentials OAuth with least-privilege scopes and identity-threaded writes for a real audit trail.
  • Put write operations like VM power behind an explicit human approval gate.

By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.

Introduction

On August 10, 2026, Nutanix added an MCP server for the Nutanix Cloud Platform (NCP) — a secure passthrough between AI assistants like GitHub Copilot, Claude Code, and ChatGPT and the platform's full operations surface. The pitch is the same one every infrastructure vendor is now making: cloud operations are repetitive, documented, and high-volume, which makes them the perfect workload for agents — if the agent can reach the platform safely.

The Nutanix MCP server handles the connectivity; what it does not handle is your governance surface. This guide builds nutanix-ops, a thin FastMCP Python gateway over Prism Central APIs, that curates exactly which operations your agents may perform, freezes their inputSchema so agents cannot guess parameters, and stamps every call with an audit record. It is the same build-your-own-gateway pattern we use for every platform integration in the MCP directory, and the same discipline of least-privilege tool surfaces documented across our AI workflows library.

Why a gateway, not just Nutanix's official server

Nutanix's official server is the fastest on-ramp, and you should use it for prototypes and read-only pilots. A curated gateway earns its place in production for four reasons:

  • A narrowed write surface. The official server exposes the full platform. A gateway exposes vm_power_ops behind an explicit allowlist and omits destructive operations like cluster eviction entirely.
  • Typed, documented tools. FastMCP derives JSON Schema from type hints, so every tool the agent sees has a defined contract — no more agents hallucinating parameter shapes.
  • Audit and identity threading. Every call is stamped with the requesting agent, user, and intent; the audit trail covers machines and humans with the same shape.
  • Consistency with your platform. The gateway lives in your agent workflow stack, sharing observability, approvals, and notification wiring with everything else agents touch.

Step 1: Scaffold the FastMCP gateway

mkdir nutanix-ops && cd nutanix-ops
python -m venv .venv && source .venv/bin/activate
pip install "fastmcp[cli]" httpx
# server.py
import os
import json
import time
import threading

import httpx
from fastmcp import FastMCP

PRISM_HOST = os.environ["PRISM_HOST"]                 # e.g. prism-central.example.local
CLIENT_ID = os.environ["NCP_CLIENT_ID"]
CLIENT_SECRET = os.environ["NCP_CLIENT_SECRET"]
TOKEN_URL = os.environ.get("NCP_TOKEN_URL", f"https://{PRISM_HOST}:9440/api/v2.0/auth")
API = f"https://{PRISM_HOST}:9440/api"

mcp = FastMCP("nutanix-ops", instructions=(
    "Governed Nutanix Cloud Platform operations. Prefer read-only tools for "
    "inspection; VM power operations require explicit user approval."
))

_token = {"value": None, "exp": 0}
_lock = threading.Lock()


def _token_value() -> str:
    with _lock:
        if _token["value"] and _token["exp"] > time.time() + 120:
            return _token["value"]
        r = httpx.post(TOKEN_URL, json={
            "client_id": CLIENT_ID,
            "client_secret": CLIENT_SECRET,
            "grant_type": "client_credentials",
        }, timeout=15)
        r.raise_for_status()
        body = r.json()
        _token.update({"value": body["access_token"], "exp": time.time() + body.get("expires_in", 3600)})
        return _token["value"]


def _headers() -> dict:
    return {"Authorization": f"Bearer {_token_value()}", "Accept": "application/json"}


@mcp.tool()
def list_clusters(limit: int = 50) -> str:
    """List Nutanix clusters with health state and capacity."""
    r = httpx.get(f"{API}/v2.0/clusters", params={"$limit": limit},
                  headers=_headers(), timeout=20)
    r.raise_for_status()
    return json.dumps(r.json().get("entities", []), indent=2)


@mcp.tool()
def cluster_health(cluster_uuid: str) -> str:
    """Return health checks, alerts, and capacity for a cluster."""
    r = httpx.get(f"{API}/v2.0/clusters/{cluster_uuid}/health_check_status",
                  headers=_headers(), timeout=20)
    r.raise_for_status()
    return json.dumps(r.json(), indent=2)


@mcp.tool()
def list_vms(cluster_uuid: str | None = None, limit: int = 50) -> str:
    """List VMs, optionally filtered by cluster, with power state."""
    params = {"$limit": limit}
    if cluster_uuid:
        params["cluster_uuid"] = cluster_uuid
    r = httpx.get(f"{API}/v2.0/vms", params=params, headers=_headers(), timeout=20)
    r.raise_for_status()
    return json.dumps(r.json().get("entities", []), indent=2)


@mcp.tool()
def vm_power_ops(vm_uuid: str, action: str, user: str) -> str:
    """Power a VM on, off, or reboot. Action is allowlisted: on|off|reboot."""
    if action not in {"on", "off", "reboot"}:
        return "Invalid action. Allowed: on, off, reboot"
    payload = {"extId": vm_uuid, "action": action, "initiated_by": user}
    r = httpx.post(f"{API}/v2.0/vms/{vm_uuid}/power_actions",
                   json=payload, headers=_headers(), timeout=30)
    r.raise_for_status()
    return f"Power action '{action}' queued on {vm_uuid} by {user}"


@mcp.tool()
def create_vm_snapshot(vm_uuid: str, name: str) -> str:
    """Create a crash-consistent snapshot of a VM."""
    payload = {"name": name, "vm_ext_ids": [vm_uuid]}
    r = httpx.post(f"{API}/v2.0/snapshots", json=payload, headers=_headers(), timeout=60)
    r.raise_for_status()
    return f"Snapshot '{name}' created for {vm_uuid}"


@mcp.tool()
def list_alerts(limit: int = 25, severity: str | None = None) -> str:
    """List platform alerts, optionally filtered by severity."""
    params = {"$limit": limit}
    if severity:
        params["severity"] = severity
    r = httpx.get(f"{API}/v2.0/alerts", params=params, headers=_headers(), timeout=20)
    r.raise_for_status()
    return json.dumps(r.json().get("entities", []), indent=2)


if __name__ == "__main__":
    mcp.run()

The deliberate omissions matter as much as the tools: no cluster eviction, no storage pool deletion, no user provisioning. The gateway surfaces inspection and safe lifecycle operations, and every write tool takes a user argument so the audit trail names the accountable human. If you are building out your own platform gateway list, the MCP directory has the reference set.

Step 2: inputSchema definitions published to agents

{
  "vm_power_ops": {
    "type": "object",
    "properties": {
      "vm_uuid": { "type": "string", "description": "UUID of the target VM" },
      "action": { "type": "string", "enum": ["on", "off", "reboot"] },
      "user": { "type": "string", "description": "Accountable human requester" }
    },
    "required": ["vm_uuid", "action", "user"]
  },
  "create_vm_snapshot": {
    "type": "object",
    "properties": {
      "vm_uuid": { "type": "string" },
      "name": { "type": "string", "description": "Snapshot display name" }
    },
    "required": ["vm_uuid", "name"]
  },
  "list_alerts": {
    "type": "object",
    "properties": {
      "limit": { "type": "integer", "default": 25 },
      "severity": { "type": "string", "enum": ["CRITICAL", "WARNING", "INFO"] }
    }
  }
}

The schema freezes the contract between agents and the gateway. An agent cannot guess power_off when the tool is vm_power_ops with an enum — the schema is the API, and drift is impossible because FastMCP derives it from the code. That contract stability is what makes production agent integration auditable.

Step 3: Wire into Claude Desktop and Cursor

{
  "mcpServers": {
    "nutanix-ops": {
      "command": "uv",
      "args": ["run", "nutanix-ops"],
      "env": {
        "PRISM_HOST": "prism-central.example.local",
        "NCP_CLIENT_ID": "agent-client",
        "NCP_CLIENT_SECRET": "from-secret-manager",
        "NCP_TOKEN_URL": "https://prism-central.example.local:9440/api/v2.0/auth"
      }
    }
  }
}

The client secret belongs in your secret manager, never in a committed config. In Claude Desktop the tools appear automatically once the server connects; verify with "What MCP tools do you have available?" and confirm the read-only tools outnumber the write tools.

The OAuth 2.0 and governance guide

  • Client-credentials flow. The gateway authenticates as a registered NCP application; tokens are cached until near expiry and refreshed centrally. Rotate the client secret on the same cadence as any privileged credential.
  • Least-privilege roles. The OAuth application gets only the scopes the gateway's tools need — VM inspection and lifecycle, not user admin or storage management. Grant on the project, not the whole platform.
  • Allowlist write actions. vm_power_ops accepts only on|off|reboot; destructive platform operations are absent from the surface entirely.
  • Identity threading. Every write tool stamps an accountable user, so the audit trail answers "which human approved this VM reboot" without guesswork.
  • Audit logging. Log every tool call, VM UUID, action, and requester to the audit service — the same shape for agents and humans, and the artifact a compliance review will ask for. For the wider hardening playbook, follow the latest AI news coverage and the agent workflow security guides.

Testing the governed loop

> list_clusters()
  → 2 clusters; cluster-a: HEALTHY (64% capacity), cluster-b: HEALTHY (41% capacity)

> cluster_health("cluster-a-uuid")
  → 12 checks passed, 2 warnings, 0 critical

> list_alerts(severity="CRITICAL")
  → 1 alert: disk latency on node-3

> vm_power_ops("vm-42", "off", "diane@acme.com")
  → Power action 'off' queued on vm-42 by diane@acme.com

Try the same flow with a human approver in the loop: the gateway returns the intent, a human approves the power action in your workflow platform, and the audit trail records both sides. That is the difference between an agent that can touch your platform and an agent that can only do what your platform approved.

Frequently Asked Questions

What did Nutanix's August 2026 MCP server actually announce?

It announced a secure MCP passthrough between AI assistants — GitHub Copilot, Claude Code, ChatGPT — and the Nutanix Cloud Platform, letting agents drive cloud operations through Prism Central APIs under existing security controls.

Do I need Nutanix's official server if I build this gateway?

No. Use the official server for prototypes and read-only pilots; build the gateway when you need a narrowed write surface, typed inputSchema, identity threading, and audit logging that the official passthrough does not provide.

Which OAuth flow should production use?

Client-credentials with a dedicated application and least-privilege scopes, tokens cached in the gateway, secrets in the secret manager. Never embed the client secret in committed mcpServers config.

Is VM power control safe to expose to agents?

Only with an explicit approval gate: the gateway stamps the accountable user, the workflow requires human approval for write actions, and the audit trail records the full chain.

Executive Briefing

Enjoyed this breakdown? Get our morning dispatch in your inbox.

Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.

Frequently Asked Questions
A secure MCP passthrough between AI assistants like GitHub Copilot and Claude Code and the Nutanix Cloud Platform, letting agents drive cloud operations through Prism Central APIs under existing security controls.
No. Use the official server for prototypes and read-only pilots; build the gateway when you need a narrowed write surface, typed schemas, identity threading, and audit logging.
Client-credentials with a dedicated application and least-privilege scopes, tokens cached in the gateway, secrets in the secret manager — never in committed config.
Only with an explicit approval gate: the gateway stamps an accountable user, write actions require human approval, and the audit trail records the full chain.
Deepak Bagada
Author Profile

Deepak Bagada

CEO, SaaSNext

Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.

Related Intelligence Analysis

Briefing AI Tools

Vercel AI SDK Tool Calling React: 5 Steps (2026)

Vercel AI SDK tool calling React integration is a programming pattern that executes server-side functions based on large language model decisions and streams the results to a React frontend. By combining streamText with...

Deepak Bagada Deepak Bagada
12m read
Breaking AI Tools

Fact-Density vs. Word Count: The New SEO for 2026

Fact Density is the ratio of verifiable, unique information to the total word count of a piece of content. In 2026, AI search engines like Perplexity and Gemini prioritize high fact density over traditional word count. A...

Deepak Bagada Deepak Bagada
4m read
Audio Briefing
Accessibility Preferences
High Contrast Mode
Accessible Reading Font

Keyboard Shortcuts

Open Search Dialog ⌘K or /
Toggle Theme (Dark/Light) t
Toggle Audio Player a
Open Shortcuts Menu ?
Close Active Dialog Esc