#
tokens: 35833/50000 53/53 files
lines: on (toggle) GitHub
raw markdown copy reset
# 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:
--------------------------------------------------------------------------------

```
1 | bin
2 | .DS_Store
3 | mcp.json
4 | 
```

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

```markdown
  1 | # MCP Nutanix
  2 | 
  3 | A Model Context Protocol (MCP) server for interacting with Nutanix Prism Central APIs through Large Language Models (LLMs).
  4 | 
  5 | ## ⚠️ Disclaimer
  6 | 
  7 | **THIS IS AN EXPERIMENTAL PROJECT**
  8 | 
  9 | This project was created as a personal project to explore the capabilities of the Model Context Protocol frameworks in Go. It is:
 10 | 
 11 | - **NOT** an official Nutanix product or tool
 12 | - **NOT** supported, endorsed, or maintained by Nutanix
 13 | - **NOT** suitable for production environments
 14 | - **PROVIDED AS-IS** with no warranties or guarantees
 15 | 
 16 | **USE AT YOUR OWN RISK**: The author takes no responsibility for any issues, damages, or outages that may result from using this code.
 17 | 
 18 | ## Overview
 19 | 
 20 | This MCP server allows LLMs to interact with Nutanix Prism Central by:
 21 | 
 22 | 1. Connecting to a Prism Central instance with user credentials
 23 | 2. Listing various resources (VMs, Clusters, Hosts, etc.)
 24 | 3. Retrieving specific resource details via URI-based access
 25 | 
 26 | 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.
 27 | 
 28 | ## Getting Started
 29 | 
 30 | ### Prerequisites
 31 | 
 32 | - Go 1.23 or higher
 33 | - Access to a Nutanix Prism Central instance
 34 | - Tools like `make` and `go fmt` for building
 35 | 
 36 | ### Building
 37 | 
 38 | ```bash
 39 | # Clone the repository
 40 | git clone https://github.com/thunderboltsid/mcp-nutanix.git
 41 | cd mcp-nutanix
 42 | 
 43 | # Build the MCP server
 44 | make build
 45 | ```
 46 | 
 47 | ## Credential Configuration
 48 | 
 49 | The server supports two credential methods:
 50 | 
 51 | 1. **Interactive credentials** (default) - Works with Claude via MCP prompts
 52 | 2. **Static credentials** - Required for tools like Cursor that don't support interactive prompts
 53 | 
 54 | ## MCP Client Configuration
 55 | 
 56 | To use this server with MCP clients, you need to configure the client to connect to the server.
 57 | 
 58 | ### Claude Desktop/Code
 59 | 
 60 | Create or update `~/.anthropic/claude_desktop.json`:
 61 | 
 62 | ```json
 63 | {
 64 |   "mcpServers": {
 65 |     "nutanix": {
 66 |       "command": "/path/to/mcp-nutanix"
 67 |     }
 68 |   }
 69 | }
 70 | ```
 71 | 
 72 | Claude will prompt you for credentials when first using the server.
 73 | 
 74 | ### Cursor
 75 | 
 76 | For Cursor, you need to provide static credentials via environment variables since it doesn't support interactive prompts.
 77 | 
 78 | Create or update `~/.cursor/mcp.json`:
 79 | 
 80 | ```json
 81 | {
 82 |   "mcpServers": {
 83 |     "nutanix": {
 84 |       "command": "/path/to/mcp-nutanix",
 85 |       "env": {
 86 |         "NUTANIX_ENDPOINT": "your-prism-central-ip-or-hostname",
 87 |         "NUTANIX_USERNAME": "your-username", 
 88 |         "NUTANIX_PASSWORD": "your-password",
 89 |         "NUTANIX_INSECURE": "true"
 90 |       }
 91 |     }
 92 |   }
 93 | }
 94 | ```
 95 | 
 96 | **Environment Variables:**
 97 | - `NUTANIX_ENDPOINT` - Prism Central IP or hostname (required)
 98 | - `NUTANIX_USERNAME` - API username (required)
 99 | - `NUTANIX_PASSWORD` - API password (required)
100 | - `NUTANIX_INSECURE` - Set to "true" for self-signed certificates (optional)
101 | 
102 | ### Other MCP Clients
103 | 
104 | 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.
105 | 
106 | ## Usage
107 | 
108 | 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.
109 | 
110 | ### Resource Listing
111 | 
112 | To list resources, use the appropriate tool:
113 | 
114 | ```
115 | vms
116 | clusters
117 | hosts
118 | images
119 | subnets
120 | ```
121 | 
122 | The LLM will receive a JSON list of resources that it can parse and analyze.
123 | 
124 | ### Resource Access
125 | 
126 | To access a specific resource, use a resource URI:
127 | 
128 | ```
129 | vm://{uuid}
130 | cluster://{uuid}
131 | host://{uuid}
132 | ```
133 | 
134 | The LLM will receive detailed JSON information about the specific resource.
135 | 
136 | ## Development
137 | 
138 | ### Project Structure
139 | 
140 | ```
141 | mcp-nutanix/
142 | ├── bin/                  # Compiled binaries
143 | ├── internal/             # Internal packages
144 | │   ├── client/           # Prism Central client handling
145 | │   ├── codegen/          # Code generation utilities
146 | │   └── json/             # JSON helpers
147 | ├── pkg/                  # components
148 | │   ├── prompts/          # MCP prompt implementations
149 | │   ├── resources/        # Resource handlers
150 | │   └── tools/            # Tool handlers
151 | └── Makefile              # Build and utility commands
152 | ```
153 | 
154 | ### Code Generation
155 | 
156 | The project uses code generation to create resource and tool handlers. To update these:
157 | 
158 | ```bash
159 | make generate
160 | ```
161 | 
162 | ## Limitations
163 | 
164 | - Response size is limited by the MCP protocol
165 | - Some resources with large response sizes may cause errors
166 | - No pagination support in the current implementation
167 | - Only supports read operations, no create/update/delete
168 | 
169 | ## License
170 | 
171 | This project is licensed under the MIT License - see the LICENSE file for details.
172 | 
173 | ## Acknowledgments
174 | 
175 | - [Nutanix](https://www.nutanix.com/) for creating the Prism API
176 | - [Mark3Labs](https://github.com/mark3labs) for the MCP Go library
177 | - [Nutanix Cloud Native](https://github.com/nutanix-cloud-native) for the Prism Go Client
178 | 
179 | ## Contributing
180 | 
181 | This is an experimental project with no formal contribution process. Feel free to create issues or pull requests.
182 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // VM defines the VM resource template
13 | func VM() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeVM))+"{uuid}",
16 | 		string(ResourceTypeVM),
17 | 		mcp.WithTemplateDescription("Virtual Machine resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // VMHandler implements the handler for the VM resource
23 | func VMHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeVM, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the VM
26 | 		return client.V3().GetVM(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // Host defines the Host resource template
13 | func Host() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeHost))+"{uuid}",
16 | 		string(ResourceTypeHost),
17 | 		mcp.WithTemplateDescription("Host resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // HostHandler implements the handler for the Host resource
23 | func HostHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeHost, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the Host
26 | 		return client.V3().GetHost(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // Role defines the Role resource template
13 | func Role() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeRole))+"{uuid}",
16 | 		string(ResourceTypeRole),
17 | 		mcp.WithTemplateDescription("Role resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // RoleHandler implements the handler for the Role resource
23 | func RoleHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeRole, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the Role
26 | 		return client.V3().GetRole(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // User defines the User resource template
13 | func User() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeUser))+"{uuid}",
16 | 		string(ResourceTypeUser),
17 | 		mcp.WithTemplateDescription("User resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // UserHandler implements the handler for the User resource
23 | func UserHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeUser, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the User
26 | 		return client.V3().GetUser(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // Image defines the Image resource template
13 | func Image() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeImage))+"{uuid}",
16 | 		string(ResourceTypeImage),
17 | 		mcp.WithTemplateDescription("Image resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // ImageHandler implements the handler for the Image resource
23 | func ImageHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeImage, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the Image
26 | 		return client.V3().GetImage(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // Subnet defines the Subnet resource template
13 | func Subnet() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeSubnet))+"{uuid}",
16 | 		string(ResourceTypeSubnet),
17 | 		mcp.WithTemplateDescription("Subnet resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // SubnetHandler implements the handler for the Subnet resource
23 | func SubnetHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeSubnet, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the Subnet
26 | 		return client.V3().GetSubnet(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // Cluster defines the Cluster resource template
13 | func Cluster() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeCluster))+"{uuid}",
16 | 		string(ResourceTypeCluster),
17 | 		mcp.WithTemplateDescription("Cluster resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // ClusterHandler implements the handler for the Cluster resource
23 | func ClusterHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeCluster, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the Cluster
26 | 		return client.V3().GetCluster(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // Project defines the Project resource template
13 | func Project() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeProject))+"{uuid}",
16 | 		string(ResourceTypeProject),
17 | 		mcp.WithTemplateDescription("Project resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // ProjectHandler implements the handler for the Project resource
23 | func ProjectHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeProject, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the Project
26 | 		return client.V3().GetProject(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // Category defines the Category resource template
13 | func Category() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeCategory))+"{uuid}",
16 | 		string(ResourceTypeCategory),
17 | 		mcp.WithTemplateDescription("Category resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // CategoryHandler implements the handler for the Category resource
23 | func CategoryHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeCategory, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the Category
26 | 		return client.V3().GetCategoryKey(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // UserGroup defines the UserGroup resource template
13 | func UserGroup() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeUserGroup))+"{uuid}",
16 | 		string(ResourceTypeUserGroup),
17 | 		mcp.WithTemplateDescription("User Group resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // UserGroupHandler implements the handler for the UserGroup resource
23 | func UserGroupHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeUserGroup, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the UserGroup
26 | 		return client.V3().GetUserGroup(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // Permission defines the Permission resource template
13 | func Permission() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypePermission))+"{uuid}",
16 | 		string(ResourceTypePermission),
17 | 		mcp.WithTemplateDescription("Permission resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // PermissionHandler implements the handler for the Permission resource
23 | func PermissionHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypePermission, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the Permission
26 | 		return client.V3().GetPermission(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // VolumeGroup defines the VolumeGroup resource template
13 | func VolumeGroup() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeVolumeGroup))+"{uuid}",
16 | 		string(ResourceTypeVolumeGroup),
17 | 		mcp.WithTemplateDescription("Volume Group resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // VolumeGroupHandler implements the handler for the VolumeGroup resource
23 | func VolumeGroupHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeVolumeGroup, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the VolumeGroup
26 | 		return client.V3().GetVolumeGroup(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // AddressGroup defines the AddressGroup resource template
13 | func AddressGroup() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeAddressGroup))+"{uuid}",
16 | 		string(ResourceTypeAddressGroup),
17 | 		mcp.WithTemplateDescription("Address Group resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // AddressGroupHandler implements the handler for the AddressGroup resource
23 | func AddressGroupHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeAddressGroup, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the AddressGroup
26 | 		return client.V3().GetAddressGroup(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // RecoveryPlan defines the RecoveryPlan resource template
13 | func RecoveryPlan() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeRecoveryPlan))+"{uuid}",
16 | 		string(ResourceTypeRecoveryPlan),
17 | 		mcp.WithTemplateDescription("Recovery Plan resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // RecoveryPlanHandler implements the handler for the RecoveryPlan resource
23 | func RecoveryPlanHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeRecoveryPlan, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the RecoveryPlan
26 | 		return client.V3().GetRecoveryPlan(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // ServiceGroup defines the ServiceGroup resource template
13 | func ServiceGroup() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeServiceGroup))+"{uuid}",
16 | 		string(ResourceTypeServiceGroup),
17 | 		mcp.WithTemplateDescription("Service Group resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // ServiceGroupHandler implements the handler for the ServiceGroup resource
23 | func ServiceGroupHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeServiceGroup, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the ServiceGroup
26 | 		return client.V3().GetServiceGroup(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package main
 2 | 
 3 | import (
 4 | 	"flag"
 5 | 	"fmt"
 6 | 	"os"
 7 | 	"path/filepath"
 8 | 
 9 | 	"github.com/thunderboltsid/mcp-nutanix/internal/codegen/templates"
10 | )
11 | 
12 | func main() {
13 | 	// Parse command-line arguments
14 | 	outputDir := flag.String("output", ".", "Output directory for generated files")
15 | 	flag.Parse()
16 | 
17 | 	// Get absolute path
18 | 	absPath, err := filepath.Abs(*outputDir)
19 | 	if err != nil {
20 | 		fmt.Printf("Error getting absolute path: %v\n", err)
21 | 		os.Exit(1)
22 | 	}
23 | 
24 | 	fmt.Printf("Generating resource and tool files in: %s\n", absPath)
25 | 
26 | 	// Generate all resource files
27 | 	if err := templates.GenerateResourceFiles(absPath); err != nil {
28 | 		fmt.Printf("Error generating files: %v\n", err)
29 | 		os.Exit(1)
30 | 	}
31 | 
32 | 	// Generate all resource files
33 | 	if err := templates.GenerateToolFiles(absPath); err != nil {
34 | 		fmt.Printf("Error generating files: %v\n", err)
35 | 		os.Exit(1)
36 | 	}
37 | 
38 | 	fmt.Println("Resource and tool files generated successfully!")
39 | }
40 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // ProtectionRule defines the ProtectionRule resource template
13 | func ProtectionRule() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeProtectionRule))+"{uuid}",
16 | 		string(ResourceTypeProtectionRule),
17 | 		mcp.WithTemplateDescription("Protection Rule resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // ProtectionRuleHandler implements the handler for the ProtectionRule resource
23 | func ProtectionRuleHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeProtectionRule, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the ProtectionRule
26 | 		return client.V3().GetProtectionRule(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // RecoveryPlanJob defines the RecoveryPlanJob resource template
13 | func RecoveryPlanJob() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeRecoveryPlanJob))+"{uuid}",
16 | 		string(ResourceTypeRecoveryPlanJob),
17 | 		mcp.WithTemplateDescription("Recovery Plan Job resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // RecoveryPlanJobHandler implements the handler for the RecoveryPlanJob resource
23 | func RecoveryPlanJobHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeRecoveryPlanJob, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the RecoveryPlanJob
26 | 		return client.V3().GetRecoveryPlanJob(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // AvailabilityZone defines the AvailabilityZone resource template
13 | func AvailabilityZone() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeAvailabilityZone))+"{uuid}",
16 | 		string(ResourceTypeAvailabilityZone),
17 | 		mcp.WithTemplateDescription("Availability Zone resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // AvailabilityZoneHandler implements the handler for the AvailabilityZone resource
23 | func AvailabilityZoneHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeAvailabilityZone, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the AvailabilityZone
26 | 		return client.V3().GetAvailabilityZone(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // AccessControlPolicy defines the AccessControlPolicy resource template
13 | func AccessControlPolicy() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeAccessControlPolicy))+"{uuid}",
16 | 		string(ResourceTypeAccessControlPolicy),
17 | 		mcp.WithTemplateDescription("Access Control Policy resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // AccessControlPolicyHandler implements the handler for the AccessControlPolicy resource
23 | func AccessControlPolicyHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeAccessControlPolicy, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the AccessControlPolicy
26 | 		return client.V3().GetAccessControlPolicy(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package resources
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 
 8 | 	"github.com/mark3labs/mcp-go/mcp"
 9 | 	"github.com/mark3labs/mcp-go/server"
10 | )
11 | 
12 | // NetworkSecurityRule defines the NetworkSecurityRule resource template
13 | func NetworkSecurityRule() mcp.ResourceTemplate {
14 | 	return mcp.NewResourceTemplate(
15 | 		string(ResourceURIPrefix(ResourceTypeNetworkSecurityRule))+"{uuid}",
16 | 		string(ResourceTypeNetworkSecurityRule),
17 | 		mcp.WithTemplateDescription("Network Security Rule resource"),
18 | 		mcp.WithTemplateMIMEType("application/json"),
19 | 	)
20 | }
21 | 
22 | // NetworkSecurityRuleHandler implements the handler for the NetworkSecurityRule resource
23 | func NetworkSecurityRuleHandler() server.ResourceTemplateHandlerFunc {
24 | 	return CreateResourceHandler(ResourceTypeNetworkSecurityRule, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
25 | 		// Get the NetworkSecurityRule
26 | 		return client.V3().GetNetworkSecurityRule(ctx, uuid)
27 | 	})
28 | }
29 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/internal/json"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // ApiNamespacesList defines the API namespaces list tool
14 | func ApiNamespacesList() mcp.Tool {
15 | 	return mcp.NewTool("api_namespaces_list",
16 | 		mcp.WithDescription("List available API namespaces and their routes in Prism Central"),
17 | 	)
18 | }
19 | 
20 | // ApiNamespacesListHandler implements the handler for the API namespaces list tool
21 | func ApiNamespacesListHandler() server.ToolHandlerFunc {
22 | 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
23 | 		// Get the Prism client
24 | 		prismClient := client.GetPrismClient()
25 | 
26 | 		// Call the Actuator API to get version routes
27 | 		response, err := prismClient.V4().ActuatorApiInstance.GetVersionRoutes(ctx)
28 | 		if err != nil {
29 | 			return nil, err
30 | 		}
31 | 
32 | 		// Convert to JSON using regular JSON encoder
33 | 		cjson := json.RegularJSONEncoder(response)
34 | 		jsonBytes, err := cjson.MarshalJSON()
35 | 		if err != nil {
36 | 			return nil, err
37 | 		}
38 | 
39 | 		return mcp.NewToolResultText(string(jsonBytes)), nil
40 | 	}
41 | }
42 | 
```

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

```go
 1 | package client
 2 | 
 3 | import (
 4 | 	"errors"
 5 | 	"sync"
 6 | 
 7 | 	"github.com/nutanix-cloud-native/prism-go-client/environment/providers/mcp"
 8 | )
 9 | 
10 | // mcpModelContextClient is an example implementation of ModelContextClient.
11 | // It stores key–value pairs in an in-memory map.
12 | type mcpModelContextClient struct {
13 | 	mu   sync.RWMutex
14 | 	data map[string]string
15 | }
16 | 
17 | var PrismClientProvider = &mcpModelContextClient{
18 | 	data: make(map[string]string),
19 | }
20 | 
21 | var _ mcp.ModelContextClient = &mcpModelContextClient{}
22 | 
23 | // NewMCPModelContextClient creates a new instance with the provided initial data.
24 | func NewMCPModelContextClient(initialData map[string]string) mcp.ModelContextClient {
25 | 	if initialData == nil {
26 | 		initialData = make(map[string]string)
27 | 	}
28 | 
29 | 	return &mcpModelContextClient{
30 | 		data: initialData,
31 | 	}
32 | }
33 | 
34 | // GetValue retrieves the value for a given key from the model context.
35 | // It returns an error if the key is not found.
36 | func (c *mcpModelContextClient) GetValue(key string) (string, error) {
37 | 	c.mu.RLock()
38 | 	defer c.mu.RUnlock()
39 | 	if val, exists := c.data[key]; exists {
40 | 		return val, nil
41 | 	}
42 | 	return "", errors.New("model context key not found")
43 | }
44 | 
45 | // Optionally, you can add a method to update values in the model context.
46 | func (c *mcpModelContextClient) UpdateValue(key, value string) {
47 | 	c.mu.Lock()
48 | 	defer c.mu.Unlock()
49 | 	c.data[key] = value
50 | }
51 | 
```

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

```go
 1 | package json
 2 | 
 3 | import (
 4 | 	"encoding/json"
 5 | 	"github.com/stretchr/testify/assert"
 6 | 	"testing"
 7 | )
 8 | 
 9 | func TestMarshalJSON(t *testing.T) {
10 | 	jsonData := []byte(`
11 |     {
12 |         "api_version": "3.0",
13 |         "entities": [
14 |             {
15 |                 "metadata": {"uuid": "b7816400-16c5-47c7-9fcc-474e39594ad5"},
16 |                 "status": {"big": "object"},
17 |                 "spec": {
18 |                     "name": "vm1",
19 | 					"resources": {
20 |                         "guest_customization": {"very": "large", "nested": "object"},
21 |                         "subnets": [{"name": "subnet1"}, {"name": "subnet2"}]
22 |                     }
23 |                 }
24 |             },
25 |             {
26 |                 "metadata": {"uuid": "b7816400-16c5-47c7-9fcc-474e39594ad6"},
27 |                 "status": {"big": "object2"},
28 |                 "spec": {
29 |                     "name": "vm2",
30 | 					"resources": {
31 |                         "guest_customization": {"very": "large", "nested": "object"},
32 |                         "subnets": [{"name": "subnet1"}, {"name": "subnet2"}]
33 |                     }
34 |                 }
35 |             }
36 |         ]
37 |     }`)
38 | 	ujson := make(map[string]any)
39 | 	err := json.Unmarshal(jsonData, &ujson)
40 | 	assert.NoError(t, err)
41 | 
42 | 	cjson := CustomJSON{
43 | 		Value: ujson,
44 | 		StripPaths: []string{
45 | 			"api_version",
46 | 			"entities[].status",
47 | 			"spec.resources.guest_customization",
48 | 			"entities[].spec.resources.guest_customization",
49 | 		},
50 | 	}
51 | 
52 | 	mdata, err := json.Marshal(cjson)
53 | 	assert.NoError(t, err)
54 | 	assert.NotNil(t, mdata)
55 | }
56 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // VM defines the VM tool
14 | func VMList() mcp.Tool {
15 | 	return mcp.NewTool("vm_list",
16 | 		mcp.WithDescription("List vm resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // VMListHandler implements the handler for the VM list tool
24 | func VMListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeVM,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllVM(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // VMCount defines the VM count tool
38 | func VMCount() mcp.Tool {
39 | 	return mcp.NewTool("vm_count",
40 | 		mcp.WithDescription("Count vm resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // VMCountHandler implements the handler for the VM count tool
48 | func VMCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeVM,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllVM(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "VM",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // Role defines the Role tool
14 | func RoleList() mcp.Tool {
15 | 	return mcp.NewTool("role_list",
16 | 		mcp.WithDescription("List role resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // RoleListHandler implements the handler for the Role list tool
24 | func RoleListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeRole,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllRole(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // RoleCount defines the Role count tool
38 | func RoleCount() mcp.Tool {
39 | 	return mcp.NewTool("role_count",
40 | 		mcp.WithDescription("Count role resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // RoleCountHandler implements the handler for the Role count tool
48 | func RoleCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeRole,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllRole(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "Role",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // User defines the User tool
14 | func UserList() mcp.Tool {
15 | 	return mcp.NewTool("user_list",
16 | 		mcp.WithDescription("List user resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // UserListHandler implements the handler for the User list tool
24 | func UserListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeUser,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllUser(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // UserCount defines the User count tool
38 | func UserCount() mcp.Tool {
39 | 	return mcp.NewTool("user_count",
40 | 		mcp.WithDescription("Count user resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // UserCountHandler implements the handler for the User count tool
48 | func UserCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeUser,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllUser(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "User",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // Host defines the Host tool
14 | func HostList() mcp.Tool {
15 | 	return mcp.NewTool("host_list",
16 | 		mcp.WithDescription("List host resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // HostListHandler implements the handler for the Host list tool
24 | func HostListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeHost,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Special case for Host which doesn't take a filter
31 | 			return client.V3().ListAllHost(ctx)
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // HostCount defines the Host count tool
38 | func HostCount() mcp.Tool {
39 | 	return mcp.NewTool("host_count",
40 | 		mcp.WithDescription("Count host resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // HostCountHandler implements the handler for the Host count tool
48 | func HostCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeHost,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Special case for Host which doesn't take a filter
55 | 			resp, err := client.V3().ListAllHost(ctx)
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "Host",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // Image defines the Image tool
14 | func ImageList() mcp.Tool {
15 | 	return mcp.NewTool("image_list",
16 | 		mcp.WithDescription("List image resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // ImageListHandler implements the handler for the Image list tool
24 | func ImageListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeImage,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllImage(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // ImageCount defines the Image count tool
38 | func ImageCount() mcp.Tool {
39 | 	return mcp.NewTool("image_count",
40 | 		mcp.WithDescription("Count image resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // ImageCountHandler implements the handler for the Image count tool
48 | func ImageCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeImage,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllImage(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "Image",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // Cluster defines the Cluster tool
14 | func ClusterList() mcp.Tool {
15 | 	return mcp.NewTool("cluster_list",
16 | 		mcp.WithDescription("List cluster resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // ClusterListHandler implements the handler for the Cluster list tool
24 | func ClusterListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeCluster,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllCluster(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // ClusterCount defines the Cluster count tool
38 | func ClusterCount() mcp.Tool {
39 | 	return mcp.NewTool("cluster_count",
40 | 		mcp.WithDescription("Count cluster resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // ClusterCountHandler implements the handler for the Cluster count tool
48 | func ClusterCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeCluster,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllCluster(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "Cluster",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // Project defines the Project tool
14 | func ProjectList() mcp.Tool {
15 | 	return mcp.NewTool("project_list",
16 | 		mcp.WithDescription("List project resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // ProjectListHandler implements the handler for the Project list tool
24 | func ProjectListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeProject,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllProject(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // ProjectCount defines the Project count tool
38 | func ProjectCount() mcp.Tool {
39 | 	return mcp.NewTool("project_count",
40 | 		mcp.WithDescription("Count project resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // ProjectCountHandler implements the handler for the Project count tool
48 | func ProjectCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeProject,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllProject(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "Project",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // Subnet defines the Subnet tool
14 | func SubnetList() mcp.Tool {
15 | 	return mcp.NewTool("subnet_list",
16 | 		mcp.WithDescription("List subnet resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // SubnetListHandler implements the handler for the Subnet list tool
24 | func SubnetListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeSubnet,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Special case for Subnet which has an extra parameter
31 | 			return client.V3().ListAllSubnet(ctx, "", nil)
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // SubnetCount defines the Subnet count tool
38 | func SubnetCount() mcp.Tool {
39 | 	return mcp.NewTool("subnet_count",
40 | 		mcp.WithDescription("Count subnet resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // SubnetCountHandler implements the handler for the Subnet count tool
48 | func SubnetCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeSubnet,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Special case for Subnet which has an extra parameter
55 | 			resp, err := client.V3().ListAllSubnet(ctx, "", nil)
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "Subnet",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // UserGroup defines the UserGroup tool
14 | func UserGroupList() mcp.Tool {
15 | 	return mcp.NewTool("usergroup_list",
16 | 		mcp.WithDescription("List usergroup resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // UserGroupListHandler implements the handler for the UserGroup list tool
24 | func UserGroupListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeUserGroup,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllUserGroup(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // UserGroupCount defines the UserGroup count tool
38 | func UserGroupCount() mcp.Tool {
39 | 	return mcp.NewTool("usergroup_count",
40 | 		mcp.WithDescription("Count usergroup resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // UserGroupCountHandler implements the handler for the UserGroup count tool
48 | func UserGroupCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeUserGroup,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllUserGroup(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "UserGroup",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // Permission defines the Permission tool
14 | func PermissionList() mcp.Tool {
15 | 	return mcp.NewTool("permission_list",
16 | 		mcp.WithDescription("List permission resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // PermissionListHandler implements the handler for the Permission list tool
24 | func PermissionListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypePermission,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllPermission(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // PermissionCount defines the Permission count tool
38 | func PermissionCount() mcp.Tool {
39 | 	return mcp.NewTool("permission_count",
40 | 		mcp.WithDescription("Count permission resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // PermissionCountHandler implements the handler for the Permission count tool
48 | func PermissionCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypePermission,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllPermission(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "Permission",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // AddressGroup defines the AddressGroup tool
14 | func AddressGroupList() mcp.Tool {
15 | 	return mcp.NewTool("addressgroup_list",
16 | 		mcp.WithDescription("List addressgroup resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // AddressGroupListHandler implements the handler for the AddressGroup list tool
24 | func AddressGroupListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeAddressGroup,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllAddressGroups(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // AddressGroupCount defines the AddressGroup count tool
38 | func AddressGroupCount() mcp.Tool {
39 | 	return mcp.NewTool("addressgroup_count",
40 | 		mcp.WithDescription("Count addressgroup resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // AddressGroupCountHandler implements the handler for the AddressGroup count tool
48 | func AddressGroupCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeAddressGroup,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllAddressGroups(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "AddressGroup",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // RecoveryPlan defines the RecoveryPlan tool
14 | func RecoveryPlanList() mcp.Tool {
15 | 	return mcp.NewTool("recoveryplan_list",
16 | 		mcp.WithDescription("List recoveryplan resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // RecoveryPlanListHandler implements the handler for the RecoveryPlan list tool
24 | func RecoveryPlanListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeRecoveryPlan,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllRecoveryPlans(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // RecoveryPlanCount defines the RecoveryPlan count tool
38 | func RecoveryPlanCount() mcp.Tool {
39 | 	return mcp.NewTool("recoveryplan_count",
40 | 		mcp.WithDescription("Count recoveryplan resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // RecoveryPlanCountHandler implements the handler for the RecoveryPlan count tool
48 | func RecoveryPlanCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeRecoveryPlan,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllRecoveryPlans(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "RecoveryPlan",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // ServiceGroup defines the ServiceGroup tool
14 | func ServiceGroupList() mcp.Tool {
15 | 	return mcp.NewTool("servicegroup_list",
16 | 		mcp.WithDescription("List servicegroup resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // ServiceGroupListHandler implements the handler for the ServiceGroup list tool
24 | func ServiceGroupListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeServiceGroup,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllServiceGroups(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // ServiceGroupCount defines the ServiceGroup count tool
38 | func ServiceGroupCount() mcp.Tool {
39 | 	return mcp.NewTool("servicegroup_count",
40 | 		mcp.WithDescription("Count servicegroup resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // ServiceGroupCountHandler implements the handler for the ServiceGroup count tool
48 | func ServiceGroupCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeServiceGroup,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllServiceGroups(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "ServiceGroup",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // ProtectionRule defines the ProtectionRule tool
14 | func ProtectionRuleList() mcp.Tool {
15 | 	return mcp.NewTool("protectionrule_list",
16 | 		mcp.WithDescription("List protectionrule resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // ProtectionRuleListHandler implements the handler for the ProtectionRule list tool
24 | func ProtectionRuleListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeProtectionRule,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllProtectionRules(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // ProtectionRuleCount defines the ProtectionRule count tool
38 | func ProtectionRuleCount() mcp.Tool {
39 | 	return mcp.NewTool("protectionrule_count",
40 | 		mcp.WithDescription("Count protectionrule resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // ProtectionRuleCountHandler implements the handler for the ProtectionRule count tool
48 | func ProtectionRuleCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeProtectionRule,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllProtectionRules(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "ProtectionRule",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	v3 "github.com/nutanix-cloud-native/prism-go-client/v3"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 8 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 9 | 
10 | 	"github.com/mark3labs/mcp-go/mcp"
11 | 	"github.com/mark3labs/mcp-go/server"
12 | )
13 | 
14 | // VolumeGroup defines the VolumeGroup tool
15 | func VolumeGroupList() mcp.Tool {
16 | 	return mcp.NewTool("volumegroup_list",
17 | 		mcp.WithDescription("List volumegroup resources"),
18 | 		mcp.WithString("filter",
19 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
20 | 		),
21 | 	)
22 | }
23 | 
24 | // VolumeGroupListHandler implements the handler for the VolumeGroup list tool
25 | func VolumeGroupListHandler() server.ToolHandlerFunc {
26 | 	return CreateListToolHandler(
27 | 		resources.ResourceTypeVolumeGroup,
28 | 		// Define the ListResourceFunc implementation
29 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
30 | 
31 | 			// Create DSMetadata without filter
32 | 			metadata := &v3.DSMetadata{}
33 | 
34 | 			return client.V3().ListVolumeGroup(ctx, metadata)
35 | 
36 | 		},
37 | 	)
38 | }
39 | 
40 | // VolumeGroupCount defines the VolumeGroup count tool
41 | func VolumeGroupCount() mcp.Tool {
42 | 	return mcp.NewTool("volumegroup_count",
43 | 		mcp.WithDescription("Count volumegroup resources"),
44 | 		mcp.WithString("filter",
45 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
46 | 		),
47 | 	)
48 | }
49 | 
50 | // VolumeGroupCountHandler implements the handler for the VolumeGroup count tool
51 | func VolumeGroupCountHandler() server.ToolHandlerFunc {
52 | 	return CreateCountToolHandler(
53 | 		resources.ResourceTypeVolumeGroup,
54 | 		// Define the ListResourceFunc implementation
55 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
56 | 
57 | 			// Create DSMetadata without filter
58 | 			metadata := &v3.DSMetadata{}
59 | 
60 | 			resp, err := client.V3().ListVolumeGroup(ctx, metadata)
61 | 
62 | 			if err != nil {
63 | 				return nil, err
64 | 			}
65 | 
66 | 			res := map[string]interface{}{
67 | 				"resource_type": "VolumeGroup",
68 | 				"count":         len(resp.Entities),
69 | 				"metadata":      resp.Metadata,
70 | 			}
71 | 
72 | 			return res, nil
73 | 		},
74 | 	)
75 | }
76 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | 	v3 "github.com/nutanix-cloud-native/prism-go-client/v3"
12 | )
13 | 
14 | // Category defines the Category tool
15 | func CategoryList() mcp.Tool {
16 | 	return mcp.NewTool("category_list",
17 | 		mcp.WithDescription("List category resources"),
18 | 		mcp.WithString("filter",
19 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
20 | 		),
21 | 	)
22 | }
23 | 
24 | // CategoryListHandler implements the handler for the Category list tool
25 | func CategoryListHandler() server.ToolHandlerFunc {
26 | 	return CreateListToolHandler(
27 | 		resources.ResourceTypeCategory,
28 | 		// Define the ListResourceFunc implementation
29 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
30 | 
31 | 			// Special case for Category which takes CategoryListMetadata
32 | 			metadata := &v3.CategoryListMetadata{}
33 | 			return client.V3().ListCategories(ctx, metadata)
34 | 
35 | 		},
36 | 	)
37 | }
38 | 
39 | // CategoryCount defines the Category count tool
40 | func CategoryCount() mcp.Tool {
41 | 	return mcp.NewTool("category_count",
42 | 		mcp.WithDescription("Count category resources"),
43 | 		mcp.WithString("filter",
44 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
45 | 		),
46 | 	)
47 | }
48 | 
49 | // CategoryCountHandler implements the handler for the Category count tool
50 | func CategoryCountHandler() server.ToolHandlerFunc {
51 | 	return CreateCountToolHandler(
52 | 		resources.ResourceTypeCategory,
53 | 		// Define the ListResourceFunc implementation
54 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
55 | 
56 | 			// Special case for Category which takes CategoryListMetadata
57 | 			metadata := &v3.CategoryListMetadata{}
58 | 			resp, err := client.V3().ListCategories(ctx, metadata)
59 | 
60 | 			if err != nil {
61 | 				return nil, err
62 | 			}
63 | 
64 | 			res := map[string]interface{}{
65 | 				"resource_type": "Category",
66 | 				"count":         len(resp.Entities),
67 | 				"metadata":      resp.Metadata,
68 | 			}
69 | 
70 | 			return res, nil
71 | 		},
72 | 	)
73 | }
74 | 
```

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

```go
 1 | package client
 2 | 
 3 | import (
 4 | 	"github.com/nutanix-cloud-native/prism-go-client/environment"
 5 | 	"github.com/nutanix-cloud-native/prism-go-client/environment/providers/local"
 6 | 	"github.com/nutanix-cloud-native/prism-go-client/environment/providers/mcp"
 7 | 	envtypes "github.com/nutanix-cloud-native/prism-go-client/environment/types"
 8 | 	prismclientv3 "github.com/nutanix-cloud-native/prism-go-client/v3"
 9 | 	prismclientv4 "github.com/nutanix-cloud-native/prism-go-client/v4"
10 | 	"k8s.io/klog"
11 | )
12 | 
13 | var (
14 | 	prismClient *NutanixClient
15 | )
16 | 
17 | func Init(modelcontextclient mcp.ModelContextClient) {
18 | 	prismClient = &NutanixClient{
19 | 		env:           environment.NewEnvironment(local.NewProvider(), mcp.NewProvider(modelcontextclient)),
20 | 		v3ClientCache: prismclientv3.NewClientCache(),
21 | 		v4ClientCache: prismclientv4.NewClientCache(),
22 | 	}
23 | }
24 | 
25 | func GetPrismClient() *NutanixClient {
26 | 	if prismClient == nil {
27 | 		panic("Prism client not initialized. Call Init() first.")
28 | 	}
29 | 
30 | 	return prismClient
31 | }
32 | 
33 | type NutanixClient struct {
34 | 	env           envtypes.Environment
35 | 	v3ClientCache *prismclientv3.ClientCache
36 | 	v4ClientCache *prismclientv4.ClientCache
37 | }
38 | 
39 | // GetV3Client returns the v3 client
40 | func (n *NutanixClient) V3() prismclientv3.Service {
41 | 	c, err := n.v3ClientCache.GetOrCreate(n)
42 | 	if err != nil {
43 | 		panic(err)
44 | 	}
45 | 
46 | 	return c.V3
47 | }
48 | 
49 | // GetV4Client returns the v4 client
50 | func (n *NutanixClient) V4() *prismclientv4.Client {
51 | 	c, err := n.v4ClientCache.GetOrCreate(n)
52 | 	if err != nil {
53 | 		panic(err)
54 | 	}
55 | 
56 | 	return c
57 | }
58 | 
59 | // Key returns the constant client name
60 | // This implements the CachedClientParams interface of prism-go-client
61 | func (n *NutanixClient) Key() string {
62 | 	return "mcp-server"
63 | }
64 | 
65 | // ManagementEndpoint returns the management endpoint of the Nutanix cluster
66 | // This implements the CachedClientParams interface of prism-go-client
67 | func (n *NutanixClient) ManagementEndpoint() envtypes.ManagementEndpoint {
68 | 	mgmtEndpoint, err := n.env.GetManagementEndpoint(envtypes.Topology{})
69 | 	if err != nil {
70 | 		klog.Errorf("failed to get management endpoint: %s", err.Error())
71 | 		return envtypes.ManagementEndpoint{}
72 | 	}
73 | 
74 | 	return *mgmtEndpoint
75 | }
76 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // AccessControlPolicy defines the AccessControlPolicy tool
14 | func AccessControlPolicyList() mcp.Tool {
15 | 	return mcp.NewTool("accesscontrolpolicy_list",
16 | 		mcp.WithDescription("List accesscontrolpolicy resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // AccessControlPolicyListHandler implements the handler for the AccessControlPolicy list tool
24 | func AccessControlPolicyListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeAccessControlPolicy,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllAccessControlPolicy(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // AccessControlPolicyCount defines the AccessControlPolicy count tool
38 | func AccessControlPolicyCount() mcp.Tool {
39 | 	return mcp.NewTool("accesscontrolpolicy_count",
40 | 		mcp.WithDescription("Count accesscontrolpolicy resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // AccessControlPolicyCountHandler implements the handler for the AccessControlPolicy count tool
48 | func AccessControlPolicyCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeAccessControlPolicy,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllAccessControlPolicy(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "AccessControlPolicy",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | // NetworkSecurityRule defines the NetworkSecurityRule tool
14 | func NetworkSecurityRuleList() mcp.Tool {
15 | 	return mcp.NewTool("networksecurityrule_list",
16 | 		mcp.WithDescription("List networksecurityrule resources"),
17 | 		mcp.WithString("filter",
18 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
19 | 		),
20 | 	)
21 | }
22 | 
23 | // NetworkSecurityRuleListHandler implements the handler for the NetworkSecurityRule list tool
24 | func NetworkSecurityRuleListHandler() server.ToolHandlerFunc {
25 | 	return CreateListToolHandler(
26 | 		resources.ResourceTypeNetworkSecurityRule,
27 | 		// Define the ListResourceFunc implementation
28 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
29 | 
30 | 			// Use ListAll function to get all resources
31 | 			return client.V3().ListAllNetworkSecurityRule(ctx, "")
32 | 
33 | 		},
34 | 	)
35 | }
36 | 
37 | // NetworkSecurityRuleCount defines the NetworkSecurityRule count tool
38 | func NetworkSecurityRuleCount() mcp.Tool {
39 | 	return mcp.NewTool("networksecurityrule_count",
40 | 		mcp.WithDescription("Count networksecurityrule resources"),
41 | 		mcp.WithString("filter",
42 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
43 | 		),
44 | 	)
45 | }
46 | 
47 | // NetworkSecurityRuleCountHandler implements the handler for the NetworkSecurityRule count tool
48 | func NetworkSecurityRuleCountHandler() server.ToolHandlerFunc {
49 | 	return CreateCountToolHandler(
50 | 		resources.ResourceTypeNetworkSecurityRule,
51 | 		// Define the ListResourceFunc implementation
52 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
53 | 
54 | 			// Use ListAll function to get all resources
55 | 			resp, err := client.V3().ListAllNetworkSecurityRule(ctx, "")
56 | 
57 | 			if err != nil {
58 | 				return nil, err
59 | 			}
60 | 
61 | 			res := map[string]interface{}{
62 | 				"resource_type": "NetworkSecurityRule",
63 | 				"count":         len(resp.Entities),
64 | 				"metadata":      resp.Metadata,
65 | 			}
66 | 
67 | 			return res, nil
68 | 		},
69 | 	)
70 | }
71 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | 	v3 "github.com/nutanix-cloud-native/prism-go-client/v3"
12 | )
13 | 
14 | // RecoveryPlanJob defines the RecoveryPlanJob tool
15 | func RecoveryPlanJobList() mcp.Tool {
16 | 	return mcp.NewTool("recoveryplanjob_list",
17 | 		mcp.WithDescription("List recoveryplanjob resources"),
18 | 		mcp.WithString("filter",
19 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
20 | 		),
21 | 	)
22 | }
23 | 
24 | // RecoveryPlanJobListHandler implements the handler for the RecoveryPlanJob list tool
25 | func RecoveryPlanJobListHandler() server.ToolHandlerFunc {
26 | 	return CreateListToolHandler(
27 | 		resources.ResourceTypeRecoveryPlanJob,
28 | 		// Define the ListResourceFunc implementation
29 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
30 | 
31 | 			// Create DSMetadata without filter
32 | 			metadata := &v3.DSMetadata{}
33 | 
34 | 			return client.V3().ListRecoveryPlanJobs(ctx, metadata)
35 | 
36 | 		},
37 | 	)
38 | }
39 | 
40 | // RecoveryPlanJobCount defines the RecoveryPlanJob count tool
41 | func RecoveryPlanJobCount() mcp.Tool {
42 | 	return mcp.NewTool("recoveryplanjob_count",
43 | 		mcp.WithDescription("Count recoveryplanjob resources"),
44 | 		mcp.WithString("filter",
45 | 			mcp.Description("Optional text filter (interpreted by LLM)"),
46 | 		),
47 | 	)
48 | }
49 | 
50 | // RecoveryPlanJobCountHandler implements the handler for the RecoveryPlanJob count tool
51 | func RecoveryPlanJobCountHandler() server.ToolHandlerFunc {
52 | 	return CreateCountToolHandler(
53 | 		resources.ResourceTypeRecoveryPlanJob,
54 | 		// Define the ListResourceFunc implementation
55 | 		func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
56 | 
57 | 			// Create DSMetadata without filter
58 | 			metadata := &v3.DSMetadata{}
59 | 
60 | 			resp, err := client.V3().ListRecoveryPlanJobs(ctx, metadata)
61 | 
62 | 			if err != nil {
63 | 				return nil, err
64 | 			}
65 | 
66 | 			res := map[string]interface{}{
67 | 				"resource_type": "RecoveryPlanJob",
68 | 				"count":         len(resp.Entities),
69 | 				"metadata":      resp.Metadata,
70 | 			}
71 | 
72 | 			return res, nil
73 | 		},
74 | 	)
75 | }
76 | 
```

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

```go
 1 | package prompts
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 
 7 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 8 | 
 9 | 	"github.com/mark3labs/mcp-go/mcp"
10 | 	"github.com/mark3labs/mcp-go/server"
11 | )
12 | 
13 | func SetCredentials() mcp.Prompt {
14 | 	return mcp.NewPrompt("credentials",
15 | 		mcp.WithPromptDescription("Credentials for Prism Central"),
16 | 		mcp.WithArgument("endpoint",
17 | 			mcp.RequiredArgument(),
18 | 			mcp.ArgumentDescription("Prism Central endpoint"),
19 | 		),
20 | 		mcp.WithArgument("username",
21 | 			mcp.RequiredArgument(),
22 | 			mcp.ArgumentDescription("Username of the Prism Central user"),
23 | 		),
24 | 		mcp.WithArgument("password",
25 | 			mcp.RequiredArgument(),
26 | 			mcp.ArgumentDescription("Password of the Prism Central user"),
27 | 		),
28 | 		mcp.WithArgument("insecure",
29 | 			mcp.ArgumentDescription("Skip TLS verification (true/false)"),
30 | 		),
31 | 	)
32 | }
33 | 
34 | func SetCredentialsResponse() server.PromptHandlerFunc {
35 | 	return func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
36 | 		endpoint := request.Params.Arguments["endpoint"]
37 | 		username := request.Params.Arguments["username"]
38 | 		password := request.Params.Arguments["password"]
39 | 		insecure := request.Params.Arguments["insecure"]
40 | 
41 | 		client.PrismClientProvider.UpdateValue("endpoint", endpoint)
42 | 		client.PrismClientProvider.UpdateValue("username", username)
43 | 		client.PrismClientProvider.UpdateValue("password", password)
44 | 		client.PrismClientProvider.UpdateValue("insecure", insecure)
45 | 
46 | 		client.Init(client.PrismClientProvider)
47 | 
48 | 		// Validate the credentials
49 | 		pcInfo, err := client.GetPrismClient().V3().GetPrismCentral(ctx)
50 | 		if err != nil {
51 | 			return mcp.NewGetPromptResult(
52 | 				"Failed to connect to Prism Central",
53 | 				[]mcp.PromptMessage{
54 | 					mcp.NewPromptMessage(
55 | 						mcp.RoleAssistant,
56 | 						mcp.NewTextContent(fmt.Sprintf("Failed to connect to Prism Central: %s. Please check your credentials and try again.", err.Error())),
57 | 					),
58 | 				},
59 | 			), nil
60 | 		}
61 | 
62 | 		return mcp.NewGetPromptResult(
63 | 			"Connected to Prism Central",
64 | 			[]mcp.PromptMessage{
65 | 				mcp.NewPromptMessage(
66 | 					mcp.RoleAssistant,
67 | 					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)),
68 | 				),
69 | 			},
70 | 		), nil
71 | 	}
72 | }
73 | 
```

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

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
 7 | 	"github.com/thunderboltsid/mcp-nutanix/internal/json"
 8 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 9 | 
10 | 	"github.com/mark3labs/mcp-go/mcp"
11 | 	"github.com/mark3labs/mcp-go/server"
12 | )
13 | 
14 | // ListResourceFunc defines a function that handles listing a resource type
15 | type ListResourceFunc func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error)
16 | 
17 | // CreateListToolHandler creates a generic tool handler for listing resources
18 | func CreateListToolHandler(
19 | 	resourceType resources.ResourceType,
20 | 	listFunc ListResourceFunc,
21 | ) server.ToolHandlerFunc {
22 | 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
23 | 		// Get the Prism client
24 | 		prismClient := client.GetPrismClient()
25 | 		if prismClient == nil {
26 | 			return nil, fmt.Errorf("prism client not initialized, please set credentials first")
27 | 		}
28 | 
29 | 		// Get filter if provided (for LLM reference only)
30 | 		//filter, _ := request.Params.Arguments["filter"].(string)
31 | 
32 | 		// List all resources
33 | 		resp, err := listFunc(ctx, prismClient, "")
34 | 		if err != nil {
35 | 			return nil, fmt.Errorf("failed to list %s: %w", resourceType, err)
36 | 		}
37 | 
38 | 		// Convert to JSON
39 | 		cjson := json.CustomJSONEncoder(resp)
40 | 		jsonBytes, err := cjson.MarshalJSON()
41 | 		if err != nil {
42 | 			return nil, fmt.Errorf("failed to marshal %s: %w", resourceType, err)
43 | 		}
44 | 
45 | 		return mcp.NewToolResultText(string(jsonBytes)), nil
46 | 	}
47 | }
48 | 
49 | // CreateCountToolHandler creates a generic tool handler for counting resources
50 | func CreateCountToolHandler(
51 | 	resourceType resources.ResourceType,
52 | 	countFunc ListResourceFunc,
53 | ) server.ToolHandlerFunc {
54 | 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
55 | 		// Get the Prism client
56 | 		prismClient := client.GetPrismClient()
57 | 		if prismClient == nil {
58 | 			return nil, fmt.Errorf("prism client not initialized, please set credentials first")
59 | 		}
60 | 
61 | 		// Get filter if provided (for LLM reference only)
62 | 		//filter, _ := request.Params.Arguments["filter"].(string)
63 | 
64 | 		// List all resources
65 | 		resp, err := countFunc(ctx, prismClient, "")
66 | 		if err != nil {
67 | 			return nil, fmt.Errorf("failed to list %s: %w", resourceType, err)
68 | 		}
69 | 
70 | 		// Convert to JSON
71 | 		cjson := json.RegularJSONEncoder(resp)
72 | 		jsonBytes, err := cjson.MarshalJSON()
73 | 		if err != nil {
74 | 			return nil, fmt.Errorf("failed to marshal %s count: %w", resourceType, err)
75 | 		}
76 | 
77 | 		return mcp.NewToolResultText(string(jsonBytes)), nil
78 | 	}
79 | }
80 | 
```

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

```go
  1 | package json
  2 | 
  3 | import (
  4 | 	"encoding/json"
  5 | 	"fmt"
  6 | 	"strings"
  7 | 
  8 | 	"github.com/itchyny/gojq"
  9 | )
 10 | 
 11 | // DefaultStripPaths is a list of default paths to strip from the JSON output.
 12 | // These paths are used to remove unnecessary or sensitive information from the JSON response.
 13 | // guest_customization on VMs is massive and could contain sensitive information.
 14 | // spec and status are duplicative info and hence status can be removed.
 15 | var DefaultStripPaths = []string{
 16 | 	"api_version",
 17 | 	"spec.resources.guest_customization",
 18 | 	"entities[].spec.resources.guest_customization",
 19 | 	"entities[].status.resources.guest_customization",
 20 | }
 21 | 
 22 | func stripProperties(data []byte, paths []string) ([]byte, error) {
 23 | 	var input interface{}
 24 | 	if err := json.Unmarshal(data, &input); err != nil {
 25 | 		return nil, err
 26 | 	}
 27 | 
 28 | 	// Start with identity query
 29 | 	queryStr := "."
 30 | 
 31 | 	for _, path := range paths {
 32 | 		if strings.Contains(path, "[]") {
 33 | 			// Handle array paths (entities[].status)
 34 | 			parts := strings.Split(path, "[]")
 35 | 			arrayPath := parts[0]
 36 | 			fieldPath := parts[1]
 37 | 
 38 | 			if len(fieldPath) > 0 && fieldPath[0] == '.' {
 39 | 				fieldPath = fieldPath[1:] // Remove leading dot
 40 | 			}
 41 | 
 42 | 			// Correct jq syntax for modifying each element in an array
 43 | 			queryStr += fmt.Sprintf(" | .%s |= map(del(.%s))", arrayPath, fieldPath)
 44 | 		} else {
 45 | 			// Simple path (api_version)
 46 | 			queryStr += fmt.Sprintf(" | del(.%s)", path)
 47 | 		}
 48 | 	}
 49 | 
 50 | 	// For debugging
 51 | 	// fmt.Printf("JQ Query: %s\n", queryStr)
 52 | 
 53 | 	query, err := gojq.Parse(queryStr)
 54 | 	if err != nil {
 55 | 		return nil, fmt.Errorf("jq parse error: %v for query: %s", err, queryStr)
 56 | 	}
 57 | 
 58 | 	code, err := gojq.Compile(query)
 59 | 	if err != nil {
 60 | 		return nil, fmt.Errorf("jq compile error: %v", err)
 61 | 	}
 62 | 
 63 | 	iter := code.Run(input)
 64 | 	result, ok := iter.Next()
 65 | 	if !ok {
 66 | 		return nil, fmt.Errorf("jq query returned no results")
 67 | 	}
 68 | 
 69 | 	if err, ok := result.(error); ok {
 70 | 		return nil, fmt.Errorf("jq execution error: %v", err)
 71 | 	}
 72 | 
 73 | 	return json.Marshal(result)
 74 | }
 75 | 
 76 | type CustomJSON struct {
 77 | 	Value      interface{}
 78 | 	StripPaths []string
 79 | }
 80 | 
 81 | type RegularJSON struct {
 82 | 	Value interface{}
 83 | }
 84 | 
 85 | func CustomJSONEncoder(value any) *CustomJSON {
 86 | 	return &CustomJSON{
 87 | 		Value:      value,
 88 | 		StripPaths: DefaultStripPaths,
 89 | 	}
 90 | }
 91 | 
 92 | func RegularJSONEncoder(value any) *RegularJSON {
 93 | 	return &RegularJSON{
 94 | 		Value: value,
 95 | 	}
 96 | }
 97 | 
 98 | func (r *RegularJSON) MarshalJSON() ([]byte, error) {
 99 | 	data, err := json.Marshal(r.Value)
100 | 	if err != nil {
101 | 		return nil, err
102 | 	}
103 | 
104 | 	return data, nil
105 | }
106 | 
107 | func (d *CustomJSON) MarshalJSON() ([]byte, error) {
108 | 	data, err := json.Marshal(d.Value)
109 | 	if err != nil {
110 | 		return nil, err
111 | 	}
112 | 
113 | 	return stripProperties(data, d.StripPaths)
114 | }
115 | 
```

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

```go
  1 | package resources
  2 | 
  3 | import (
  4 | 	"context"
  5 | 	"fmt"
  6 | 	"strings"
  7 | 
  8 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
  9 | 	"github.com/thunderboltsid/mcp-nutanix/internal/json"
 10 | 
 11 | 	"github.com/mark3labs/mcp-go/mcp"
 12 | 	"github.com/mark3labs/mcp-go/server"
 13 | )
 14 | 
 15 | // ResourceType enum for different resource types
 16 | type ResourceType string
 17 | 
 18 | const (
 19 | 	ResourceTypeVM                  ResourceType = "vm"
 20 | 	ResourceTypeSubnet              ResourceType = "subnet"
 21 | 	ResourceTypeImage               ResourceType = "image"
 22 | 	ResourceTypeCluster             ResourceType = "cluster"
 23 | 	ResourceTypeHost                ResourceType = "host"
 24 | 	ResourceTypeProject             ResourceType = "project"
 25 | 	ResourceTypeVolumeGroup         ResourceType = "volumegroup"
 26 | 	ResourceTypeNetworkSecurityRule ResourceType = "networksecurityrule"
 27 | 	ResourceTypeServiceGroup        ResourceType = "servicegroup"
 28 | 	ResourceTypeAddressGroup        ResourceType = "addressgroup"
 29 | 	ResourceTypeAccessControlPolicy ResourceType = "accesscontrolpolicy"
 30 | 	ResourceTypeRole                ResourceType = "role"
 31 | 	ResourceTypeUser                ResourceType = "user"
 32 | 	ResourceTypeUserGroup           ResourceType = "usergroup"
 33 | 	ResourceTypePermission          ResourceType = "permission"
 34 | 	ResourceTypeProtectionRule      ResourceType = "protectionrule"
 35 | 	ResourceTypeRecoveryPlan        ResourceType = "recoveryplan"
 36 | 	ResourceTypeRecoveryPlanJob     ResourceType = "recoveryplanjob"
 37 | 	ResourceTypeCategory            ResourceType = "category"
 38 | 	ResourceTypeCategoryValue       ResourceType = "categoryvalue"
 39 | 	ResourceTypeAvailabilityZone    ResourceType = "availabilityzone"
 40 | )
 41 | 
 42 | // ResourceHandlerFunc defines a function that handles a specific resource get operation
 43 | type ResourceHandlerFunc func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error)
 44 | 
 45 | // ResourceURIPrefix returns the URI prefix for a resource type
 46 | func ResourceURIPrefix(resourceType ResourceType) string {
 47 | 	return fmt.Sprintf("%s://", resourceType)
 48 | }
 49 | 
 50 | // NutanixURI returns a URI for a resource type and UUID
 51 | func NutanixURI(resourceType ResourceType, uuid string) string {
 52 | 	return fmt.Sprintf("%s://%s", resourceType, uuid)
 53 | }
 54 | 
 55 | // ExtractIDFromURI extracts the UUID from a URI
 56 | // uri is expected to be in the format of resourceType://uuid
 57 | func ExtractIDFromURI(uri string) string {
 58 | 	parts := strings.Split(uri, "://")
 59 | 	if len(parts) != 2 {
 60 | 		return ""
 61 | 	}
 62 | 	return parts[1]
 63 | }
 64 | 
 65 | // ExtractTypeFromURI extracts the resource type from a URI
 66 | // uri is expected to be in the format of resourceType://uuid
 67 | func ExtractTypeFromURI(uri string) ResourceType {
 68 | 	parts := strings.Split(uri, "://")
 69 | 	if len(parts) != 2 {
 70 | 		return ""
 71 | 	}
 72 | 	return ResourceType(parts[0])
 73 | }
 74 | 
 75 | // CreateResourceHandler creates a generic resource handler for any Nutanix resource
 76 | func CreateResourceHandler(resourceType ResourceType, handlerFunc ResourceHandlerFunc) server.ResourceTemplateHandlerFunc {
 77 | 	return func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
 78 | 		uuid := ExtractIDFromURI(request.Params.URI)
 79 | 		if uuid == "" {
 80 | 			return nil, fmt.Errorf("URI must contain a UUID")
 81 | 		}
 82 | 
 83 | 		// Get the Prism client
 84 | 		prismClient := client.GetPrismClient()
 85 | 		if prismClient == nil {
 86 | 			return nil, fmt.Errorf("prism client not initialized, please set credentials first")
 87 | 		}
 88 | 
 89 | 		// Call the specific resource handler
 90 | 		resource, err := handlerFunc(ctx, prismClient, uuid)
 91 | 		if err != nil {
 92 | 			return nil, fmt.Errorf("failed to get %s: %w", resourceType, err)
 93 | 		}
 94 | 
 95 | 		// Convert to JSON
 96 | 		cjson := json.CustomJSONEncoder(resource)
 97 | 		jsonBytes, err := cjson.MarshalJSON()
 98 | 		if err != nil {
 99 | 			return nil, fmt.Errorf("failed to marshal %s details: %w", resourceType, err)
100 | 		}
101 | 
102 | 		return []mcp.ResourceContents{
103 | 			&mcp.TextResourceContents{
104 | 				URI:      request.Params.URI,
105 | 				MIMEType: "application/json",
106 | 				Text:     string(jsonBytes),
107 | 			},
108 | 		}, nil
109 | 	}
110 | }
111 | 
```

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

```go
  1 | package templates
  2 | 
  3 | import (
  4 | 	"fmt"
  5 | 	"os"
  6 | 	"strings"
  7 | 	"text/template"
  8 | )
  9 | 
 10 | // Templates for tool implementations
 11 | const toolTemplate = `package tools
 12 | 
 13 | import (
 14 |     "context"
 15 |     "fmt"
 16 | 
 17 |     "github.com/thunderboltsid/mcp-nutanix/internal/client"
 18 |     "github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 19 | 
 20 |     "github.com/mark3labs/mcp-go/mcp"
 21 |     "github.com/mark3labs/mcp-go/server"
 22 |     "github.com/nutanix-cloud-native/prism-go-client/v3"
 23 | )
 24 | 
 25 | // {{.Name}} defines the {{.Name}} tool
 26 | func {{.Name}}List() mcp.Tool {
 27 |     return mcp.NewTool("{{.ResourceType}}_list",
 28 |         mcp.WithDescription("List {{.ResourceType}} resources"),
 29 |         mcp.WithString("filter",
 30 |            mcp.Description("Optional text filter (interpreted by LLM)"),
 31 |         ),
 32 |     )
 33 | }
 34 | 
 35 | // {{.Name}}ListHandler implements the handler for the {{.Name}} list tool
 36 | func {{.Name}}ListHandler() server.ToolHandlerFunc {
 37 |     return CreateListToolHandler(
 38 |         resources.ResourceType{{.Name}},
 39 |         // Define the ListResourceFunc implementation
 40 |         func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
 41 |             {{if eq .Name "Host"}}
 42 |             // Special case for Host which doesn't take a filter
 43 |             return client.V3().{{.ClientListAllFunc}}(ctx)
 44 |             {{else if eq .Name "Subnet"}}
 45 |             // Special case for Subnet which has an extra parameter
 46 |             return client.V3().{{.ClientListAllFunc}}(ctx, "", nil)
 47 |             {{else if eq .Name "Category"}}
 48 |             // Special case for Category which takes CategoryListMetadata
 49 |             metadata := &v3.CategoryListMetadata{}
 50 |             return client.V3().{{.ClientListFunc}}(ctx, metadata)
 51 |             {{else if .HasListAllFunc}}
 52 |             // Use ListAll function to get all resources
 53 |             return client.V3().{{.ClientListAllFunc}}(ctx, "")
 54 |             {{else}}
 55 |             // Create DSMetadata without filter
 56 |             metadata := &v3.DSMetadata{}
 57 |             
 58 |             return client.V3().{{.ClientListFunc}}(ctx, metadata)
 59 |             {{end}}
 60 |         },
 61 |     )
 62 | }
 63 | 
 64 | // {{.Name}}Count defines the {{.Name}} count tool
 65 | func {{.Name}}Count() mcp.Tool {
 66 |     return mcp.NewTool("{{.ResourceType}}_count",
 67 |         mcp.WithDescription("Count {{.ResourceType}} resources"),
 68 |         mcp.WithString("filter",
 69 |            mcp.Description("Optional text filter (interpreted by LLM)"),
 70 |         ),
 71 |     )
 72 | }
 73 | 
 74 | // {{.Name}}CountHandler implements the handler for the {{.Name}} count tool
 75 | func {{.Name}}CountHandler() server.ToolHandlerFunc {
 76 |     return CreateCountToolHandler(
 77 |         resources.ResourceType{{.Name}},
 78 |         // Define the ListResourceFunc implementation
 79 |         func(ctx context.Context, client *client.NutanixClient, filter string) (interface{}, error) {
 80 |             {{if eq .Name "Host"}}
 81 |             // Special case for Host which doesn't take a filter
 82 |             resp, err := client.V3().{{.ClientListAllFunc}}(ctx)
 83 |             {{else if eq .Name "Subnet"}}
 84 |             // Special case for Subnet which has an extra parameter
 85 |             resp, err := client.V3().{{.ClientListAllFunc}}(ctx, "", nil)
 86 |             {{else if eq .Name "Category"}}
 87 |             // Special case for Category which takes CategoryListMetadata
 88 |             metadata := &v3.CategoryListMetadata{}
 89 |             resp, err := client.V3().{{.ClientListFunc}}(ctx, metadata)
 90 |             {{else if .HasListAllFunc}}
 91 |             // Use ListAll function to get all resources
 92 |             resp, err := client.V3().{{.ClientListAllFunc}}(ctx, "")
 93 |             {{else}}
 94 |             // Create DSMetadata without filter
 95 |             metadata := &v3.DSMetadata{}
 96 |             
 97 |             resp, err := client.V3().{{.ClientListFunc}}(ctx, metadata)
 98 |             {{end}}
 99 |             if err != nil {
100 | 				return nil, err
101 | 			}
102 | 
103 | 			res := map[string]interface{}{
104 | 				"resource_type": "{{.Name}}",
105 | 				"count": len(resp.Entities),
106 | 				"metadata": resp.Metadata,
107 |         	}
108 | 
109 | 			return res, nil
110 | 		},
111 |     )
112 | }
113 | `
114 | 
115 | // GenerateToolFiles generates tool files for all Nutanix resources that support listing
116 | func GenerateToolFiles(baseDir string) error {
117 | 	resources := GetResourceDefinitions()
118 | 
119 | 	// Create the tools directory if it doesn't exist
120 | 	toolsDir := fmt.Sprintf("%s/pkg/tools", baseDir)
121 | 	err := os.MkdirAll(toolsDir, 0755)
122 | 	if err != nil {
123 | 		return fmt.Errorf("error creating tools directory: %w", err)
124 | 	}
125 | 
126 | 	// Parse the tool template
127 | 	toolTmpl, err := template.New("tool").Parse(toolTemplate)
128 | 	if err != nil {
129 | 		return fmt.Errorf("error parsing tool template: %w", err)
130 | 	}
131 | 
132 | 	// Generate tool files
133 | 	for _, res := range resources {
134 | 		// Skip resources that don't support listing
135 | 		if !res.HasListFunc && !res.HasListAllFunc {
136 | 			fmt.Printf("Skipping tool generation for %s: no list capability\n", res.Name)
137 | 			continue
138 | 		}
139 | 
140 | 		// Create tool file
141 | 		toolFilePath := fmt.Sprintf("%s/%s.go", toolsDir, strings.ToLower(res.Name))
142 | 		toolFile, err := os.Create(toolFilePath)
143 | 		if err != nil {
144 | 			fmt.Printf("Error creating tool file for %s: %v\n", res.Name, err)
145 | 			continue
146 | 		}
147 | 		defer toolFile.Close()
148 | 
149 | 		// Execute the template
150 | 		err = toolTmpl.Execute(toolFile, res)
151 | 		if err != nil {
152 | 			fmt.Printf("Error executing tool template for %s: %v\n", res.Name, err)
153 | 		}
154 | 	}
155 | 
156 | 	return nil
157 | }
158 | 
```

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

```go
  1 | package templates
  2 | 
  3 | import (
  4 | 	"fmt"
  5 | 	"os"
  6 | 	"strings"
  7 | 	"text/template"
  8 | )
  9 | 
 10 | // Resource defines the structure for a Nutanix resource
 11 | type Resource struct {
 12 | 	Name              string
 13 | 	ResourceType      string
 14 | 	Description       string
 15 | 	ClientGetFunc     string
 16 | 	ClientListFunc    string // Regular List function with DSMetadata parameter
 17 | 	ClientListAllFunc string // ListAll function with filter string parameter
 18 | 	HasListFunc       bool   // Whether the service has a ListX function
 19 | 	HasListAllFunc    bool   // Whether the service has a ListAllX function
 20 | }
 21 | 
 22 | const resourceTemplate = `package resources
 23 | 
 24 | import (
 25 |     "context"
 26 | 
 27 |     "github.com/thunderboltsid/mcp-nutanix/internal/client"
 28 | 
 29 |     "github.com/mark3labs/mcp-go/mcp"
 30 |     "github.com/mark3labs/mcp-go/server"
 31 | )
 32 | 
 33 | // {{.Name}} defines the {{.Name}} resource template
 34 | func {{.Name}}() mcp.ResourceTemplate {
 35 |     return mcp.NewResourceTemplate(
 36 |         string(ResourceURIPrefix(ResourceType{{.Name}})) + "{uuid}",
 37 |         string(ResourceType{{.Name}}),
 38 |         mcp.WithTemplateDescription("{{.Description}}"),
 39 |         mcp.WithTemplateMIMEType("application/json"),
 40 |     )
 41 | }
 42 | 
 43 | // {{.Name}}Handler implements the handler for the {{.Name}} resource
 44 | func {{.Name}}Handler() server.ResourceTemplateHandlerFunc {
 45 |     return CreateResourceHandler(ResourceType{{.Name}}, func(ctx context.Context, client *client.NutanixClient, uuid string) (interface{}, error) {
 46 |         // Get the {{.Name}}
 47 |         return client.V3().{{.ClientGetFunc}}(ctx, uuid)
 48 |     })
 49 | }
 50 | `
 51 | 
 52 | // GetResourceDefinitions returns all Nutanix resource definitions
 53 | func GetResourceDefinitions() []Resource {
 54 | 	return []Resource{
 55 | 		{
 56 | 			Name:              "VM",
 57 | 			ResourceType:      "vm",
 58 | 			Description:       "Virtual Machine resource",
 59 | 			ClientGetFunc:     "GetVM",
 60 | 			ClientListFunc:    "ListVM",
 61 | 			ClientListAllFunc: "ListAllVM",
 62 | 			HasListFunc:       true,
 63 | 			HasListAllFunc:    true,
 64 | 		},
 65 | 		{
 66 | 			Name:              "Cluster",
 67 | 			ResourceType:      "cluster",
 68 | 			Description:       "Cluster resource",
 69 | 			ClientGetFunc:     "GetCluster",
 70 | 			ClientListFunc:    "ListCluster",
 71 | 			ClientListAllFunc: "ListAllCluster",
 72 | 			HasListFunc:       true,
 73 | 			HasListAllFunc:    true,
 74 | 		},
 75 | 		{
 76 | 			Name:              "Image",
 77 | 			ResourceType:      "image",
 78 | 			Description:       "Image resource",
 79 | 			ClientGetFunc:     "GetImage",
 80 | 			ClientListFunc:    "ListImage",
 81 | 			ClientListAllFunc: "ListAllImage",
 82 | 			HasListFunc:       true,
 83 | 			HasListAllFunc:    true,
 84 | 		},
 85 | 		{
 86 | 			Name:              "Subnet",
 87 | 			ResourceType:      "subnet",
 88 | 			Description:       "Subnet resource",
 89 | 			ClientGetFunc:     "GetSubnet",
 90 | 			ClientListFunc:    "ListSubnet",
 91 | 			ClientListAllFunc: "ListAllSubnet",
 92 | 			HasListFunc:       true,
 93 | 			HasListAllFunc:    true,
 94 | 		},
 95 | 		{
 96 | 			Name:              "Host",
 97 | 			ResourceType:      "host",
 98 | 			Description:       "Host resource",
 99 | 			ClientGetFunc:     "GetHost",
100 | 			ClientListFunc:    "ListHost",
101 | 			ClientListAllFunc: "ListAllHost",
102 | 			HasListFunc:       true,
103 | 			HasListAllFunc:    true,
104 | 		},
105 | 		{
106 | 			Name:              "Project",
107 | 			ResourceType:      "project",
108 | 			Description:       "Project resource",
109 | 			ClientGetFunc:     "GetProject",
110 | 			ClientListFunc:    "ListProject",
111 | 			ClientListAllFunc: "ListAllProject",
112 | 			HasListFunc:       true,
113 | 			HasListAllFunc:    true,
114 | 		},
115 | 		{
116 | 			Name:              "VolumeGroup",
117 | 			ResourceType:      "volumegroup",
118 | 			Description:       "Volume Group resource",
119 | 			ClientGetFunc:     "GetVolumeGroup",
120 | 			ClientListFunc:    "ListVolumeGroup",
121 | 			ClientListAllFunc: "",
122 | 			HasListFunc:       true,
123 | 			HasListAllFunc:    false,
124 | 		},
125 | 		{
126 | 			Name:              "NetworkSecurityRule",
127 | 			ResourceType:      "networksecurityrule",
128 | 			Description:       "Network Security Rule resource",
129 | 			ClientGetFunc:     "GetNetworkSecurityRule",
130 | 			ClientListFunc:    "ListNetworkSecurityRule",
131 | 			ClientListAllFunc: "ListAllNetworkSecurityRule",
132 | 			HasListFunc:       true,
133 | 			HasListAllFunc:    true,
134 | 		},
135 | 		{
136 | 			Name:              "Category",
137 | 			ResourceType:      "category",
138 | 			Description:       "Category resource",
139 | 			ClientGetFunc:     "GetCategoryKey",
140 | 			ClientListFunc:    "ListCategories",
141 | 			ClientListAllFunc: "",
142 | 			HasListFunc:       true,
143 | 			HasListAllFunc:    false,
144 | 		},
145 | 		{
146 | 			Name:              "AccessControlPolicy",
147 | 			ResourceType:      "accesscontrolpolicy",
148 | 			Description:       "Access Control Policy resource",
149 | 			ClientGetFunc:     "GetAccessControlPolicy",
150 | 			ClientListFunc:    "ListAccessControlPolicy",
151 | 			ClientListAllFunc: "ListAllAccessControlPolicy",
152 | 			HasListFunc:       true,
153 | 			HasListAllFunc:    true,
154 | 		},
155 | 		{
156 | 			Name:              "Role",
157 | 			ResourceType:      "role",
158 | 			Description:       "Role resource",
159 | 			ClientGetFunc:     "GetRole",
160 | 			ClientListFunc:    "ListRole",
161 | 			ClientListAllFunc: "ListAllRole",
162 | 			HasListFunc:       true,
163 | 			HasListAllFunc:    true,
164 | 		},
165 | 		{
166 | 			Name:              "User",
167 | 			ResourceType:      "user",
168 | 			Description:       "User resource",
169 | 			ClientGetFunc:     "GetUser",
170 | 			ClientListFunc:    "ListUser",
171 | 			ClientListAllFunc: "ListAllUser",
172 | 			HasListFunc:       true,
173 | 			HasListAllFunc:    true,
174 | 		},
175 | 		{
176 | 			Name:              "UserGroup",
177 | 			ResourceType:      "usergroup",
178 | 			Description:       "User Group resource",
179 | 			ClientGetFunc:     "GetUserGroup",
180 | 			ClientListFunc:    "ListUserGroup",
181 | 			ClientListAllFunc: "ListAllUserGroup",
182 | 			HasListFunc:       true,
183 | 			HasListAllFunc:    true,
184 | 		},
185 | 		{
186 | 			Name:              "Permission",
187 | 			ResourceType:      "permission",
188 | 			Description:       "Permission resource",
189 | 			ClientGetFunc:     "GetPermission",
190 | 			ClientListFunc:    "ListPermission",
191 | 			ClientListAllFunc: "ListAllPermission",
192 | 			HasListFunc:       true,
193 | 			HasListAllFunc:    true,
194 | 		},
195 | 		{
196 | 			Name:              "ProtectionRule",
197 | 			ResourceType:      "protectionrule",
198 | 			Description:       "Protection Rule resource",
199 | 			ClientGetFunc:     "GetProtectionRule",
200 | 			ClientListFunc:    "ListProtectionRules",
201 | 			ClientListAllFunc: "ListAllProtectionRules",
202 | 			HasListFunc:       true,
203 | 			HasListAllFunc:    true,
204 | 		},
205 | 		{
206 | 			Name:              "RecoveryPlan",
207 | 			ResourceType:      "recoveryplan",
208 | 			Description:       "Recovery Plan resource",
209 | 			ClientGetFunc:     "GetRecoveryPlan",
210 | 			ClientListFunc:    "ListRecoveryPlans",
211 | 			ClientListAllFunc: "ListAllRecoveryPlans",
212 | 			HasListFunc:       true,
213 | 			HasListAllFunc:    true,
214 | 		},
215 | 		{
216 | 			Name:              "ServiceGroup",
217 | 			ResourceType:      "servicegroup",
218 | 			Description:       "Service Group resource",
219 | 			ClientGetFunc:     "GetServiceGroup",
220 | 			ClientListFunc:    "",
221 | 			ClientListAllFunc: "ListAllServiceGroups",
222 | 			HasListFunc:       false,
223 | 			HasListAllFunc:    true,
224 | 		},
225 | 		{
226 | 			Name:              "AddressGroup",
227 | 			ResourceType:      "addressgroup",
228 | 			Description:       "Address Group resource",
229 | 			ClientGetFunc:     "GetAddressGroup",
230 | 			ClientListFunc:    "ListAddressGroups",
231 | 			ClientListAllFunc: "ListAllAddressGroups",
232 | 			HasListFunc:       true,
233 | 			HasListAllFunc:    true,
234 | 		},
235 | 		{
236 | 			Name:              "RecoveryPlanJob",
237 | 			ResourceType:      "recoveryplanjob",
238 | 			Description:       "Recovery Plan Job resource",
239 | 			ClientGetFunc:     "GetRecoveryPlanJob",
240 | 			ClientListFunc:    "ListRecoveryPlanJobs",
241 | 			ClientListAllFunc: "",
242 | 			HasListFunc:       true,
243 | 			HasListAllFunc:    false,
244 | 		},
245 | 		{
246 | 			Name:              "AvailabilityZone",
247 | 			ResourceType:      "availabilityzone",
248 | 			Description:       "Availability Zone resource",
249 | 			ClientGetFunc:     "GetAvailabilityZone",
250 | 			ClientListFunc:    "",
251 | 			ClientListAllFunc: "",
252 | 			HasListFunc:       false,
253 | 			HasListAllFunc:    false,
254 | 		},
255 | 	}
256 | }
257 | 
258 | // GenerateResourceFiles generates resource files for all Nutanix resources
259 | func GenerateResourceFiles(baseDir string) error {
260 | 	resources := GetResourceDefinitions()
261 | 
262 | 	// Create the resources directory if it doesn't exist
263 | 	resourcesDir := fmt.Sprintf("%s/pkg/resources", baseDir)
264 | 	err := os.MkdirAll(resourcesDir, 0755)
265 | 	if err != nil {
266 | 		return fmt.Errorf("error creating resources directory: %w", err)
267 | 	}
268 | 
269 | 	// Parse the resource template
270 | 	tmpl, err := template.New("resource").Parse(resourceTemplate)
271 | 	if err != nil {
272 | 		return fmt.Errorf("error parsing resource template: %w", err)
273 | 	}
274 | 
275 | 	// Generate resource files
276 | 	for _, res := range resources {
277 | 		// Create resource file
278 | 		resourceFilePath := fmt.Sprintf("%s/%s.go", resourcesDir, strings.ToLower(res.Name))
279 | 		resourceFile, err := os.Create(resourceFilePath)
280 | 		if err != nil {
281 | 			fmt.Printf("Error creating resource file for %s: %v\n", res.Name, err)
282 | 			continue
283 | 		}
284 | 		defer resourceFile.Close()
285 | 
286 | 		// Execute the template
287 | 		err = tmpl.Execute(resourceFile, res)
288 | 		if err != nil {
289 | 			fmt.Printf("Error executing resource template for %s: %v\n", res.Name, err)
290 | 		}
291 | 	}
292 | 
293 | 	return nil
294 | }
295 | 
```

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

```go
  1 | package main
  2 | 
  3 | import (
  4 | 	"fmt"
  5 | 	"os"
  6 | 
  7 | 	"github.com/thunderboltsid/mcp-nutanix/internal/client"
  8 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/prompts"
  9 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/resources"
 10 | 	"github.com/thunderboltsid/mcp-nutanix/pkg/tools"
 11 | 
 12 | 	"github.com/mark3labs/mcp-go/mcp"
 13 | 	"github.com/mark3labs/mcp-go/server"
 14 | )
 15 | 
 16 | // ToolRegistration holds a tool function and its handler
 17 | type ToolRegistration struct {
 18 | 	Func    func() mcp.Tool
 19 | 	Handler server.ToolHandlerFunc
 20 | }
 21 | 
 22 | // ResourceRegistration represents a resource and its associated tools
 23 | type ResourceRegistration struct {
 24 | 	Tools           []ToolRegistration
 25 | 	ResourceFunc    func() mcp.ResourceTemplate
 26 | 	ResourceHandler server.ResourceTemplateHandlerFunc
 27 | }
 28 | 
 29 | // initializeFromEnvIfAvailable initializes the Prism client only if environment variables are available
 30 | func initializeFromEnvIfAvailable() {
 31 | 	endpoint := os.Getenv("NUTANIX_ENDPOINT")
 32 | 	username := os.Getenv("NUTANIX_USERNAME")
 33 | 	password := os.Getenv("NUTANIX_PASSWORD")
 34 | 
 35 | 	// Only initialize if all required environment variables are set
 36 | 	// This allows prompt-based initialization to work when env vars are not present
 37 | 	if endpoint != "" && username != "" && password != "" {
 38 | 		client.Init(client.PrismClientProvider)
 39 | 		fmt.Printf("Initialized Prism client from environment variables for endpoint: %s\n", endpoint)
 40 | 	}
 41 | }
 42 | 
 43 | func main() {
 44 | 	// Initialize the Prism client only if environment variables are available
 45 | 	initializeFromEnvIfAvailable()
 46 | 
 47 | 	// Define server hooks for logging and debugging
 48 | 	hooks := &server.Hooks{}
 49 | 	hooks.AddOnError(func(id any, method mcp.MCPMethod, message any, err error) {
 50 | 		fmt.Printf("onError: %s, %v, %v, %v\n", method, id, message, err)
 51 | 	})
 52 | 
 53 | 	// Log level based on environment variable
 54 | 	debugMode := os.Getenv("DEBUG") != ""
 55 | 	if debugMode {
 56 | 		hooks.AddBeforeAny(func(id any, method mcp.MCPMethod, message any) {
 57 | 			fmt.Printf("beforeAny: %s, %v, %v\n", method, id, message)
 58 | 		})
 59 | 		hooks.AddOnSuccess(func(id any, method mcp.MCPMethod, message any, result any) {
 60 | 			fmt.Printf("onSuccess: %s, %v, %v, %v\n", method, id, message, result)
 61 | 		})
 62 | 		hooks.AddBeforeInitialize(func(id any, message *mcp.InitializeRequest) {
 63 | 			fmt.Printf("beforeInitialize: %v, %v\n", id, message)
 64 | 		})
 65 | 		hooks.AddAfterInitialize(func(id any, message *mcp.InitializeRequest, result *mcp.InitializeResult) {
 66 | 			fmt.Printf("afterInitialize: %v, %v, %v\n", id, message, result)
 67 | 		})
 68 | 		hooks.AddAfterCallTool(func(id any, message *mcp.CallToolRequest, result *mcp.CallToolResult) {
 69 | 			fmt.Printf("afterCallTool: %v, %v, %v\n", id, message, result)
 70 | 		})
 71 | 		hooks.AddBeforeCallTool(func(id any, message *mcp.CallToolRequest) {
 72 | 			fmt.Printf("beforeCallTool: %v, %v\n", id, message)
 73 | 		})
 74 | 	}
 75 | 
 76 | 	// Create a new MCP server
 77 | 	s := server.NewMCPServer(
 78 | 		"Prism Central",
 79 | 		"0.0.1",
 80 | 		server.WithResourceCapabilities(true, true),
 81 | 		server.WithPromptCapabilities(true),
 82 | 		server.WithLogging(),
 83 | 		server.WithHooks(hooks),
 84 | 	)
 85 | 
 86 | 	// Add the prompts
 87 | 	s.AddPrompt(prompts.SetCredentials(), prompts.SetCredentialsResponse())
 88 | 
 89 | 	// Add standalone tools
 90 | 	s.AddTool(tools.ApiNamespacesList(), tools.ApiNamespacesListHandler())
 91 | 
 92 | 	// Define all resources and tools
 93 | 	resourceRegistrations := map[string]ResourceRegistration{
 94 | 		"vm": {
 95 | 			Tools: []ToolRegistration{
 96 | 				{
 97 | 					Func:    tools.VMList,
 98 | 					Handler: tools.VMListHandler(),
 99 | 				},
100 | 				{
101 | 					Func:    tools.VMCount,
102 | 					Handler: tools.VMCountHandler(),
103 | 				},
104 | 			},
105 | 			ResourceFunc:    resources.VM,
106 | 			ResourceHandler: resources.VMHandler(),
107 | 		},
108 | 		"cluster": {
109 | 			Tools: []ToolRegistration{
110 | 				{
111 | 					Func:    tools.ClusterList,
112 | 					Handler: tools.ClusterListHandler(),
113 | 				},
114 | 				{
115 | 					Func:    tools.ClusterCount,
116 | 					Handler: tools.ClusterCountHandler(),
117 | 				},
118 | 			},
119 | 			ResourceFunc:    resources.Cluster,
120 | 			ResourceHandler: resources.ClusterHandler(),
121 | 		},
122 | 		"host": {
123 | 			Tools: []ToolRegistration{
124 | 				{
125 | 					Func:    tools.HostList,
126 | 					Handler: tools.HostListHandler(),
127 | 				},
128 | 				{
129 | 					Func:    tools.HostCount,
130 | 					Handler: tools.HostCountHandler(),
131 | 				},
132 | 			},
133 | 			ResourceFunc:    resources.Host,
134 | 			ResourceHandler: resources.HostHandler(),
135 | 		},
136 | 		"image": {
137 | 			Tools: []ToolRegistration{
138 | 				{
139 | 					Func:    tools.ImageList,
140 | 					Handler: tools.ImageListHandler(),
141 | 				},
142 | 				{
143 | 					Func:    tools.ImageCount,
144 | 					Handler: tools.ImageCountHandler(),
145 | 				},
146 | 			},
147 | 			ResourceFunc:    resources.Image,
148 | 			ResourceHandler: resources.ImageHandler(),
149 | 		},
150 | 		"subnet": {
151 | 			Tools: []ToolRegistration{
152 | 				{
153 | 					Func:    tools.SubnetList,
154 | 					Handler: tools.SubnetListHandler(),
155 | 				},
156 | 				{
157 | 					Func:    tools.SubnetCount,
158 | 					Handler: tools.SubnetCountHandler(),
159 | 				},
160 | 			},
161 | 			ResourceFunc:    resources.Subnet,
162 | 			ResourceHandler: resources.SubnetHandler(),
163 | 		},
164 | 		"project": {
165 | 			Tools: []ToolRegistration{
166 | 				{
167 | 					Func:    tools.ProjectList,
168 | 					Handler: tools.ProjectListHandler(),
169 | 				},
170 | 				{
171 | 					Func:    tools.ProjectCount,
172 | 					Handler: tools.ProjectCountHandler(),
173 | 				},
174 | 			},
175 | 			ResourceFunc:    resources.Project,
176 | 			ResourceHandler: resources.ProjectHandler(),
177 | 		},
178 | 		"volumegroup": {
179 | 			Tools: []ToolRegistration{
180 | 				{
181 | 					Func:    tools.VolumeGroupList,
182 | 					Handler: tools.VolumeGroupListHandler(),
183 | 				},
184 | 				{
185 | 					Func:    tools.VolumeGroupCount,
186 | 					Handler: tools.VolumeGroupCountHandler(),
187 | 				},
188 | 			},
189 | 			ResourceFunc:    resources.VolumeGroup,
190 | 			ResourceHandler: resources.VolumeGroupHandler(),
191 | 		},
192 | 		"networksecurityrule": {
193 | 			Tools: []ToolRegistration{
194 | 				{
195 | 					Func:    tools.NetworkSecurityRuleList,
196 | 					Handler: tools.NetworkSecurityRuleListHandler(),
197 | 				},
198 | 				{
199 | 					Func:    tools.NetworkSecurityRuleCount,
200 | 					Handler: tools.NetworkSecurityRuleCountHandler(),
201 | 				},
202 | 			},
203 | 			ResourceFunc:    resources.NetworkSecurityRule,
204 | 			ResourceHandler: resources.NetworkSecurityRuleHandler(),
205 | 		},
206 | 		"category": {
207 | 			Tools: []ToolRegistration{
208 | 				{
209 | 					Func:    tools.CategoryList,
210 | 					Handler: tools.CategoryListHandler(),
211 | 				},
212 | 				{
213 | 					Func:    tools.CategoryCount,
214 | 					Handler: tools.CategoryCountHandler(),
215 | 				},
216 | 			},
217 | 			ResourceFunc:    resources.Category,
218 | 			ResourceHandler: resources.CategoryHandler(),
219 | 		},
220 | 		"accesscontrolpolicy": {
221 | 			Tools: []ToolRegistration{
222 | 				{
223 | 					Func:    tools.AccessControlPolicyList,
224 | 					Handler: tools.AccessControlPolicyListHandler(),
225 | 				},
226 | 				{
227 | 					Func:    tools.AccessControlPolicyCount,
228 | 					Handler: tools.AccessControlPolicyCountHandler(),
229 | 				},
230 | 			},
231 | 			ResourceFunc:    resources.AccessControlPolicy,
232 | 			ResourceHandler: resources.AccessControlPolicyHandler(),
233 | 		},
234 | 		"role": {
235 | 			Tools: []ToolRegistration{
236 | 				{
237 | 					Func:    tools.RoleList,
238 | 					Handler: tools.RoleListHandler(),
239 | 				},
240 | 				{
241 | 					Func:    tools.RoleCount,
242 | 					Handler: tools.RoleCountHandler(),
243 | 				},
244 | 			},
245 | 			ResourceFunc:    resources.Role,
246 | 			ResourceHandler: resources.RoleHandler(),
247 | 		},
248 | 		"user": {
249 | 			Tools: []ToolRegistration{
250 | 				{
251 | 					Func:    tools.UserList,
252 | 					Handler: tools.UserListHandler(),
253 | 				},
254 | 				{
255 | 					Func:    tools.UserCount,
256 | 					Handler: tools.UserCountHandler(),
257 | 				},
258 | 			},
259 | 			ResourceFunc:    resources.User,
260 | 			ResourceHandler: resources.UserHandler(),
261 | 		},
262 | 		"usergroup": {
263 | 			Tools: []ToolRegistration{
264 | 				{
265 | 					Func:    tools.UserGroupList,
266 | 					Handler: tools.UserGroupListHandler(),
267 | 				},
268 | 				{
269 | 					Func:    tools.UserGroupCount,
270 | 					Handler: tools.UserGroupCountHandler(),
271 | 				},
272 | 			},
273 | 			ResourceFunc:    resources.UserGroup,
274 | 			ResourceHandler: resources.UserGroupHandler(),
275 | 		},
276 | 		"permission": {
277 | 			Tools: []ToolRegistration{
278 | 				{
279 | 					Func:    tools.PermissionList,
280 | 					Handler: tools.PermissionListHandler(),
281 | 				},
282 | 				{
283 | 					Func:    tools.PermissionCount,
284 | 					Handler: tools.PermissionCountHandler(),
285 | 				},
286 | 			},
287 | 			ResourceFunc:    resources.Permission,
288 | 			ResourceHandler: resources.PermissionHandler(),
289 | 		},
290 | 		"protectionrule": {
291 | 			Tools: []ToolRegistration{
292 | 				{
293 | 					Func:    tools.ProtectionRuleList,
294 | 					Handler: tools.ProtectionRuleListHandler(),
295 | 				},
296 | 				{
297 | 					Func:    tools.ProtectionRuleCount,
298 | 					Handler: tools.ProtectionRuleCountHandler(),
299 | 				},
300 | 			},
301 | 			ResourceFunc:    resources.ProtectionRule,
302 | 			ResourceHandler: resources.ProtectionRuleHandler(),
303 | 		},
304 | 		"recoveryplan": {
305 | 			Tools: []ToolRegistration{
306 | 				{
307 | 					Func:    tools.RecoveryPlanList,
308 | 					Handler: tools.RecoveryPlanListHandler(),
309 | 				},
310 | 				{
311 | 					Func:    tools.RecoveryPlanCount,
312 | 					Handler: tools.RecoveryPlanCountHandler(),
313 | 				},
314 | 			},
315 | 			ResourceFunc:    resources.RecoveryPlan,
316 | 			ResourceHandler: resources.RecoveryPlanHandler(),
317 | 		},
318 | 		"servicegroup": {
319 | 			Tools: []ToolRegistration{
320 | 				{
321 | 					Func:    tools.ServiceGroupList,
322 | 					Handler: tools.ServiceGroupListHandler(),
323 | 				},
324 | 				{
325 | 					Func:    tools.ServiceGroupCount,
326 | 					Handler: tools.ServiceGroupCountHandler(),
327 | 				},
328 | 			},
329 | 			ResourceFunc:    resources.ServiceGroup,
330 | 			ResourceHandler: resources.ServiceGroupHandler(),
331 | 		},
332 | 		"addressgroup": {
333 | 			Tools: []ToolRegistration{
334 | 				{
335 | 					Func:    tools.AddressGroupList,
336 | 					Handler: tools.AddressGroupListHandler(),
337 | 				},
338 | 				{
339 | 					Func:    tools.AddressGroupCount,
340 | 					Handler: tools.AddressGroupCountHandler(),
341 | 				},
342 | 			},
343 | 			ResourceFunc:    resources.AddressGroup,
344 | 			ResourceHandler: resources.AddressGroupHandler(),
345 | 		},
346 | 		"recoveryplanjob": {
347 | 			Tools: []ToolRegistration{
348 | 				{
349 | 					Func:    tools.RecoveryPlanJobList,
350 | 					Handler: tools.RecoveryPlanJobListHandler(),
351 | 				},
352 | 				{
353 | 					Func:    tools.RecoveryPlanJobCount,
354 | 					Handler: tools.RecoveryPlanJobCountHandler(),
355 | 				},
356 | 			},
357 | 			ResourceFunc:    resources.RecoveryPlanJob,
358 | 			ResourceHandler: resources.RecoveryPlanJobHandler(),
359 | 		},
360 | 	}
361 | 
362 | 	// Register all tools and resources
363 | 	for name, registration := range resourceRegistrations {
364 | 		// Add all tools
365 | 		for _, tool := range registration.Tools {
366 | 			s.AddTool(tool.Func(), tool.Handler)
367 | 			if debugMode {
368 | 				fmt.Printf("Registered %s resource and tool\n", name)
369 | 			}
370 | 		}
371 | 
372 | 		// Add the resource
373 | 		s.AddResourceTemplate(registration.ResourceFunc(), registration.ResourceHandler)
374 | 	}
375 | 
376 | 	// Start the server
377 | 	if err := server.ServeStdio(s); err != nil {
378 | 		fmt.Printf("Server error: %v\n", err)
379 | 	}
380 | }
381 | 
```