Skip to content

Commit 8950b00

Browse files
Saranya-jenaHarness
authored andcommitted
chore: [ML-1395]: Updated download logs tool to accept prefix argument (#191)
* fb760e lets call it log key wherever possible (#210) * d41a28 chore: [ML-1395]: Resolved comments * 210394 chore: [ML-1395]: Resolved comments * 71fbee chore: [ML-1395]: Resolved comments * e40cd3 chore: [ML-1395]: Resolved conflicts * 1de7af chore: [ML-1395]: update gci version * ff71a0 Merge branch 'master' of https://git0.harness.io/l7B_kbSEQD2wjrM7PShm5w/PROD/Harness_Commons/mcp-server into ML-1395 * 85817c chore: [ML-1395]: Updated download logs tool to accept prefix argument
1 parent c483877 commit 8950b00

File tree

2 files changed

+43
-28
lines changed

2 files changed

+43
-28
lines changed

client/logs.go

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package client
33
import (
44
"context"
55
"fmt"
6+
"log/slog"
67
"time"
78

89
"github.com/harness/harness-mcp/client/dto"
@@ -19,37 +20,46 @@ type LogService struct {
1920
}
2021

2122
// DownloadLogs fetches a download URL for pipeline execution logs
22-
func (l *LogService) DownloadLogs(ctx context.Context, scope dto.Scope, planExecutionID string) (string, error) {
23-
// First, get the pipeline execution details to determine the prefix format
24-
pipelineService := &PipelineService{Client: l.PipelineClient} // TODO: needs to be changed for internal case, we should move this above
25-
execution, err := pipelineService.GetExecution(ctx, scope, planExecutionID)
26-
if err != nil {
27-
return "", fmt.Errorf("failed to get execution details: %w", err)
28-
}
29-
30-
// Build the prefix based on the execution details
31-
var prefix string
32-
if execution.Data.ShouldUseSimplifiedBaseKey {
33-
// Simplified key format
34-
prefix = fmt.Sprintf("%s/pipeline/%s/%d/-%s",
35-
scope.AccountID,
36-
execution.Data.PipelineIdentifier,
37-
execution.Data.RunSequence,
38-
planExecutionID)
23+
// If logKey is not empty, it will use that log key to fetch logs instead of building one from execution details
24+
func (l *LogService) DownloadLogs(ctx context.Context, scope dto.Scope, planExecutionID string, logKey string) (string, error) {
25+
// Use custom log key if provided, otherwise build it from execution details
26+
var finalLogKey string
27+
var err error
28+
if logKey != "" {
29+
slog.Info("Using custom log key for log download", "logKey", logKey)
30+
finalLogKey = logKey
3931
} else {
40-
// Standard key format
41-
prefix = fmt.Sprintf("accountId:%s/orgId:%s/projectId:%s/pipelineId:%s/runSequence:%d/level0:pipeline",
42-
scope.AccountID,
43-
execution.Data.OrgIdentifier,
44-
execution.Data.ProjectIdentifier,
45-
execution.Data.PipelineIdentifier,
46-
execution.Data.RunSequence)
32+
slog.Info("Building log key for log download from execution details")
33+
// First, get the pipeline execution details to determine the prefix format
34+
pipelineService := &PipelineService{Client: l.PipelineClient} // TODO: needs to be changed for internal case, we should move this above
35+
execution, err := pipelineService.GetExecution(ctx, scope, planExecutionID)
36+
if err != nil {
37+
return "", fmt.Errorf("failed to get execution details: %w", err)
38+
}
39+
40+
// Build the log key based on the execution details
41+
if execution.Data.ShouldUseSimplifiedBaseKey {
42+
// Simplified key format
43+
finalLogKey = fmt.Sprintf("%s/pipeline/%s/%d/-%s",
44+
scope.AccountID,
45+
execution.Data.PipelineIdentifier,
46+
execution.Data.RunSequence,
47+
planExecutionID)
48+
} else {
49+
// Standard key format
50+
finalLogKey = fmt.Sprintf("accountId:%s/orgId:%s/projectId:%s/pipelineId:%s/runSequence:%d/level0:pipeline",
51+
scope.AccountID,
52+
execution.Data.OrgIdentifier,
53+
execution.Data.ProjectIdentifier,
54+
execution.Data.PipelineIdentifier,
55+
execution.Data.RunSequence)
56+
}
4757
}
4858

4959
// Prepare query parameters
5060
params := make(map[string]string)
5161
params["accountID"] = scope.AccountID
52-
params["prefix"] = prefix
62+
params["prefix"] = finalLogKey
5363

5464
// Initialize the response object
5565
response := &dto.LogDownloadResponse{}

pkg/harness/tools/logs.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ func DownloadExecutionLogsTool(config *config.Config, client *client.LogService)
2222
return mcp.NewTool("download_execution_logs",
2323
mcp.WithDescription("Downloads logs for an execution inside Harness"),
2424
mcp.WithString("plan_execution_id",
25-
mcp.Required(),
2625
mcp.Description("The ID of the plan execution"),
2726
),
2827
mcp.WithString("logs_directory",
2928
mcp.Required(),
3029
mcp.Description("The absolute path to the directory where the logs should get downloaded"),
3130
),
31+
mcp.WithString("log_key",
32+
mcp.Description("Optional log key to be used for downloading logs directly"),
33+
),
3234
common.WithScope(config, true),
3335
),
3436
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
@@ -42,7 +44,10 @@ func DownloadExecutionLogsTool(config *config.Config, client *client.LogService)
4244
return mcp.NewToolResultError(err.Error()), nil
4345
}
4446

45-
logDownloadURL, err := client.DownloadLogs(ctx, scope, planExecutionID)
47+
// Get optional log key parameter
48+
logKey, _ := OptionalParam[string](request, "log_key")
49+
50+
logDownloadURL, err := client.DownloadLogs(ctx, scope, planExecutionID, logKey)
4651
if err != nil {
4752
return nil, fmt.Errorf("failed to fetch log download URL: %w", err)
4853
}
@@ -76,7 +81,7 @@ func DownloadExecutionLogsTool(config *config.Config, client *client.LogService)
7681
}
7782

7883
// Get the download URL
79-
logDownloadURL, err = client.DownloadLogs(ctx, scope, planExecutionID)
84+
logDownloadURL, err = client.DownloadLogs(ctx, scope, planExecutionID, logKey)
8085
if err != nil {
8186
return mcp.NewToolResultError(fmt.Sprintf("failed to fetch log download URL: %v", err)), nil
8287
}

0 commit comments

Comments
 (0)