Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions descriptions/descriptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,7 @@ const SearchOntapEndpoints = `Search the catalog by keyword across endpoint path
const DescribeOntapEndpoint = `Get filterable query params for an endpoint. Call before ontap_get to learn valid filter names and which sub-objects need explicit fields (e.g. "space.*", "efficiency.*").
Pass cluster_name to automatically filter out fields and filters not available in that cluster's ONTAP version.`

const CreateSVM = `Create an SVM on a cluster by cluster name.`
const UpdateSVM = `Update an SVM on a cluster by cluster name.`
const DeleteSVM = `Delete an SVM on a cluster by cluster name.`
const SVMOperation = `Create, Update and Delete operations on SVM on a cluster by cluster name.`
const DeleteSVMPeer = `Delete an SVM peer on a cluster by cluster name and local SVM name. The peer relationship UUID is looked up internally using the svm.name filter.`

const OntapGet = `Execute a read-only GET against any ONTAP REST endpoint.
Expand Down
7 changes: 4 additions & 3 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,7 @@ func (a *App) createMCPServer() *mcp.Server {
addTool(a, server, "delete_nfs_export_policies_rules", descriptions.DeleteNFSExportPolicyRules, deleteAnnotation, a.DeleteNFSExportPoliciesRule)

// operation on SVM object
addTool(a, server, "create_svm", descriptions.CreateSVM, createAnnotation, a.CreateSVM)
addTool(a, server, "update_svm", descriptions.UpdateSVM, updateAnnotation, a.UpdateSVM)
addTool(a, server, "delete_svm", descriptions.DeleteSVM, deleteAnnotation, a.DeleteSVM)
addTool(a, server, "svm_operation", descriptions.SVMOperation, operationAnnotation, a.SVMOperation)
Comment on lines 149 to +150
// operation on SVM peer object
Comment on lines 149 to 151
addTool(a, server, "delete_svm_peer", descriptions.DeleteSVMPeer, deleteAnnotation, a.DeleteSVMPeer)

Expand Down Expand Up @@ -656,6 +654,9 @@ var (
DestructiveHint: new(true),
IdempotentHint: true,
}
operationAnnotation = mcp.ToolAnnotations{
DestructiveHint: new(true),
}
Comment thread
Hardikl marked this conversation as resolved.
Comment on lines +657 to +659
)

func addTool[In, Out any](a *App, server *mcp.Server, name string, description string, annotations mcp.ToolAnnotations, handler mcp.ToolHandlerFor[In, Out]) {
Expand Down
124 changes: 44 additions & 80 deletions server/svm.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,105 +9,69 @@ import (
"github.com/netapp/ontap-mcp/tool"
)

func (a *App) CreateSVM(ctx context.Context, _ *mcp.CallToolRequest, parameters tool.SVMCreate) (*mcp.CallToolResult, any, error) {
func (a *App) SVMOperation(ctx context.Context, _ *mcp.CallToolRequest, parameters tool.SVMOperation) (*mcp.CallToolResult, any, error) {
if !a.locks.TryLock(parameters.Cluster) {
return errorResult(fmt.Errorf("another write operation is in progress on cluster %s, please try again", parameters.Cluster)), nil, nil
}
defer a.locks.Unlock(parameters.Cluster)

svmCreate, err := newCreateSVM(parameters)
if err != nil {
return nil, nil, err
}

client, err := a.getClient(parameters.Cluster)
if err != nil {
return errorResult(err), nil, err
}

err = client.CreateSVM(ctx, svmCreate)
if err != nil {
return errorResult(err), nil, err
}

return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: "SVM created successfully"},
},
}, nil, nil
}

func (a *App) UpdateSVM(ctx context.Context, _ *mcp.CallToolRequest, parameters tool.SVM) (*mcp.CallToolResult, any, error) {
if !a.locks.TryLock(parameters.Cluster) {
return errorResult(fmt.Errorf("another write operation is in progress on cluster %s, please try again", parameters.Cluster)), nil, nil
}
defer a.locks.Unlock(parameters.Cluster)

svmUpdate, err := newUpdateSVM(parameters)
if err != nil {
return nil, nil, err
}

client, err := a.getClient(parameters.Cluster)
if err != nil {
return errorResult(err), nil, err
}

err = client.UpdateSVM(ctx, svmUpdate, parameters.Name)
if err != nil {
return errorResult(err), nil, err
}

return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: "SVM updated successfully"},
},
}, nil, nil
}

func (a *App) DeleteSVM(ctx context.Context, _ *mcp.CallToolRequest, parameters tool.SVM) (*mcp.CallToolResult, any, error) {
if !a.locks.TryLock(parameters.Cluster) {
return errorResult(fmt.Errorf("another write operation is in progress on cluster %s, please try again", parameters.Cluster)), nil, nil
}
defer a.locks.Unlock(parameters.Cluster)

if parameters.Name == "" {
return nil, nil, errors.New("SVM name is required")
}

client, err := a.getClient(parameters.Cluster)
if err != nil {
return errorResult(err), nil, err
switch parameters.Operation {
case "create":
svmCreate := ontap.SVMCreate{Name: parameters.Name}
err = client.CreateSVM(ctx, svmCreate)
if err != nil {
return errorResult(err), nil, err
}

return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: "SVM created successfully"},
},
}, nil, nil
case "update":
svmUpdate, err := updateSVMValidation(parameters.SVMUpdate)
if err != nil {
return nil, nil, err
}

err = client.UpdateSVM(ctx, svmUpdate, parameters.Name)
if err != nil {
return errorResult(err), nil, err
}

return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: "SVM updated successfully"},
},
}, nil, nil
case "delete":
err = client.DeleteSVM(ctx, parameters.Name)
if err != nil {
return errorResult(err), nil, err
}

return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: "SVM deleted successfully"},
},
}, nil, nil
default:
return errorResult(fmt.Errorf("unsupported type_operation %q; supported values: create, update, delete", parameters.Operation)), nil, nil
}

err = client.DeleteSVM(ctx, parameters.Name)
if err != nil {
return errorResult(err), nil, err
}

return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: "SVM deleted successfully"},
},
}, nil, nil
}

func newCreateSVM(in tool.SVMCreate) (ontap.SVMCreate, error) {
out := ontap.SVMCreate{}
if in.Name == "" {
return out, errors.New("SVM name is required")
}
out.Name = in.Name
return out, nil
}

func newUpdateSVM(in tool.SVM) (ontap.SVM, error) {
func updateSVMValidation(in tool.SVMUpdate) (ontap.SVM, error) {
out := ontap.SVM{}

if in.Name == "" {
return out, errors.New("SVM name is required")
}

hasUpdate := false
if in.NewName != "" {
out.Name = in.NewName
Expand Down
12 changes: 6 additions & 6 deletions tool/tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,14 +351,14 @@ type DNSServiceDelete struct {
SkipConfigValidation bool `json:"skip_config_validation,omitzero" jsonschema:"Indicates whether or not the validation for the specified DNS configuration is disabled."`
}

type SVMCreate struct {
Cluster string `json:"cluster_name" jsonschema:"cluster name"`
Name string `json:"svm_name" jsonschema:"SVM name"`
type SVMOperation struct {
Cluster string `json:"cluster_name" jsonschema:"cluster name"`
Operation string `json:"operation" jsonschema:"SVM operation type (e.g., create, update, delete)"`
Name string `json:"svm_name" jsonschema:"SVM name"`
Comment thread
Hardikl marked this conversation as resolved.
SVMUpdate SVMUpdate `json:"svm_update,omitzero" jsonschema:"update SVM operation"`
}

type SVM struct {
Cluster string `json:"cluster_name" jsonschema:"cluster name"`
Name string `json:"svm_name" jsonschema:"SVM name"`
type SVMUpdate struct {
NewName string `json:"new_name,omitzero" jsonschema:"new name of SVM"`
State string `json:"state,omitzero" jsonschema:"state of SVM (e.g., starting, running, stopping, stopped, deleting, initializing)"`
Comment string `json:"comment,omitzero" jsonschema:"comment"`
Expand Down
Loading