#
tokens: 26261/50000 53/53 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── go.mod
├── go.sum
├── internal
│   ├── client
│   │   ├── client.go
│   │   └── modelcontextclient.go
│   ├── codegen
│   │   ├── cmd
│   │   │   └── main.go
│   │   └── templates
│   │       ├── resources.go
│   │       └── tools.go
│   └── json
│       ├── marshal_test.go
│       └── marshal.go
├── LICENSE
├── main.go
├── Makefile
├── pkg
│   ├── prompts
│   │   └── credentials.go
│   ├── resources
│   │   ├── accesscontrolpolicy.go
│   │   ├── addressgroup.go
│   │   ├── availabilityzone.go
│   │   ├── category.go
│   │   ├── cluster.go
│   │   ├── common.go
│   │   ├── host.go
│   │   ├── image.go
│   │   ├── networksecurityrule.go
│   │   ├── permission.go
│   │   ├── project.go
│   │   ├── protectionrule.go
│   │   ├── recoveryplan.go
│   │   ├── recoveryplanjob.go
│   │   ├── role.go
│   │   ├── servicegroup.go
│   │   ├── subnet.go
│   │   ├── user.go
│   │   ├── usergroup.go
│   │   ├── vm.go
│   │   └── volumegroup.go
│   └── tools
│       ├── accesscontrolpolicy.go
│       ├── addressgroup.go
│       ├── apinamespace.go
│       ├── category.go
│       ├── cluster.go
│       ├── common.go
│       ├── host.go
│       ├── image.go
│       ├── networksecurityrule.go
│       ├── permission.go
│       ├── project.go
│       ├── protectionrule.go
│       ├── recoveryplan.go
│       ├── recoveryplanjob.go
│       ├── role.go
│       ├── servicegroup.go
│       ├── subnet.go
│       ├── user.go
│       ├── usergroup.go
│       ├── vm.go
│       └── volumegroup.go
└── README.md
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
bin
.DS_Store
mcp.json

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# MCP Nutanix

A Model Context Protocol (MCP) server for interacting with Nutanix Prism Central APIs through Large Language Models (LLMs).

## ⚠️ Disclaimer

**THIS IS AN EXPERIMENTAL PROJECT**

This project was created as a personal project to explore the capabilities of the Model Context Protocol frameworks in Go. It is:

- **NOT** an official Nutanix product or tool
- **NOT** supported, endorsed, or maintained by Nutanix
- **NOT** suitable for production environments
- **PROVIDED AS-IS** with no warranties or guarantees

**USE AT YOUR OWN RISK**: The author takes no responsibility for any issues, damages, or outages that may result from using this code.

## Overview

This MCP server allows LLMs to interact with Nutanix Prism Central by:

1. Connecting to a Prism Central instance with user credentials
2. Listing various resources (VMs, Clusters, Hosts, etc.)
3. Retrieving specific resource details via URI-based access

The implementation uses the [Prism Go Client](https://github.com/nutanix-cloud-native/prism-go-client) to communicate with Prism Central and the [MCP Go library](https://github.com/mark3labs/mcp-go) to implement the Model Context Protocol.

## Getting Started

### Prerequisites

- Go 1.23 or higher
- Access to a Nutanix Prism Central instance
- Tools like `make` and `go fmt` for building

### Building

```bash
# Clone the repository
git clone https://github.com/thunderboltsid/mcp-nutanix.git
cd mcp-nutanix

# Build the MCP server
make build
```

## Credential Configuration

The server supports two credential methods:

1. **Interactive credentials** (default) - Works with Claude via MCP prompts
2. **Static credentials** - Required for tools like Cursor that don't support interactive prompts

## MCP Client Configuration

To use this server with MCP clients, you need to configure the client to connect to the server.

### Claude Desktop/Code

Create or update `~/.anthropic/claude_desktop.json`:

```json
{
  "mcpServers": {
    "nutanix": {
      "command": "/path/to/mcp-nutanix"
    }
  }
}
```

Claude will prompt you for credentials when first using the server.

### Cursor

For Cursor, you need to provide static credentials via environment variables since it doesn't support interactive prompts.

Create or update `~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "nutanix": {
      "command": "/path/to/mcp-nutanix",
      "env": {
        "NUTANIX_ENDPOINT": "your-prism-central-ip-or-hostname",
        "NUTANIX_USERNAME": "your-username", 
        "NUTANIX_PASSWORD": "your-password",
        "NUTANIX_INSECURE": "true"
      }
    }
  }
}
```

**Environment Variables:**
- `NUTANIX_ENDPOINT` - Prism Central IP or hostname (required)
- `NUTANIX_USERNAME` - API username (required)
- `NUTANIX_PASSWORD` - API password (required)
- `NUTANIX_INSECURE` - Set to "true" for self-signed certificates (optional)

### Other MCP Clients

This server follows the standard MCP protocol and should work with any MCP client that supports stdio transport. Refer to your client's documentation for configuration instructions.

## Usage

Once the MCP server is configured with your client and connected to your Prism Central instance, LLMs can interact with it through the MCP protocol.

### Resource Listing

To list resources, use the appropriate tool:

```
vms
clusters
hosts
images
subnets
```

The LLM will receive a JSON list of resources that it can parse and analyze.

### Resource Access

To access a specific resource, use a resource URI:

```
vm://{uuid}
cluster://{uuid}
host://{uuid}
```

The LLM will receive detailed JSON information about the specific resource.

## Development

### Project Structure

```
mcp-nutanix/
├── bin/                  # Compiled binaries
├── internal/             # Internal packages
│   ├── client/           # Prism Central client handling
│   ├── codegen/          # Code generation utilities
│   └── json/             # JSON helpers
├── pkg/                  # components
│   ├── prompts/          # MCP prompt implementations
│   ├── resources/        # Resource handlers
│   └── tools/            # Tool handlers
└── Makefile              # Build and utility commands
```

### Code Generation

The project uses code generation to create resource and tool handlers. To update these:

```bash
make generate
```

## Limitations

- Response size is limited by the MCP protocol
- Some resources with large response sizes may cause errors
- No pagination support in the current implementation
- Only supports read operations, no create/update/delete

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Acknowledgments

- [Nutanix](https://www.nutanix.com/) for creating the Prism API
- [Mark3Labs](https://github.com/mark3labs) for the MCP Go library
- [Nutanix Cloud Native](https://github.com/nutanix-cloud-native) for the Prism Go Client

## Contributing

This is an experimental project with no formal contribution process. Feel free to create issues or pull requests.

```

--------------------------------------------------------------------------------
/pkg/resources/vm.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// VM defines the VM resource template
func VM() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeVM))+"{uuid}",
		string(ResourceTypeVM),
		mcp.WithTemplateDescription("Virtual Machine resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// VMHandler implements the handler for the VM resource
func VMHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeVM, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the VM
		return client.V3().GetVM(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/host.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Host defines the Host resource template
func Host() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeHost))+"{uuid}",
		string(ResourceTypeHost),
		mcp.WithTemplateDescription("Host resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// HostHandler implements the handler for the Host resource
func HostHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeHost, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the Host
		return client.V3().GetHost(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/role.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Role defines the Role resource template
func Role() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeRole))+"{uuid}",
		string(ResourceTypeRole),
		mcp.WithTemplateDescription("Role resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// RoleHandler implements the handler for the Role resource
func RoleHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeRole, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the Role
		return client.V3().GetRole(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/user.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// User defines the User resource template
func User() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeUser))+"{uuid}",
		string(ResourceTypeUser),
		mcp.WithTemplateDescription("User resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// UserHandler implements the handler for the User resource
func UserHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeUser, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the User
		return client.V3().GetUser(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/image.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Image defines the Image resource template
func Image() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeImage))+"{uuid}",
		string(ResourceTypeImage),
		mcp.WithTemplateDescription("Image resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// ImageHandler implements the handler for the Image resource
func ImageHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeImage, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the Image
		return client.V3().GetImage(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/subnet.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Subnet defines the Subnet resource template
func Subnet() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeSubnet))+"{uuid}",
		string(ResourceTypeSubnet),
		mcp.WithTemplateDescription("Subnet resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// SubnetHandler implements the handler for the Subnet resource
func SubnetHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeSubnet, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the Subnet
		return client.V3().GetSubnet(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/cluster.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Cluster defines the Cluster resource template
func Cluster() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeCluster))+"{uuid}",
		string(ResourceTypeCluster),
		mcp.WithTemplateDescription("Cluster resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// ClusterHandler implements the handler for the Cluster resource
func ClusterHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeCluster, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the Cluster
		return client.V3().GetCluster(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/project.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Project defines the Project resource template
func Project() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeProject))+"{uuid}",
		string(ResourceTypeProject),
		mcp.WithTemplateDescription("Project resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// ProjectHandler implements the handler for the Project resource
func ProjectHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeProject, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the Project
		return client.V3().GetProject(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/category.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Category defines the Category resource template
func Category() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeCategory))+"{uuid}",
		string(ResourceTypeCategory),
		mcp.WithTemplateDescription("Category resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// CategoryHandler implements the handler for the Category resource
func CategoryHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeCategory, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the Category
		return client.V3().GetCategoryKey(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/usergroup.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// UserGroup defines the UserGroup resource template
func UserGroup() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeUserGroup))+"{uuid}",
		string(ResourceTypeUserGroup),
		mcp.WithTemplateDescription("User Group resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// UserGroupHandler implements the handler for the UserGroup resource
func UserGroupHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeUserGroup, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the UserGroup
		return client.V3().GetUserGroup(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/permission.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Permission defines the Permission resource template
func Permission() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypePermission))+"{uuid}",
		string(ResourceTypePermission),
		mcp.WithTemplateDescription("Permission resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// PermissionHandler implements the handler for the Permission resource
func PermissionHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypePermission, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the Permission
		return client.V3().GetPermission(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/volumegroup.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// VolumeGroup defines the VolumeGroup resource template
func VolumeGroup() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeVolumeGroup))+"{uuid}",
		string(ResourceTypeVolumeGroup),
		mcp.WithTemplateDescription("Volume Group resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// VolumeGroupHandler implements the handler for the VolumeGroup resource
func VolumeGroupHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeVolumeGroup, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the VolumeGroup
		return client.V3().GetVolumeGroup(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/addressgroup.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// AddressGroup defines the AddressGroup resource template
func AddressGroup() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeAddressGroup))+"{uuid}",
		string(ResourceTypeAddressGroup),
		mcp.WithTemplateDescription("Address Group resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// AddressGroupHandler implements the handler for the AddressGroup resource
func AddressGroupHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeAddressGroup, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the AddressGroup
		return client.V3().GetAddressGroup(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/recoveryplan.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// RecoveryPlan defines the RecoveryPlan resource template
func RecoveryPlan() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeRecoveryPlan))+"{uuid}",
		string(ResourceTypeRecoveryPlan),
		mcp.WithTemplateDescription("Recovery Plan resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// RecoveryPlanHandler implements the handler for the RecoveryPlan resource
func RecoveryPlanHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeRecoveryPlan, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the RecoveryPlan
		return client.V3().GetRecoveryPlan(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/servicegroup.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// ServiceGroup defines the ServiceGroup resource template
func ServiceGroup() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeServiceGroup))+"{uuid}",
		string(ResourceTypeServiceGroup),
		mcp.WithTemplateDescription("Service Group resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// ServiceGroupHandler implements the handler for the ServiceGroup resource
func ServiceGroupHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeServiceGroup, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the ServiceGroup
		return client.V3().GetServiceGroup(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/internal/codegen/cmd/main.go:
--------------------------------------------------------------------------------

```go
package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"

	"github.com/thunderboltsid/mcp-nutanix/internal/codegen/templates"
)

func main() {
	// Parse command-line arguments
	outputDir := flag.String("output", ".", "Output directory for generated files")
	flag.Parse()

	// Get absolute path
	absPath, err := filepath.Abs(*outputDir)
	if err != nil {
		fmt.Printf("Error getting absolute path: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Generating resource and tool files in: %s\n", absPath)

	// Generate all resource files
	if err := templates.GenerateResourceFiles(absPath); err != nil {
		fmt.Printf("Error generating files: %v\n", err)
		os.Exit(1)
	}

	// Generate all resource files
	if err := templates.GenerateToolFiles(absPath); err != nil {
		fmt.Printf("Error generating files: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("Resource and tool files generated successfully!")
}

```

--------------------------------------------------------------------------------
/pkg/resources/protectionrule.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// ProtectionRule defines the ProtectionRule resource template
func ProtectionRule() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeProtectionRule))+"{uuid}",
		string(ResourceTypeProtectionRule),
		mcp.WithTemplateDescription("Protection Rule resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// ProtectionRuleHandler implements the handler for the ProtectionRule resource
func ProtectionRuleHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeProtectionRule, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the ProtectionRule
		return client.V3().GetProtectionRule(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/recoveryplanjob.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// RecoveryPlanJob defines the RecoveryPlanJob resource template
func RecoveryPlanJob() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeRecoveryPlanJob))+"{uuid}",
		string(ResourceTypeRecoveryPlanJob),
		mcp.WithTemplateDescription("Recovery Plan Job resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// RecoveryPlanJobHandler implements the handler for the RecoveryPlanJob resource
func RecoveryPlanJobHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeRecoveryPlanJob, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the RecoveryPlanJob
		return client.V3().GetRecoveryPlanJob(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/availabilityzone.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// AvailabilityZone defines the AvailabilityZone resource template
func AvailabilityZone() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeAvailabilityZone))+"{uuid}",
		string(ResourceTypeAvailabilityZone),
		mcp.WithTemplateDescription("Availability Zone resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// AvailabilityZoneHandler implements the handler for the AvailabilityZone resource
func AvailabilityZoneHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeAvailabilityZone, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the AvailabilityZone
		return client.V3().GetAvailabilityZone(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/accesscontrolpolicy.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// AccessControlPolicy defines the AccessControlPolicy resource template
func AccessControlPolicy() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeAccessControlPolicy))+"{uuid}",
		string(ResourceTypeAccessControlPolicy),
		mcp.WithTemplateDescription("Access Control Policy resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// AccessControlPolicyHandler implements the handler for the AccessControlPolicy resource
func AccessControlPolicyHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeAccessControlPolicy, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the AccessControlPolicy
		return client.V3().GetAccessControlPolicy(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/resources/networksecurityrule.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// NetworkSecurityRule defines the NetworkSecurityRule resource template
func NetworkSecurityRule() mcp.ResourceTemplate {
	return mcp.NewResourceTemplate(
		string(ResourceURIPrefix(ResourceTypeNetworkSecurityRule))+"{uuid}",
		string(ResourceTypeNetworkSecurityRule),
		mcp.WithTemplateDescription("Network Security Rule resource"),
		mcp.WithTemplateMIMEType("application/json"),
	)
}

// NetworkSecurityRuleHandler implements the handler for the NetworkSecurityRule resource
func NetworkSecurityRuleHandler() server.ResourceTemplateHandlerFunc {
	return CreateResourceHandler(ResourceTypeNetworkSecurityRule, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
		// Get the NetworkSecurityRule
		return client.V3().GetNetworkSecurityRule(ctx, uuid)
	})
}

```

--------------------------------------------------------------------------------
/pkg/tools/apinamespace.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/internal/json"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// ApiNamespacesList defines the API namespaces list tool
func ApiNamespacesList() mcp.Tool {
	return mcp.NewTool("api_namespaces_list",
		mcp.WithDescription("List available API namespaces and their routes in Prism Central"),
	)
}

// ApiNamespacesListHandler implements the handler for the API namespaces list tool
func ApiNamespacesListHandler() server.ToolHandlerFunc {
	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		// Get the Prism client
		prismClient := client.GetPrismClient()

		// Call the Actuator API to get version routes
		response, err := prismClient.V4().ActuatorApiInstance.GetVersionRoutes(ctx)
		if err != nil {
			return nil, err
		}

		// Convert to JSON using regular JSON encoder
		cjson := json.RegularJSONEncoder(response)
		jsonBytes, err := cjson.MarshalJSON()
		if err != nil {
			return nil, err
		}

		return mcp.NewToolResultText(string(jsonBytes)), nil
	}
}

```

--------------------------------------------------------------------------------
/internal/client/modelcontextclient.go:
--------------------------------------------------------------------------------

```go
package client

import (
	"errors"
	"sync"

	"github.com/nutanix-cloud-native/prism-go-client/environment/providers/mcp"
)

// mcpModelContextClient is an example implementation of ModelContextClient.
// It stores key–value pairs in an in-memory map.
type mcpModelContextClient struct {
	mu   sync.RWMutex
	data map[string]string
}

var PrismClientProvider = &mcpModelContextClient{
	data: make(map[string]string),
}

var _ mcp.ModelContextClient = &mcpModelContextClient{}

// NewMCPModelContextClient creates a new instance with the provided initial data.
func NewMCPModelContextClient(initialData map[string]string) mcp.ModelContextClient {
	if initialData == nil {
		initialData = make(map[string]string)
	}

	return &mcpModelContextClient{
		data: initialData,
	}
}

// GetValue retrieves the value for a given key from the model context.
// It returns an error if the key is not found.
func (c *mcpModelContextClient) GetValue(key string) (string, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	if val, exists := c.data[key]; exists {
		return val, nil
	}
	return "", errors.New("model context key not found")
}

// Optionally, you can add a method to update values in the model context.
func (c *mcpModelContextClient) UpdateValue(key, value string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.data[key] = value
}

```

--------------------------------------------------------------------------------
/internal/json/marshal_test.go:
--------------------------------------------------------------------------------

```go
package json

import (
	"encoding/json"
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestMarshalJSON(t *testing.T) {
	jsonData := []byte(`
    {
        "api_version": "3.0",
        "entities": [
            {
                "metadata": {"uuid": "b7816400-16c5-47c7-9fcc-474e39594ad5"},
                "status": {"big": "object"},
                "spec": {
                    "name": "vm1",
					"resources": {
                        "guest_customization": {"very": "large", "nested": "object"},
                        "subnets": [{"name": "subnet1"}, {"name": "subnet2"}]
                    }
                }
            },
            {
                "metadata": {"uuid": "b7816400-16c5-47c7-9fcc-474e39594ad6"},
                "status": {"big": "object2"},
                "spec": {
                    "name": "vm2",
					"resources": {
                        "guest_customization": {"very": "large", "nested": "object"},
                        "subnets": [{"name": "subnet1"}, {"name": "subnet2"}]
                    }
                }
            }
        ]
    }`)
	ujson := make(map[string]any)
	err := json.Unmarshal(jsonData, &ujson)
	assert.NoError(t, err)

	cjson := CustomJSON{
		Value: ujson,
		StripPaths: []string{
			"api_version",
			"entities[].status",
			"spec.resources.guest_customization",
			"entities[].spec.resources.guest_customization",
		},
	}

	mdata, err := json.Marshal(cjson)
	assert.NoError(t, err)
	assert.NotNil(t, mdata)
}

```

--------------------------------------------------------------------------------
/pkg/tools/vm.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// VM defines the VM tool
func VMList() mcp.Tool {
	return mcp.NewTool("vm_list",
		mcp.WithDescription("List vm resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// VMListHandler implements the handler for the VM list tool
func VMListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeVM,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllVM(ctx, "")

		},
	)
}

// VMCount defines the VM count tool
func VMCount() mcp.Tool {
	return mcp.NewTool("vm_count",
		mcp.WithDescription("Count vm resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// VMCountHandler implements the handler for the VM count tool
func VMCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeVM,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllVM(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "VM",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/role.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Role defines the Role tool
func RoleList() mcp.Tool {
	return mcp.NewTool("role_list",
		mcp.WithDescription("List role resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// RoleListHandler implements the handler for the Role list tool
func RoleListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeRole,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllRole(ctx, "")

		},
	)
}

// RoleCount defines the Role count tool
func RoleCount() mcp.Tool {
	return mcp.NewTool("role_count",
		mcp.WithDescription("Count role resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// RoleCountHandler implements the handler for the Role count tool
func RoleCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeRole,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllRole(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "Role",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/user.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// User defines the User tool
func UserList() mcp.Tool {
	return mcp.NewTool("user_list",
		mcp.WithDescription("List user resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// UserListHandler implements the handler for the User list tool
func UserListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeUser,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllUser(ctx, "")

		},
	)
}

// UserCount defines the User count tool
func UserCount() mcp.Tool {
	return mcp.NewTool("user_count",
		mcp.WithDescription("Count user resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// UserCountHandler implements the handler for the User count tool
func UserCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeUser,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllUser(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "User",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/host.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Host defines the Host tool
func HostList() mcp.Tool {
	return mcp.NewTool("host_list",
		mcp.WithDescription("List host resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// HostListHandler implements the handler for the Host list tool
func HostListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeHost,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Special case for Host which doesn't take a filter
			return client.V3().ListAllHost(ctx)

		},
	)
}

// HostCount defines the Host count tool
func HostCount() mcp.Tool {
	return mcp.NewTool("host_count",
		mcp.WithDescription("Count host resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// HostCountHandler implements the handler for the Host count tool
func HostCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeHost,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Special case for Host which doesn't take a filter
			resp, err := client.V3().ListAllHost(ctx)

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "Host",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/image.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Image defines the Image tool
func ImageList() mcp.Tool {
	return mcp.NewTool("image_list",
		mcp.WithDescription("List image resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ImageListHandler implements the handler for the Image list tool
func ImageListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeImage,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllImage(ctx, "")

		},
	)
}

// ImageCount defines the Image count tool
func ImageCount() mcp.Tool {
	return mcp.NewTool("image_count",
		mcp.WithDescription("Count image resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ImageCountHandler implements the handler for the Image count tool
func ImageCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeImage,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllImage(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "Image",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/cluster.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Cluster defines the Cluster tool
func ClusterList() mcp.Tool {
	return mcp.NewTool("cluster_list",
		mcp.WithDescription("List cluster resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ClusterListHandler implements the handler for the Cluster list tool
func ClusterListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeCluster,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllCluster(ctx, "")

		},
	)
}

// ClusterCount defines the Cluster count tool
func ClusterCount() mcp.Tool {
	return mcp.NewTool("cluster_count",
		mcp.WithDescription("Count cluster resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ClusterCountHandler implements the handler for the Cluster count tool
func ClusterCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeCluster,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllCluster(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "Cluster",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/project.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Project defines the Project tool
func ProjectList() mcp.Tool {
	return mcp.NewTool("project_list",
		mcp.WithDescription("List project resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ProjectListHandler implements the handler for the Project list tool
func ProjectListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeProject,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllProject(ctx, "")

		},
	)
}

// ProjectCount defines the Project count tool
func ProjectCount() mcp.Tool {
	return mcp.NewTool("project_count",
		mcp.WithDescription("Count project resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ProjectCountHandler implements the handler for the Project count tool
func ProjectCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeProject,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllProject(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "Project",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/subnet.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Subnet defines the Subnet tool
func SubnetList() mcp.Tool {
	return mcp.NewTool("subnet_list",
		mcp.WithDescription("List subnet resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// SubnetListHandler implements the handler for the Subnet list tool
func SubnetListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeSubnet,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Special case for Subnet which has an extra parameter
			return client.V3().ListAllSubnet(ctx, "", nil)

		},
	)
}

// SubnetCount defines the Subnet count tool
func SubnetCount() mcp.Tool {
	return mcp.NewTool("subnet_count",
		mcp.WithDescription("Count subnet resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// SubnetCountHandler implements the handler for the Subnet count tool
func SubnetCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeSubnet,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Special case for Subnet which has an extra parameter
			resp, err := client.V3().ListAllSubnet(ctx, "", nil)

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "Subnet",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/usergroup.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// UserGroup defines the UserGroup tool
func UserGroupList() mcp.Tool {
	return mcp.NewTool("usergroup_list",
		mcp.WithDescription("List usergroup resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// UserGroupListHandler implements the handler for the UserGroup list tool
func UserGroupListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeUserGroup,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllUserGroup(ctx, "")

		},
	)
}

// UserGroupCount defines the UserGroup count tool
func UserGroupCount() mcp.Tool {
	return mcp.NewTool("usergroup_count",
		mcp.WithDescription("Count usergroup resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// UserGroupCountHandler implements the handler for the UserGroup count tool
func UserGroupCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeUserGroup,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllUserGroup(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "UserGroup",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/permission.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Permission defines the Permission tool
func PermissionList() mcp.Tool {
	return mcp.NewTool("permission_list",
		mcp.WithDescription("List permission resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// PermissionListHandler implements the handler for the Permission list tool
func PermissionListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypePermission,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllPermission(ctx, "")

		},
	)
}

// PermissionCount defines the Permission count tool
func PermissionCount() mcp.Tool {
	return mcp.NewTool("permission_count",
		mcp.WithDescription("Count permission resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// PermissionCountHandler implements the handler for the Permission count tool
func PermissionCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypePermission,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllPermission(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "Permission",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/addressgroup.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// AddressGroup defines the AddressGroup tool
func AddressGroupList() mcp.Tool {
	return mcp.NewTool("addressgroup_list",
		mcp.WithDescription("List addressgroup resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// AddressGroupListHandler implements the handler for the AddressGroup list tool
func AddressGroupListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeAddressGroup,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllAddressGroups(ctx, "")

		},
	)
}

// AddressGroupCount defines the AddressGroup count tool
func AddressGroupCount() mcp.Tool {
	return mcp.NewTool("addressgroup_count",
		mcp.WithDescription("Count addressgroup resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// AddressGroupCountHandler implements the handler for the AddressGroup count tool
func AddressGroupCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeAddressGroup,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllAddressGroups(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "AddressGroup",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/recoveryplan.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// RecoveryPlan defines the RecoveryPlan tool
func RecoveryPlanList() mcp.Tool {
	return mcp.NewTool("recoveryplan_list",
		mcp.WithDescription("List recoveryplan resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// RecoveryPlanListHandler implements the handler for the RecoveryPlan list tool
func RecoveryPlanListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeRecoveryPlan,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllRecoveryPlans(ctx, "")

		},
	)
}

// RecoveryPlanCount defines the RecoveryPlan count tool
func RecoveryPlanCount() mcp.Tool {
	return mcp.NewTool("recoveryplan_count",
		mcp.WithDescription("Count recoveryplan resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// RecoveryPlanCountHandler implements the handler for the RecoveryPlan count tool
func RecoveryPlanCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeRecoveryPlan,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllRecoveryPlans(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "RecoveryPlan",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/servicegroup.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// ServiceGroup defines the ServiceGroup tool
func ServiceGroupList() mcp.Tool {
	return mcp.NewTool("servicegroup_list",
		mcp.WithDescription("List servicegroup resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ServiceGroupListHandler implements the handler for the ServiceGroup list tool
func ServiceGroupListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeServiceGroup,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllServiceGroups(ctx, "")

		},
	)
}

// ServiceGroupCount defines the ServiceGroup count tool
func ServiceGroupCount() mcp.Tool {
	return mcp.NewTool("servicegroup_count",
		mcp.WithDescription("Count servicegroup resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ServiceGroupCountHandler implements the handler for the ServiceGroup count tool
func ServiceGroupCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeServiceGroup,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllServiceGroups(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "ServiceGroup",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/protectionrule.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// ProtectionRule defines the ProtectionRule tool
func ProtectionRuleList() mcp.Tool {
	return mcp.NewTool("protectionrule_list",
		mcp.WithDescription("List protectionrule resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ProtectionRuleListHandler implements the handler for the ProtectionRule list tool
func ProtectionRuleListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeProtectionRule,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllProtectionRules(ctx, "")

		},
	)
}

// ProtectionRuleCount defines the ProtectionRule count tool
func ProtectionRuleCount() mcp.Tool {
	return mcp.NewTool("protectionrule_count",
		mcp.WithDescription("Count protectionrule resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// ProtectionRuleCountHandler implements the handler for the ProtectionRule count tool
func ProtectionRuleCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeProtectionRule,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllProtectionRules(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "ProtectionRule",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/volumegroup.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	v3 "github.com/nutanix-cloud-native/prism-go-client/v3"
	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// VolumeGroup defines the VolumeGroup tool
func VolumeGroupList() mcp.Tool {
	return mcp.NewTool("volumegroup_list",
		mcp.WithDescription("List volumegroup resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// VolumeGroupListHandler implements the handler for the VolumeGroup list tool
func VolumeGroupListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeVolumeGroup,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Create DSMetadata without filter
			metadata := &v3.DSMetadata{}

			return client.V3().ListVolumeGroup(ctx, metadata)

		},
	)
}

// VolumeGroupCount defines the VolumeGroup count tool
func VolumeGroupCount() mcp.Tool {
	return mcp.NewTool("volumegroup_count",
		mcp.WithDescription("Count volumegroup resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// VolumeGroupCountHandler implements the handler for the VolumeGroup count tool
func VolumeGroupCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeVolumeGroup,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Create DSMetadata without filter
			metadata := &v3.DSMetadata{}

			resp, err := client.V3().ListVolumeGroup(ctx, metadata)

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "VolumeGroup",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/category.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
	v3 "github.com/nutanix-cloud-native/prism-go-client/v3"
)

// Category defines the Category tool
func CategoryList() mcp.Tool {
	return mcp.NewTool("category_list",
		mcp.WithDescription("List category resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// CategoryListHandler implements the handler for the Category list tool
func CategoryListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeCategory,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Special case for Category which takes CategoryListMetadata
			metadata := &v3.CategoryListMetadata{}
			return client.V3().ListCategories(ctx, metadata)

		},
	)
}

// CategoryCount defines the Category count tool
func CategoryCount() mcp.Tool {
	return mcp.NewTool("category_count",
		mcp.WithDescription("Count category resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// CategoryCountHandler implements the handler for the Category count tool
func CategoryCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeCategory,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Special case for Category which takes CategoryListMetadata
			metadata := &v3.CategoryListMetadata{}
			resp, err := client.V3().ListCategories(ctx, metadata)

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "Category",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/internal/client/client.go:
--------------------------------------------------------------------------------

```go
package client

import (
	"github.com/nutanix-cloud-native/prism-go-client/environment"
	"github.com/nutanix-cloud-native/prism-go-client/environment/providers/local"
	"github.com/nutanix-cloud-native/prism-go-client/environment/providers/mcp"
	envtypes "github.com/nutanix-cloud-native/prism-go-client/environment/types"
	prismclientv3 "github.com/nutanix-cloud-native/prism-go-client/v3"
	prismclientv4 "github.com/nutanix-cloud-native/prism-go-client/v4"
	"k8s.io/klog"
)

var (
	prismClient *NutanixClient
)

func Init(modelcontextclient mcp.ModelContextClient) {
	prismClient = &NutanixClient{
		env:           environment.NewEnvironment(local.NewProvider(), mcp.NewProvider(modelcontextclient)),
		v3ClientCache: prismclientv3.NewClientCache(),
		v4ClientCache: prismclientv4.NewClientCache(),
	}
}

func GetPrismClient() *NutanixClient {
	if prismClient == nil {
		panic("Prism client not initialized. Call Init() first.")
	}

	return prismClient
}

type NutanixClient struct {
	env           envtypes.Environment
	v3ClientCache *prismclientv3.ClientCache
	v4ClientCache *prismclientv4.ClientCache
}

// GetV3Client returns the v3 client
func (n *NutanixClient) V3() prismclientv3.Service {
	c, err := n.v3ClientCache.GetOrCreate(n)
	if err != nil {
		panic(err)
	}

	return c.V3
}

// GetV4Client returns the v4 client
func (n *NutanixClient) V4() *prismclientv4.Client {
	c, err := n.v4ClientCache.GetOrCreate(n)
	if err != nil {
		panic(err)
	}

	return c
}

// Key returns the constant client name
// This implements the CachedClientParams interface of prism-go-client
func (n *NutanixClient) Key() string {
	return "mcp-server"
}

// ManagementEndpoint returns the management endpoint of the Nutanix cluster
// This implements the CachedClientParams interface of prism-go-client
func (n *NutanixClient) ManagementEndpoint() envtypes.ManagementEndpoint {
	mgmtEndpoint, err := n.env.GetManagementEndpoint(envtypes.Topology{})
	if err != nil {
		klog.Errorf("failed to get management endpoint: %s", err.Error())
		return envtypes.ManagementEndpoint{}
	}

	return *mgmtEndpoint
}

```

--------------------------------------------------------------------------------
/pkg/tools/accesscontrolpolicy.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// AccessControlPolicy defines the AccessControlPolicy tool
func AccessControlPolicyList() mcp.Tool {
	return mcp.NewTool("accesscontrolpolicy_list",
		mcp.WithDescription("List accesscontrolpolicy resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// AccessControlPolicyListHandler implements the handler for the AccessControlPolicy list tool
func AccessControlPolicyListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeAccessControlPolicy,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllAccessControlPolicy(ctx, "")

		},
	)
}

// AccessControlPolicyCount defines the AccessControlPolicy count tool
func AccessControlPolicyCount() mcp.Tool {
	return mcp.NewTool("accesscontrolpolicy_count",
		mcp.WithDescription("Count accesscontrolpolicy resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// AccessControlPolicyCountHandler implements the handler for the AccessControlPolicy count tool
func AccessControlPolicyCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeAccessControlPolicy,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllAccessControlPolicy(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "AccessControlPolicy",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/networksecurityrule.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// NetworkSecurityRule defines the NetworkSecurityRule tool
func NetworkSecurityRuleList() mcp.Tool {
	return mcp.NewTool("networksecurityrule_list",
		mcp.WithDescription("List networksecurityrule resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// NetworkSecurityRuleListHandler implements the handler for the NetworkSecurityRule list tool
func NetworkSecurityRuleListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeNetworkSecurityRule,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			return client.V3().ListAllNetworkSecurityRule(ctx, "")

		},
	)
}

// NetworkSecurityRuleCount defines the NetworkSecurityRule count tool
func NetworkSecurityRuleCount() mcp.Tool {
	return mcp.NewTool("networksecurityrule_count",
		mcp.WithDescription("Count networksecurityrule resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// NetworkSecurityRuleCountHandler implements the handler for the NetworkSecurityRule count tool
func NetworkSecurityRuleCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeNetworkSecurityRule,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Use ListAll function to get all resources
			resp, err := client.V3().ListAllNetworkSecurityRule(ctx, "")

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "NetworkSecurityRule",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/tools/recoveryplanjob.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
	v3 "github.com/nutanix-cloud-native/prism-go-client/v3"
)

// RecoveryPlanJob defines the RecoveryPlanJob tool
func RecoveryPlanJobList() mcp.Tool {
	return mcp.NewTool("recoveryplanjob_list",
		mcp.WithDescription("List recoveryplanjob resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// RecoveryPlanJobListHandler implements the handler for the RecoveryPlanJob list tool
func RecoveryPlanJobListHandler() server.ToolHandlerFunc {
	return CreateListToolHandler(
		resources.ResourceTypeRecoveryPlanJob,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Create DSMetadata without filter
			metadata := &v3.DSMetadata{}

			return client.V3().ListRecoveryPlanJobs(ctx, metadata)

		},
	)
}

// RecoveryPlanJobCount defines the RecoveryPlanJob count tool
func RecoveryPlanJobCount() mcp.Tool {
	return mcp.NewTool("recoveryplanjob_count",
		mcp.WithDescription("Count recoveryplanjob resources"),
		mcp.WithString("filter",
			mcp.Description("Optional text filter (interpreted by LLM)"),
		),
	)
}

// RecoveryPlanJobCountHandler implements the handler for the RecoveryPlanJob count tool
func RecoveryPlanJobCountHandler() server.ToolHandlerFunc {
	return CreateCountToolHandler(
		resources.ResourceTypeRecoveryPlanJob,
		// Define the ListResourceFunc implementation
		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {

			// Create DSMetadata without filter
			metadata := &v3.DSMetadata{}

			resp, err := client.V3().ListRecoveryPlanJobs(ctx, metadata)

			if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "RecoveryPlanJob",
				"count":         len(resp.Entities),
				"metadata":      resp.Metadata,
			}

			return res, nil
		},
	)
}

```

--------------------------------------------------------------------------------
/pkg/prompts/credentials.go:
--------------------------------------------------------------------------------

```go
package prompts

import (
	"context"
	"fmt"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

func SetCredentials() mcp.Prompt {
	return mcp.NewPrompt("credentials",
		mcp.WithPromptDescription("Credentials for Prism Central"),
		mcp.WithArgument("endpoint",
			mcp.RequiredArgument(),
			mcp.ArgumentDescription("Prism Central endpoint"),
		),
		mcp.WithArgument("username",
			mcp.RequiredArgument(),
			mcp.ArgumentDescription("Username of the Prism Central user"),
		),
		mcp.WithArgument("password",
			mcp.RequiredArgument(),
			mcp.ArgumentDescription("Password of the Prism Central user"),
		),
		mcp.WithArgument("insecure",
			mcp.ArgumentDescription("Skip TLS verification (true/false)"),
		),
	)
}

func SetCredentialsResponse() server.PromptHandlerFunc {
	return func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
		endpoint := request.Params.Arguments["endpoint"]
		username := request.Params.Arguments["username"]
		password := request.Params.Arguments["password"]
		insecure := request.Params.Arguments["insecure"]

		client.PrismClientProvider.UpdateValue("endpoint", endpoint)
		client.PrismClientProvider.UpdateValue("username", username)
		client.PrismClientProvider.UpdateValue("password", password)
		client.PrismClientProvider.UpdateValue("insecure", insecure)

		client.Init(client.PrismClientProvider)

		// Validate the credentials
		pcInfo, err := client.GetPrismClient().V3().GetPrismCentral(ctx)
		if err != nil {
			return mcp.NewGetPromptResult(
				"Failed to connect to Prism Central",
				[]mcp.PromptMessage{
					mcp.NewPromptMessage(
						mcp.RoleAssistant,
						mcp.NewTextContent(fmt.Sprintf("Failed to connect to Prism Central: %s. Please check your credentials and try again.", err.Error())),
					),
				},
			), nil
		}

		return mcp.NewGetPromptResult(
			"Connected to Prism Central",
			[]mcp.PromptMessage{
				mcp.NewPromptMessage(
					mcp.RoleAssistant,
					mcp.NewTextContent(fmt.Sprintf("Successfully connected to Prism Central %s at %s. You can now use the tools to interact with your Nutanix environment.", pcInfo.Resources.ClusterUUID, endpoint)),
				),
			},
		), nil
	}
}

```

--------------------------------------------------------------------------------
/pkg/tools/common.go:
--------------------------------------------------------------------------------

```go
package tools

import (
	"context"
	"fmt"
	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/internal/json"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// ListResourceFunc defines a function that handles listing a resource type
type ListResourceFunc func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error)

// CreateListToolHandler creates a generic tool handler for listing resources
func CreateListToolHandler(
	resourceType resources.ResourceType,
	listFunc ListResourceFunc,
) server.ToolHandlerFunc {
	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		// Get the Prism client
		prismClient := client.GetPrismClient()
		if prismClient == nil {
			return nil, fmt.Errorf("prism client not initialized, please set credentials first")
		}

		// Get filter if provided (for LLM reference only)
		//filter, _ := request.Params.Arguments["filter"].(string)

		// List all resources
		resp, err := listFunc(ctx, prismClient, "")
		if err != nil {
			return nil, fmt.Errorf("failed to list %s: %w", resourceType, err)
		}

		// Convert to JSON
		cjson := json.CustomJSONEncoder(resp)
		jsonBytes, err := cjson.MarshalJSON()
		if err != nil {
			return nil, fmt.Errorf("failed to marshal %s: %w", resourceType, err)
		}

		return mcp.NewToolResultText(string(jsonBytes)), nil
	}
}

// CreateCountToolHandler creates a generic tool handler for counting resources
func CreateCountToolHandler(
	resourceType resources.ResourceType,
	countFunc ListResourceFunc,
) server.ToolHandlerFunc {
	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		// Get the Prism client
		prismClient := client.GetPrismClient()
		if prismClient == nil {
			return nil, fmt.Errorf("prism client not initialized, please set credentials first")
		}

		// Get filter if provided (for LLM reference only)
		//filter, _ := request.Params.Arguments["filter"].(string)

		// List all resources
		resp, err := countFunc(ctx, prismClient, "")
		if err != nil {
			return nil, fmt.Errorf("failed to list %s: %w", resourceType, err)
		}

		// Convert to JSON
		cjson := json.RegularJSONEncoder(resp)
		jsonBytes, err := cjson.MarshalJSON()
		if err != nil {
			return nil, fmt.Errorf("failed to marshal %s count: %w", resourceType, err)
		}

		return mcp.NewToolResultText(string(jsonBytes)), nil
	}
}

```

--------------------------------------------------------------------------------
/internal/json/marshal.go:
--------------------------------------------------------------------------------

```go
package json

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/itchyny/gojq"
)

// DefaultStripPaths is a list of default paths to strip from the JSON output.
// These paths are used to remove unnecessary or sensitive information from the JSON response.
// guest_customization on VMs is massive and could contain sensitive information.
// spec and status are duplicative info and hence status can be removed.
var DefaultStripPaths = []string{
	"api_version",
	"spec.resources.guest_customization",
	"entities[].spec.resources.guest_customization",
	"entities[].status.resources.guest_customization",
}

func stripProperties(data []byte, paths []string) ([]byte, error) {
	var input interface{}
	if err := json.Unmarshal(data, &input); err != nil {
		return nil, err
	}

	// Start with identity query
	queryStr := "."

	for _, path := range paths {
		if strings.Contains(path, "[]") {
			// Handle array paths (entities[].status)
			parts := strings.Split(path, "[]")
			arrayPath := parts[0]
			fieldPath := parts[1]

			if len(fieldPath) > 0 && fieldPath[0] == '.' {
				fieldPath = fieldPath[1:] // Remove leading dot
			}

			// Correct jq syntax for modifying each element in an array
			queryStr += fmt.Sprintf(" | .%s |= map(del(.%s))", arrayPath, fieldPath)
		} else {
			// Simple path (api_version)
			queryStr += fmt.Sprintf(" | del(.%s)", path)
		}
	}

	// For debugging
	// fmt.Printf("JQ Query: %s\n", queryStr)

	query, err := gojq.Parse(queryStr)
	if err != nil {
		return nil, fmt.Errorf("jq parse error: %v for query: %s", err, queryStr)
	}

	code, err := gojq.Compile(query)
	if err != nil {
		return nil, fmt.Errorf("jq compile error: %v", err)
	}

	iter := code.Run(input)
	result, ok := iter.Next()
	if !ok {
		return nil, fmt.Errorf("jq query returned no results")
	}

	if err, ok := result.(error); ok {
		return nil, fmt.Errorf("jq execution error: %v", err)
	}

	return json.Marshal(result)
}

type CustomJSON struct {
	Value      interface{}
	StripPaths []string
}

type RegularJSON struct {
	Value interface{}
}

func CustomJSONEncoder(value any) *CustomJSON {
	return &CustomJSON{
		Value:      value,
		StripPaths: DefaultStripPaths,
	}
}

func RegularJSONEncoder(value any) *RegularJSON {
	return &RegularJSON{
		Value: value,
	}
}

func (r *RegularJSON) MarshalJSON() ([]byte, error) {
	data, err := json.Marshal(r.Value)
	if err != nil {
		return nil, err
	}

	return data, nil
}

func (d *CustomJSON) MarshalJSON() ([]byte, error) {
	data, err := json.Marshal(d.Value)
	if err != nil {
		return nil, err
	}

	return stripProperties(data, d.StripPaths)
}

```

--------------------------------------------------------------------------------
/pkg/resources/common.go:
--------------------------------------------------------------------------------

```go
package resources

import (
	"context"
	"fmt"
	"strings"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/internal/json"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// ResourceType enum for different resource types
type ResourceType string

const (
	ResourceTypeVM                  ResourceType = "vm"
	ResourceTypeSubnet              ResourceType = "subnet"
	ResourceTypeImage               ResourceType = "image"
	ResourceTypeCluster             ResourceType = "cluster"
	ResourceTypeHost                ResourceType = "host"
	ResourceTypeProject             ResourceType = "project"
	ResourceTypeVolumeGroup         ResourceType = "volumegroup"
	ResourceTypeNetworkSecurityRule ResourceType = "networksecurityrule"
	ResourceTypeServiceGroup        ResourceType = "servicegroup"
	ResourceTypeAddressGroup        ResourceType = "addressgroup"
	ResourceTypeAccessControlPolicy ResourceType = "accesscontrolpolicy"
	ResourceTypeRole                ResourceType = "role"
	ResourceTypeUser                ResourceType = "user"
	ResourceTypeUserGroup           ResourceType = "usergroup"
	ResourceTypePermission          ResourceType = "permission"
	ResourceTypeProtectionRule      ResourceType = "protectionrule"
	ResourceTypeRecoveryPlan        ResourceType = "recoveryplan"
	ResourceTypeRecoveryPlanJob     ResourceType = "recoveryplanjob"
	ResourceTypeCategory            ResourceType = "category"
	ResourceTypeCategoryValue       ResourceType = "categoryvalue"
	ResourceTypeAvailabilityZone    ResourceType = "availabilityzone"
)

// ResourceHandlerFunc defines a function that handles a specific resource get operation
type ResourceHandlerFunc func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error)

// ResourceURIPrefix returns the URI prefix for a resource type
func ResourceURIPrefix(resourceType ResourceType) string {
	return fmt.Sprintf("%s://", resourceType)
}

// NutanixURI returns a URI for a resource type and UUID
func NutanixURI(resourceType ResourceType, uuid string) string {
	return fmt.Sprintf("%s://%s", resourceType, uuid)
}

// ExtractIDFromURI extracts the UUID from a URI
// uri is expected to be in the format of resourceType://uuid
func ExtractIDFromURI(uri string) string {
	parts := strings.Split(uri, "://")
	if len(parts) != 2 {
		return ""
	}
	return parts[1]
}

// ExtractTypeFromURI extracts the resource type from a URI
// uri is expected to be in the format of resourceType://uuid
func ExtractTypeFromURI(uri string) ResourceType {
	parts := strings.Split(uri, "://")
	if len(parts) != 2 {
		return ""
	}
	return ResourceType(parts[0])
}

// CreateResourceHandler creates a generic resource handler for any Nutanix resource
func CreateResourceHandler(resourceType ResourceType, handlerFunc ResourceHandlerFunc) server.ResourceTemplateHandlerFunc {
	return func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
		uuid := ExtractIDFromURI(request.Params.URI)
		if uuid == "" {
			return nil, fmt.Errorf("URI must contain a UUID")
		}

		// Get the Prism client
		prismClient := client.GetPrismClient()
		if prismClient == nil {
			return nil, fmt.Errorf("prism client not initialized, please set credentials first")
		}

		// Call the specific resource handler
		resource, err := handlerFunc(ctx, prismClient, uuid)
		if err != nil {
			return nil, fmt.Errorf("failed to get %s: %w", resourceType, err)
		}

		// Convert to JSON
		cjson := json.CustomJSONEncoder(resource)
		jsonBytes, err := cjson.MarshalJSON()
		if err != nil {
			return nil, fmt.Errorf("failed to marshal %s details: %w", resourceType, err)
		}

		return []mcp.ResourceContents{
			&mcp.TextResourceContents{
				URI:      request.Params.URI,
				MIMEType: "application/json",
				Text:     string(jsonBytes),
			},
		}, nil
	}
}

```

--------------------------------------------------------------------------------
/internal/codegen/templates/tools.go:
--------------------------------------------------------------------------------

```go
package templates

import (
	"fmt"
	"os"
	"strings"
	"text/template"
)

// Templates for tool implementations
const toolTemplate = `package tools

import (
    "context"
    "fmt"

    "github.com/thunderboltsid/mcp-nutanix/internal/client"
    "github.com/thunderboltsid/mcp-nutanix/pkg/resources"

    "github.com/mark3labs/mcp-go/mcp"
    "github.com/mark3labs/mcp-go/server"
    "github.com/nutanix-cloud-native/prism-go-client/v3"
)

// {{.Name}} defines the {{.Name}} tool
func {{.Name}}List() mcp.Tool {
    return mcp.NewTool("{{.ResourceType}}_list",
        mcp.WithDescription("List {{.ResourceType}} resources"),
        mcp.WithString("filter",
           mcp.Description("Optional text filter (interpreted by LLM)"),
        ),
    )
}

// {{.Name}}ListHandler implements the handler for the {{.Name}} list tool
func {{.Name}}ListHandler() server.ToolHandlerFunc {
    return CreateListToolHandler(
        resources.ResourceType{{.Name}},
        // Define the ListResourceFunc implementation
        func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
            {{if eq .Name "Host"}}
            // Special case for Host which doesn't take a filter
            return client.V3().{{.ClientListAllFunc}}(ctx)
            {{else if eq .Name "Subnet"}}
            // Special case for Subnet which has an extra parameter
            return client.V3().{{.ClientListAllFunc}}(ctx, "", nil)
            {{else if eq .Name "Category"}}
            // Special case for Category which takes CategoryListMetadata
            metadata := &v3.CategoryListMetadata{}
            return client.V3().{{.ClientListFunc}}(ctx, metadata)
            {{else if .HasListAllFunc}}
            // Use ListAll function to get all resources
            return client.V3().{{.ClientListAllFunc}}(ctx, "")
            {{else}}
            // Create DSMetadata without filter
            metadata := &v3.DSMetadata{}
            
            return client.V3().{{.ClientListFunc}}(ctx, metadata)
            {{end}}
        },
    )
}

// {{.Name}}Count defines the {{.Name}} count tool
func {{.Name}}Count() mcp.Tool {
    return mcp.NewTool("{{.ResourceType}}_count",
        mcp.WithDescription("Count {{.ResourceType}} resources"),
        mcp.WithString("filter",
           mcp.Description("Optional text filter (interpreted by LLM)"),
        ),
    )
}

// {{.Name}}CountHandler implements the handler for the {{.Name}} count tool
func {{.Name}}CountHandler() server.ToolHandlerFunc {
    return CreateCountToolHandler(
        resources.ResourceType{{.Name}},
        // Define the ListResourceFunc implementation
        func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
            {{if eq .Name "Host"}}
            // Special case for Host which doesn't take a filter
            resp, err := client.V3().{{.ClientListAllFunc}}(ctx)
            {{else if eq .Name "Subnet"}}
            // Special case for Subnet which has an extra parameter
            resp, err := client.V3().{{.ClientListAllFunc}}(ctx, "", nil)
            {{else if eq .Name "Category"}}
            // Special case for Category which takes CategoryListMetadata
            metadata := &v3.CategoryListMetadata{}
            resp, err := client.V3().{{.ClientListFunc}}(ctx, metadata)
            {{else if .HasListAllFunc}}
            // Use ListAll function to get all resources
            resp, err := client.V3().{{.ClientListAllFunc}}(ctx, "")
            {{else}}
            // Create DSMetadata without filter
            metadata := &v3.DSMetadata{}
            
            resp, err := client.V3().{{.ClientListFunc}}(ctx, metadata)
            {{end}}
            if err != nil {
				return nil, err
			}

			res := map[string]interface{}{
				"resource_type": "{{.Name}}",
				"count": len(resp.Entities),
				"metadata": resp.Metadata,
        	}

			return res, nil
		},
    )
}
`

// GenerateToolFiles generates tool files for all Nutanix resources that support listing
func GenerateToolFiles(baseDir string) error {
	resources := GetResourceDefinitions()

	// Create the tools directory if it doesn't exist
	toolsDir := fmt.Sprintf("%s/pkg/tools", baseDir)
	err := os.MkdirAll(toolsDir, 0755)
	if err != nil {
		return fmt.Errorf("error creating tools directory: %w", err)
	}

	// Parse the tool template
	toolTmpl, err := template.New("tool").Parse(toolTemplate)
	if err != nil {
		return fmt.Errorf("error parsing tool template: %w", err)
	}

	// Generate tool files
	for _, res := range resources {
		// Skip resources that don't support listing
		if !res.HasListFunc && !res.HasListAllFunc {
			fmt.Printf("Skipping tool generation for %s: no list capability\n", res.Name)
			continue
		}

		// Create tool file
		toolFilePath := fmt.Sprintf("%s/%s.go", toolsDir, strings.ToLower(res.Name))
		toolFile, err := os.Create(toolFilePath)
		if err != nil {
			fmt.Printf("Error creating tool file for %s: %v\n", res.Name, err)
			continue
		}
		defer toolFile.Close()

		// Execute the template
		err = toolTmpl.Execute(toolFile, res)
		if err != nil {
			fmt.Printf("Error executing tool template for %s: %v\n", res.Name, err)
		}
	}

	return nil
}

```

--------------------------------------------------------------------------------
/internal/codegen/templates/resources.go:
--------------------------------------------------------------------------------

```go
package templates

import (
	"fmt"
	"os"
	"strings"
	"text/template"
)

// Resource defines the structure for a Nutanix resource
type Resource struct {
	Name              string
	ResourceType      string
	Description       string
	ClientGetFunc     string
	ClientListFunc    string // Regular List function with DSMetadata parameter
	ClientListAllFunc string // ListAll function with filter string parameter
	HasListFunc       bool   // Whether the service has a ListX function
	HasListAllFunc    bool   // Whether the service has a ListAllX function
}

const resourceTemplate = `package resources

import (
    "context"

    "github.com/thunderboltsid/mcp-nutanix/internal/client"

    "github.com/mark3labs/mcp-go/mcp"
    "github.com/mark3labs/mcp-go/server"
)

// {{.Name}} defines the {{.Name}} resource template
func {{.Name}}() mcp.ResourceTemplate {
    return mcp.NewResourceTemplate(
        string(ResourceURIPrefix(ResourceType{{.Name}})) + "{uuid}",
        string(ResourceType{{.Name}}),
        mcp.WithTemplateDescription("{{.Description}}"),
        mcp.WithTemplateMIMEType("application/json"),
    )
}

// {{.Name}}Handler implements the handler for the {{.Name}} resource
func {{.Name}}Handler() server.ResourceTemplateHandlerFunc {
    return CreateResourceHandler(ResourceType{{.Name}}, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
        // Get the {{.Name}}
        return client.V3().{{.ClientGetFunc}}(ctx, uuid)
    })
}
`

// GetResourceDefinitions returns all Nutanix resource definitions
func GetResourceDefinitions() []Resource {
	return []Resource{
		{
			Name:              "VM",
			ResourceType:      "vm",
			Description:       "Virtual Machine resource",
			ClientGetFunc:     "GetVM",
			ClientListFunc:    "ListVM",
			ClientListAllFunc: "ListAllVM",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "Cluster",
			ResourceType:      "cluster",
			Description:       "Cluster resource",
			ClientGetFunc:     "GetCluster",
			ClientListFunc:    "ListCluster",
			ClientListAllFunc: "ListAllCluster",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "Image",
			ResourceType:      "image",
			Description:       "Image resource",
			ClientGetFunc:     "GetImage",
			ClientListFunc:    "ListImage",
			ClientListAllFunc: "ListAllImage",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "Subnet",
			ResourceType:      "subnet",
			Description:       "Subnet resource",
			ClientGetFunc:     "GetSubnet",
			ClientListFunc:    "ListSubnet",
			ClientListAllFunc: "ListAllSubnet",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "Host",
			ResourceType:      "host",
			Description:       "Host resource",
			ClientGetFunc:     "GetHost",
			ClientListFunc:    "ListHost",
			ClientListAllFunc: "ListAllHost",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "Project",
			ResourceType:      "project",
			Description:       "Project resource",
			ClientGetFunc:     "GetProject",
			ClientListFunc:    "ListProject",
			ClientListAllFunc: "ListAllProject",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "VolumeGroup",
			ResourceType:      "volumegroup",
			Description:       "Volume Group resource",
			ClientGetFunc:     "GetVolumeGroup",
			ClientListFunc:    "ListVolumeGroup",
			ClientListAllFunc: "",
			HasListFunc:       true,
			HasListAllFunc:    false,
		},
		{
			Name:              "NetworkSecurityRule",
			ResourceType:      "networksecurityrule",
			Description:       "Network Security Rule resource",
			ClientGetFunc:     "GetNetworkSecurityRule",
			ClientListFunc:    "ListNetworkSecurityRule",
			ClientListAllFunc: "ListAllNetworkSecurityRule",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "Category",
			ResourceType:      "category",
			Description:       "Category resource",
			ClientGetFunc:     "GetCategoryKey",
			ClientListFunc:    "ListCategories",
			ClientListAllFunc: "",
			HasListFunc:       true,
			HasListAllFunc:    false,
		},
		{
			Name:              "AccessControlPolicy",
			ResourceType:      "accesscontrolpolicy",
			Description:       "Access Control Policy resource",
			ClientGetFunc:     "GetAccessControlPolicy",
			ClientListFunc:    "ListAccessControlPolicy",
			ClientListAllFunc: "ListAllAccessControlPolicy",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "Role",
			ResourceType:      "role",
			Description:       "Role resource",
			ClientGetFunc:     "GetRole",
			ClientListFunc:    "ListRole",
			ClientListAllFunc: "ListAllRole",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "User",
			ResourceType:      "user",
			Description:       "User resource",
			ClientGetFunc:     "GetUser",
			ClientListFunc:    "ListUser",
			ClientListAllFunc: "ListAllUser",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "UserGroup",
			ResourceType:      "usergroup",
			Description:       "User Group resource",
			ClientGetFunc:     "GetUserGroup",
			ClientListFunc:    "ListUserGroup",
			ClientListAllFunc: "ListAllUserGroup",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "Permission",
			ResourceType:      "permission",
			Description:       "Permission resource",
			ClientGetFunc:     "GetPermission",
			ClientListFunc:    "ListPermission",
			ClientListAllFunc: "ListAllPermission",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "ProtectionRule",
			ResourceType:      "protectionrule",
			Description:       "Protection Rule resource",
			ClientGetFunc:     "GetProtectionRule",
			ClientListFunc:    "ListProtectionRules",
			ClientListAllFunc: "ListAllProtectionRules",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "RecoveryPlan",
			ResourceType:      "recoveryplan",
			Description:       "Recovery Plan resource",
			ClientGetFunc:     "GetRecoveryPlan",
			ClientListFunc:    "ListRecoveryPlans",
			ClientListAllFunc: "ListAllRecoveryPlans",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "ServiceGroup",
			ResourceType:      "servicegroup",
			Description:       "Service Group resource",
			ClientGetFunc:     "GetServiceGroup",
			ClientListFunc:    "",
			ClientListAllFunc: "ListAllServiceGroups",
			HasListFunc:       false,
			HasListAllFunc:    true,
		},
		{
			Name:              "AddressGroup",
			ResourceType:      "addressgroup",
			Description:       "Address Group resource",
			ClientGetFunc:     "GetAddressGroup",
			ClientListFunc:    "ListAddressGroups",
			ClientListAllFunc: "ListAllAddressGroups",
			HasListFunc:       true,
			HasListAllFunc:    true,
		},
		{
			Name:              "RecoveryPlanJob",
			ResourceType:      "recoveryplanjob",
			Description:       "Recovery Plan Job resource",
			ClientGetFunc:     "GetRecoveryPlanJob",
			ClientListFunc:    "ListRecoveryPlanJobs",
			ClientListAllFunc: "",
			HasListFunc:       true,
			HasListAllFunc:    false,
		},
		{
			Name:              "AvailabilityZone",
			ResourceType:      "availabilityzone",
			Description:       "Availability Zone resource",
			ClientGetFunc:     "GetAvailabilityZone",
			ClientListFunc:    "",
			ClientListAllFunc: "",
			HasListFunc:       false,
			HasListAllFunc:    false,
		},
	}
}

// GenerateResourceFiles generates resource files for all Nutanix resources
func GenerateResourceFiles(baseDir string) error {
	resources := GetResourceDefinitions()

	// Create the resources directory if it doesn't exist
	resourcesDir := fmt.Sprintf("%s/pkg/resources", baseDir)
	err := os.MkdirAll(resourcesDir, 0755)
	if err != nil {
		return fmt.Errorf("error creating resources directory: %w", err)
	}

	// Parse the resource template
	tmpl, err := template.New("resource").Parse(resourceTemplate)
	if err != nil {
		return fmt.Errorf("error parsing resource template: %w", err)
	}

	// Generate resource files
	for _, res := range resources {
		// Create resource file
		resourceFilePath := fmt.Sprintf("%s/%s.go", resourcesDir, strings.ToLower(res.Name))
		resourceFile, err := os.Create(resourceFilePath)
		if err != nil {
			fmt.Printf("Error creating resource file for %s: %v\n", res.Name, err)
			continue
		}
		defer resourceFile.Close()

		// Execute the template
		err = tmpl.Execute(resourceFile, res)
		if err != nil {
			fmt.Printf("Error executing resource template for %s: %v\n", res.Name, err)
		}
	}

	return nil
}

```

--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------

```go
package main

import (
	"fmt"
	"os"

	"github.com/thunderboltsid/mcp-nutanix/internal/client"
	"github.com/thunderboltsid/mcp-nutanix/pkg/prompts"
	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
	"github.com/thunderboltsid/mcp-nutanix/pkg/tools"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// ToolRegistration holds a tool function and its handler
type ToolRegistration struct {
	Func    func() mcp.Tool
	Handler server.ToolHandlerFunc
}

// ResourceRegistration represents a resource and its associated tools
type ResourceRegistration struct {
	Tools           []ToolRegistration
	ResourceFunc    func() mcp.ResourceTemplate
	ResourceHandler server.ResourceTemplateHandlerFunc
}

// initializeFromEnvIfAvailable initializes the Prism client only if environment variables are available
func initializeFromEnvIfAvailable() {
	endpoint := os.Getenv("NUTANIX_ENDPOINT")
	username := os.Getenv("NUTANIX_USERNAME")
	password := os.Getenv("NUTANIX_PASSWORD")

	// Only initialize if all required environment variables are set
	// This allows prompt-based initialization to work when env vars are not present
	if endpoint != "" && username != "" && password != "" {
		client.Init(client.PrismClientProvider)
		fmt.Printf("Initialized Prism client from environment variables for endpoint: %s\n", endpoint)
	}
}

func main() {
	// Initialize the Prism client only if environment variables are available
	initializeFromEnvIfAvailable()

	// Define server hooks for logging and debugging
	hooks := &server.Hooks{}
	hooks.AddOnError(func(id any, method mcp.MCPMethod, message any, err error) {
		fmt.Printf("onError: %s, %v, %v, %v\n", method, id, message, err)
	})

	// Log level based on environment variable
	debugMode := os.Getenv("DEBUG") != ""
	if debugMode {
		hooks.AddBeforeAny(func(id any, method mcp.MCPMethod, message any) {
			fmt.Printf("beforeAny: %s, %v, %v\n", method, id, message)
		})
		hooks.AddOnSuccess(func(id any, method mcp.MCPMethod, message any, result any) {
			fmt.Printf("onSuccess: %s, %v, %v, %v\n", method, id, message, result)
		})
		hooks.AddBeforeInitialize(func(id any, message *mcp.InitializeRequest) {
			fmt.Printf("beforeInitialize: %v, %v\n", id, message)
		})
		hooks.AddAfterInitialize(func(id any, message *mcp.InitializeRequest, result *mcp.InitializeResult) {
			fmt.Printf("afterInitialize: %v, %v, %v\n", id, message, result)
		})
		hooks.AddAfterCallTool(func(id any, message *mcp.CallToolRequest, result *mcp.CallToolResult) {
			fmt.Printf("afterCallTool: %v, %v, %v\n", id, message, result)
		})
		hooks.AddBeforeCallTool(func(id any, message *mcp.CallToolRequest) {
			fmt.Printf("beforeCallTool: %v, %v\n", id, message)
		})
	}

	// Create a new MCP server
	s := server.NewMCPServer(
		"Prism Central",
		"0.0.1",
		server.WithResourceCapabilities(true, true),
		server.WithPromptCapabilities(true),
		server.WithLogging(),
		server.WithHooks(hooks),
	)

	// Add the prompts
	s.AddPrompt(prompts.SetCredentials(), prompts.SetCredentialsResponse())

	// Add standalone tools
	s.AddTool(tools.ApiNamespacesList(), tools.ApiNamespacesListHandler())

	// Define all resources and tools
	resourceRegistrations := map[string]ResourceRegistration{
		"vm": {
			Tools: []ToolRegistration{
				{
					Func:    tools.VMList,
					Handler: tools.VMListHandler(),
				},
				{
					Func:    tools.VMCount,
					Handler: tools.VMCountHandler(),
				},
			},
			ResourceFunc:    resources.VM,
			ResourceHandler: resources.VMHandler(),
		},
		"cluster": {
			Tools: []ToolRegistration{
				{
					Func:    tools.ClusterList,
					Handler: tools.ClusterListHandler(),
				},
				{
					Func:    tools.ClusterCount,
					Handler: tools.ClusterCountHandler(),
				},
			},
			ResourceFunc:    resources.Cluster,
			ResourceHandler: resources.ClusterHandler(),
		},
		"host": {
			Tools: []ToolRegistration{
				{
					Func:    tools.HostList,
					Handler: tools.HostListHandler(),
				},
				{
					Func:    tools.HostCount,
					Handler: tools.HostCountHandler(),
				},
			},
			ResourceFunc:    resources.Host,
			ResourceHandler: resources.HostHandler(),
		},
		"image": {
			Tools: []ToolRegistration{
				{
					Func:    tools.ImageList,
					Handler: tools.ImageListHandler(),
				},
				{
					Func:    tools.ImageCount,
					Handler: tools.ImageCountHandler(),
				},
			},
			ResourceFunc:    resources.Image,
			ResourceHandler: resources.ImageHandler(),
		},
		"subnet": {
			Tools: []ToolRegistration{
				{
					Func:    tools.SubnetList,
					Handler: tools.SubnetListHandler(),
				},
				{
					Func:    tools.SubnetCount,
					Handler: tools.SubnetCountHandler(),
				},
			},
			ResourceFunc:    resources.Subnet,
			ResourceHandler: resources.SubnetHandler(),
		},
		"project": {
			Tools: []ToolRegistration{
				{
					Func:    tools.ProjectList,
					Handler: tools.ProjectListHandler(),
				},
				{
					Func:    tools.ProjectCount,
					Handler: tools.ProjectCountHandler(),
				},
			},
			ResourceFunc:    resources.Project,
			ResourceHandler: resources.ProjectHandler(),
		},
		"volumegroup": {
			Tools: []ToolRegistration{
				{
					Func:    tools.VolumeGroupList,
					Handler: tools.VolumeGroupListHandler(),
				},
				{
					Func:    tools.VolumeGroupCount,
					Handler: tools.VolumeGroupCountHandler(),
				},
			},
			ResourceFunc:    resources.VolumeGroup,
			ResourceHandler: resources.VolumeGroupHandler(),
		},
		"networksecurityrule": {
			Tools: []ToolRegistration{
				{
					Func:    tools.NetworkSecurityRuleList,
					Handler: tools.NetworkSecurityRuleListHandler(),
				},
				{
					Func:    tools.NetworkSecurityRuleCount,
					Handler: tools.NetworkSecurityRuleCountHandler(),
				},
			},
			ResourceFunc:    resources.NetworkSecurityRule,
			ResourceHandler: resources.NetworkSecurityRuleHandler(),
		},
		"category": {
			Tools: []ToolRegistration{
				{
					Func:    tools.CategoryList,
					Handler: tools.CategoryListHandler(),
				},
				{
					Func:    tools.CategoryCount,
					Handler: tools.CategoryCountHandler(),
				},
			},
			ResourceFunc:    resources.Category,
			ResourceHandler: resources.CategoryHandler(),
		},
		"accesscontrolpolicy": {
			Tools: []ToolRegistration{
				{
					Func:    tools.AccessControlPolicyList,
					Handler: tools.AccessControlPolicyListHandler(),
				},
				{
					Func:    tools.AccessControlPolicyCount,
					Handler: tools.AccessControlPolicyCountHandler(),
				},
			},
			ResourceFunc:    resources.AccessControlPolicy,
			ResourceHandler: resources.AccessControlPolicyHandler(),
		},
		"role": {
			Tools: []ToolRegistration{
				{
					Func:    tools.RoleList,
					Handler: tools.RoleListHandler(),
				},
				{
					Func:    tools.RoleCount,
					Handler: tools.RoleCountHandler(),
				},
			},
			ResourceFunc:    resources.Role,
			ResourceHandler: resources.RoleHandler(),
		},
		"user": {
			Tools: []ToolRegistration{
				{
					Func:    tools.UserList,
					Handler: tools.UserListHandler(),
				},
				{
					Func:    tools.UserCount,
					Handler: tools.UserCountHandler(),
				},
			},
			ResourceFunc:    resources.User,
			ResourceHandler: resources.UserHandler(),
		},
		"usergroup": {
			Tools: []ToolRegistration{
				{
					Func:    tools.UserGroupList,
					Handler: tools.UserGroupListHandler(),
				},
				{
					Func:    tools.UserGroupCount,
					Handler: tools.UserGroupCountHandler(),
				},
			},
			ResourceFunc:    resources.UserGroup,
			ResourceHandler: resources.UserGroupHandler(),
		},
		"permission": {
			Tools: []ToolRegistration{
				{
					Func:    tools.PermissionList,
					Handler: tools.PermissionListHandler(),
				},
				{
					Func:    tools.PermissionCount,
					Handler: tools.PermissionCountHandler(),
				},
			},
			ResourceFunc:    resources.Permission,
			ResourceHandler: resources.PermissionHandler(),
		},
		"protectionrule": {
			Tools: []ToolRegistration{
				{
					Func:    tools.ProtectionRuleList,
					Handler: tools.ProtectionRuleListHandler(),
				},
				{
					Func:    tools.ProtectionRuleCount,
					Handler: tools.ProtectionRuleCountHandler(),
				},
			},
			ResourceFunc:    resources.ProtectionRule,
			ResourceHandler: resources.ProtectionRuleHandler(),
		},
		"recoveryplan": {
			Tools: []ToolRegistration{
				{
					Func:    tools.RecoveryPlanList,
					Handler: tools.RecoveryPlanListHandler(),
				},
				{
					Func:    tools.RecoveryPlanCount,
					Handler: tools.RecoveryPlanCountHandler(),
				},
			},
			ResourceFunc:    resources.RecoveryPlan,
			ResourceHandler: resources.RecoveryPlanHandler(),
		},
		"servicegroup": {
			Tools: []ToolRegistration{
				{
					Func:    tools.ServiceGroupList,
					Handler: tools.ServiceGroupListHandler(),
				},
				{
					Func:    tools.ServiceGroupCount,
					Handler: tools.ServiceGroupCountHandler(),
				},
			},
			ResourceFunc:    resources.ServiceGroup,
			ResourceHandler: resources.ServiceGroupHandler(),
		},
		"addressgroup": {
			Tools: []ToolRegistration{
				{
					Func:    tools.AddressGroupList,
					Handler: tools.AddressGroupListHandler(),
				},
				{
					Func:    tools.AddressGroupCount,
					Handler: tools.AddressGroupCountHandler(),
				},
			},
			ResourceFunc:    resources.AddressGroup,
			ResourceHandler: resources.AddressGroupHandler(),
		},
		"recoveryplanjob": {
			Tools: []ToolRegistration{
				{
					Func:    tools.RecoveryPlanJobList,
					Handler: tools.RecoveryPlanJobListHandler(),
				},
				{
					Func:    tools.RecoveryPlanJobCount,
					Handler: tools.RecoveryPlanJobCountHandler(),
				},
			},
			ResourceFunc:    resources.RecoveryPlanJob,
			ResourceHandler: resources.RecoveryPlanJobHandler(),
		},
	}

	// Register all tools and resources
	for name, registration := range resourceRegistrations {
		// Add all tools
		for _, tool := range registration.Tools {
			s.AddTool(tool.Func(), tool.Handler)
			if debugMode {
				fmt.Printf("Registered %s resource and tool\n", name)
			}
		}

		// Add the resource
		s.AddResourceTemplate(registration.ResourceFunc(), registration.ResourceHandler)
	}

	// Start the server
	if err := server.ServeStdio(s); err != nil {
		fmt.Printf("Server error: %v\n", err)
	}
}

```