Skip to content

Commit b72b344

Browse files
hingerabhinavHarness
authored andcommitted
fix: [ML-1174]: template fixes for mcp (#69)
* add recursive, entity type param to the tool * address comments * refactor common code * remove unused param from api * fix: [ML-1174]: template fixes for mcp
1 parent 39e1a16 commit b72b344

File tree

5 files changed

+97
-54
lines changed

5 files changed

+97
-54
lines changed

client/dto/audit.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ type AuditOutputData[T any] struct {
8080
PageIndex int `json:"pageIndex,omitempty"`
8181
HasNext bool `json:"hasNext,omitempty"`
8282
PageToken string `json:"pageToken,omitempty"`
83-
TotalItems int `json:totalItems, omitempty`
84-
TotalPages int `json:totalPages, omitempty`
83+
TotalItems int `json:"totalItems,omitempty"`
84+
TotalPages int `json:"totalPages,omitempty"`
8585
}
8686

8787
type AuditListItem struct {

client/dto/template.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,24 @@ package dto
22

33
// TemplateListOptions represents options for listing templates
44
type TemplateListOptions struct {
5-
SearchTerm string `json:"search_term,omitempty"`
6-
TemplateListType string `json:"template_list_type,omitempty"`
7-
PaginationOptions
5+
// Pagination parameters
6+
Page int `json:"page,omitempty"` // Default: 0
7+
Limit int `json:"limit,omitempty"` // Default: 30
8+
9+
// Sorting parameters
10+
Sort string `json:"sort,omitempty"` // Enum: "identifier" "name" "updated"
11+
Order string `json:"order,omitempty"` // Enum: "ASC" "DESC"
12+
13+
// Filtering parameters
14+
SearchTerm string `json:"search_term,omitempty"` // Filter resources having attributes matching with search term
15+
Type string `json:"type,omitempty"` // Template List Type: Enum: "STABLE_TEMPLATE" "LAST_UPDATES_TEMPLATE" "ALL"
16+
Recursive bool `json:"recursive,omitempty"` // Default: false - Specify true if all accessible Templates are to be included
17+
18+
// List filtering
19+
Names []string `json:"names,omitempty"` // Template names for filtering
20+
Identifiers []string `json:"identifiers,omitempty"` // Template Ids for Filtering
21+
EntityTypes []string `json:"entity_types,omitempty"` // Type of Template - Enum: "Step" "Stage" "Pipeline" "CustomDeployment" "MonitoredService" "SecretManager"
22+
ChildTypes []string `json:"child_types,omitempty"` // Child types describe the type of Step or stage
823
}
924

1025
// TemplateMetadataSummaryResponse represents a template metadata summary

client/templates.go

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package client
33
import (
44
"context"
55
"fmt"
6+
"strconv"
67

78
"github.com/harness/harness-mcp/client/dto"
89
)
@@ -15,27 +16,64 @@ const (
1516
)
1617

1718
type TemplateService struct {
18-
Client *Client
19-
UseInternalPaths bool
19+
Client *Client
2020
}
2121

2222
func (ts *TemplateService) buildPath(basePath string) string {
2323
return basePath
2424
}
2525

26-
// ListAccount lists templates in the account scope
27-
func (ts *TemplateService) ListAccount(ctx context.Context, opts *dto.TemplateListOptions) (*dto.TemplateMetaDataList, error) {
28-
endpoint := ts.buildPath(templateAccountPath)
29-
26+
// buildTemplateParams converts template list options to query parameters map
27+
func buildTemplateParams(opts *dto.TemplateListOptions) map[string]string {
3028
params := make(map[string]string)
29+
30+
if opts == nil {
31+
opts = &dto.TemplateListOptions{}
32+
}
33+
34+
// Pagination params
35+
params["page"] = strconv.Itoa(opts.Page)
36+
params["limit"] = strconv.Itoa(opts.Limit)
37+
38+
// Sorting params
39+
if opts.Sort != "" {
40+
params["sort"] = opts.Sort
41+
}
42+
if opts.Order != "" {
43+
params["order"] = opts.Order
44+
}
45+
46+
// Filtering params
3147
if opts.SearchTerm != "" {
32-
params["searchTerm"] = opts.SearchTerm
48+
params["search_term"] = opts.SearchTerm
49+
}
50+
if opts.Type != "" {
51+
params["type"] = opts.Type
3352
}
34-
if opts.TemplateListType != "" {
35-
params["templateListType"] = opts.TemplateListType
53+
if opts.Recursive {
54+
params["recursive"] = "true"
55+
}
56+
57+
appendArrayParams(params, "names", opts.Names)
58+
appendArrayParams(params, "identifiers", opts.Identifiers)
59+
appendArrayParams(params, "entity_types", opts.EntityTypes)
60+
appendArrayParams(params, "child_types", opts.ChildTypes)
61+
62+
return params
63+
}
64+
65+
func appendArrayParams(params map[string]string, paramName string, values []string) {
66+
for i, value := range values {
67+
// Use strconv.Itoa instead of fmt.Sprintf for integer to string conversion
68+
key := paramName + "[" + strconv.Itoa(i) + "]"
69+
params[key] = value
3670
}
37-
params["page"] = fmt.Sprintf("%d", opts.Page)
38-
params["size"] = fmt.Sprintf("%d", opts.Size)
71+
}
72+
73+
// ListAccount lists templates in the account scope
74+
func (ts *TemplateService) ListAccount(ctx context.Context, opts *dto.TemplateListOptions) (*dto.TemplateMetaDataList, error) {
75+
endpoint := ts.buildPath(templateAccountPath)
76+
params := buildTemplateParams(opts)
3977

4078
var result dto.TemplateMetaDataList
4179
err := ts.Client.Get(ctx, endpoint, params, map[string]string{}, &result)
@@ -49,17 +87,7 @@ func (ts *TemplateService) ListAccount(ctx context.Context, opts *dto.TemplateLi
4987
// ListOrg lists templates in the organization scope
5088
func (ts *TemplateService) ListOrg(ctx context.Context, scope dto.Scope, opts *dto.TemplateListOptions) (*dto.TemplateMetaDataList, error) {
5189
endpoint := ts.buildPath(fmt.Sprintf(templateOrgPath, scope.OrgID))
52-
53-
params := make(map[string]string)
54-
addScope(scope, params)
55-
if opts.SearchTerm != "" {
56-
params["searchTerm"] = opts.SearchTerm
57-
}
58-
if opts.TemplateListType != "" {
59-
params["templateListType"] = opts.TemplateListType
60-
}
61-
params["page"] = fmt.Sprintf("%d", opts.Page)
62-
params["size"] = fmt.Sprintf("%d", opts.Size)
90+
params := buildTemplateParams(opts)
6391

6492
var result dto.TemplateMetaDataList
6593
err := ts.Client.Get(ctx, endpoint, params, map[string]string{}, &result)
@@ -73,17 +101,7 @@ func (ts *TemplateService) ListOrg(ctx context.Context, scope dto.Scope, opts *d
73101
// ListProject lists templates in the project scope
74102
func (ts *TemplateService) ListProject(ctx context.Context, scope dto.Scope, opts *dto.TemplateListOptions) (*dto.TemplateMetaDataList, error) {
75103
endpoint := ts.buildPath(fmt.Sprintf(templateProjectPath, scope.OrgID, scope.ProjectID))
76-
77-
params := make(map[string]string)
78-
addScope(scope, params)
79-
if opts.SearchTerm != "" {
80-
params["searchTerm"] = opts.SearchTerm
81-
}
82-
if opts.TemplateListType != "" {
83-
params["templateListType"] = opts.TemplateListType
84-
}
85-
params["page"] = fmt.Sprintf("%d", opts.Page)
86-
params["size"] = fmt.Sprintf("%d", opts.Size)
104+
params := buildTemplateParams(opts)
87105

88106
var result dto.TemplateMetaDataList
89107
err := ts.Client.Get(ctx, endpoint, params, map[string]string{}, &result)

pkg/harness/templates.go

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,17 @@ func ListTemplates(config *config.Config, client *client.TemplateService) (tool
2020
mcp.WithString("search_term",
2121
mcp.Description("Optional search term to filter templates"),
2222
),
23-
mcp.WithString("template_list_type",
24-
mcp.Description("Type of templates to list (e.g., Step, Stage, Pipeline)"),
23+
mcp.WithString("entity_type",
24+
mcp.Description("Type of Template - Enum: Step, Stage, Pipeline, CustomDeployment, MonitoredService, SecretManager"),
25+
mcp.Enum("Step", "Stage", "Pipeline", "CustomDeployment", "MonitoredService", "SecretManager"),
2526
),
2627
mcp.WithString("scope",
2728
mcp.Description("Scope level to query templates from (account, org, project). If not specified, defaults to project if org_id and project_id are provided, org if only org_id is provided, or account otherwise."),
2829
mcp.Enum("account", "org", "project"),
2930
),
31+
mcp.WithBoolean("recursive",
32+
mcp.Description("If true, returns all supported templates at the specified scope. Default: false"),
33+
),
3034
WithScope(config, false),
3135
WithPagination(),
3236
),
@@ -43,19 +47,29 @@ func ListTemplates(config *config.Config, client *client.TemplateService) (tool
4347
return mcp.NewToolResultError(err.Error()), nil
4448
}
4549

46-
templateListType, err := OptionalParam[string](request, "template_list_type")
50+
// Get entity_type parameter if provided
51+
entityType, err := OptionalParam[string](request, "entity_type")
52+
if err != nil {
53+
return mcp.NewToolResultError(err.Error()), nil
54+
}
55+
56+
// Get recursive parameter (defaults to false if not provided)
57+
recursive, err := OptionalParam[bool](request, "recursive")
4758
if err != nil {
4859
return mcp.NewToolResultError(err.Error()), nil
4960
}
5061

5162
// Create options object
5263
opts := &dto.TemplateListOptions{
53-
SearchTerm: searchTerm,
54-
TemplateListType: templateListType,
55-
PaginationOptions: dto.PaginationOptions{
56-
Page: page,
57-
Size: size,
58-
},
64+
SearchTerm: searchTerm,
65+
Page: page,
66+
Limit: size,
67+
Recursive: recursive,
68+
}
69+
70+
// Add entity_type to EntityTypes array if provided
71+
if entityType != "" {
72+
opts.EntityTypes = []string{entityType}
5973
}
6074

6175
// Determine scope from parameters

pkg/harness/tools.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -756,11 +756,8 @@ func registerChaos(config *config.Config, tsg *toolsets.ToolsetGroup) error {
756756
// registerTemplates registers the templates toolset
757757
func registerTemplates(config *config.Config, tsg *toolsets.ToolsetGroup) error {
758758
// Determine the base URL and secret for templates
759-
baseURL := config.BaseURL
759+
baseURL := buildServiceURL(config, config.TemplateSvcBaseURL, config.BaseURL, "")
760760
secret := config.TemplateSvcSecret
761-
if config.Internal {
762-
baseURL = config.TemplateSvcBaseURL
763-
}
764761

765762
// Create base client for templates
766763
c, err := createClient(baseURL, config, secret)
@@ -769,8 +766,7 @@ func registerTemplates(config *config.Config, tsg *toolsets.ToolsetGroup) error
769766
}
770767

771768
templateClient := &client.TemplateService{
772-
Client: c,
773-
UseInternalPaths: config.Internal,
769+
Client: c,
774770
}
775771

776772
// Create the templates toolset
@@ -791,7 +787,7 @@ func registerIntelligence(config *config.Config, tsg *toolsets.ToolsetGroup) err
791787
secret := config.IntelligenceSvcSecret
792788

793789
// Create base client for intelligence service
794-
c, err := createClient(baseURL, config, secret)
790+
c, err := createClientWithIdentity(baseURL, config, secret, aiServiceIdentity)
795791
if err != nil {
796792
return err
797793
}

0 commit comments

Comments
 (0)