Skip to content

Commit 8da5259

Browse files
Saranya-jenaHarness
authored andcommitted
chore: [ML-1392]:Fixed Download Log Files from MCP are inaccessible to Claude Code (#212)
* 3678fd chore: [ML-1392-new]: resolved comments * 253fa3 chore: [ML-1392-new]: resolved comments * a86f92 Apply suggestion from code review * edb34c Apply suggestion from code review * d72698 Apply suggestion from code review * ac9e0c chore: [ML-1392]: resolved comments * 9279ab chore: [ML-1392]: minor fixes * 066d83 chore: [ML-1392]:Fixed Download Log Files from MCP are inaccessible to Claude Code
1 parent b283134 commit 8da5259

File tree

4 files changed

+124
-1
lines changed

4 files changed

+124
-1
lines changed

README.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,104 @@ To use the Harness MCP Server with Amazon Q Developer CLI:
514514

515515
[VS Code MCP Guide](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
516516

517+
## Tool Usage Guide
518+
519+
### Download Execution Logs
520+
521+
#### Using Docker:
522+
523+
We need to mount the logs directory to the container to download the logs.
524+
525+
```bash
526+
docker run -d --name mcp-server -p 8080:8080 -v /path/to/logs/in/host:/path/in/container harness/mcp-server --output-dir=/path/in/container
527+
```
528+
This ensures that the logs downloaded to container are accessible in the host.
529+
530+
Example:
531+
532+
```bash
533+
docker run -d --name mcp-server -p 8080:8080 -v /Users/testuser/logs:/logs harness/mcp-server --output-dir=/logs
534+
```
535+
536+
Sample MCP Configuration:
537+
538+
```bash
539+
{
540+
"mcpServers": {
541+
"harness": {
542+
"command": "docker",
543+
"args": [
544+
"run",
545+
"-i",
546+
"--rm",
547+
"-v",
548+
"/Users/testuser/logs:/logs",
549+
"-e",
550+
"HARNESS_MCP_USER_PAT",
551+
"-e",
552+
"HARNESS_DEFAULT_ORG_ID",
553+
"-e",
554+
"HARNESS_DEFAULT_PROJECT_ID",
555+
"-e",
556+
"HARNESS_MCP_BASE_URL",
557+
"harness/mcp-server",
558+
"stdio",
559+
"--output-dir=/logs", #/path/in/container
560+
"--toolsets=logs",
561+
"--api-key="
562+
],
563+
"env": {
564+
"HARNESS_MCP_USER_PAT": "<YOUR_API_KEY>",
565+
"HARNESS_DEFAULT_ORG_ID": "<YOUR_ORG_ID>",
566+
"HARNESS_DEFAULT_PROJECT_ID": "<YOUR_PROJECT_ID>",
567+
"HARNESS_MCP_BASE_URL": "<YOUR_BASE_URL>"
568+
}
569+
}
570+
}
571+
}
572+
```
573+
574+
Example Tool Input:
575+
576+
```json
577+
{
578+
"logs_directory": "pipeline-logs",
579+
"org_id": "<YOUR_ORG_ID>",
580+
"plan_execution_id": "<YOUR_PLAN_EXECUTION_ID>",
581+
"project_id": "<YOUR_PROJECT_ID>"
582+
}
583+
```
584+
585+
Sample Response:
586+
587+
```json
588+
Files downloaded to : /Users/testuser/logs/pipeline-logs/logs-<YOUR_PLAN_EXECUTION_ID>/logs.zip
589+
```
590+
591+
### Using Local Binary:
592+
593+
Example configuration:
594+
595+
```json
596+
"args": ["stdio", "--toolsets=logs", "--api-key=", "--output-dir=/Users/testuser/log-files"]
597+
```
598+
599+
Example Tool Input:
600+
601+
```json
602+
{
603+
"logs_directory": "logs1",
604+
"project_id": "<YOUR_PROJECT_ID>",
605+
"plan_execution_id": "<YOUR_PLAN_EXECUTION_ID>",
606+
"org_id": "<YOUR_ORG_ID>"
607+
}
608+
```
609+
610+
Sample Response:
611+
612+
```json
613+
Files downloaded to : /Users/testuser/log-files/logs1/logs-<YOUR_PLAN_EXECUTION_ID>/logs.zip
614+
```
517615

518616
## Development
519617

@@ -530,6 +628,7 @@ The Harness MCP Server supports the following command line arguments:
530628
- `--version`: Show version information
531629
- `--help`: Show help message
532630
- `--base-url`: Base URL for Harness (default: "https://app.harness.io")
631+
- `--output-dir`: Directory where the tool writes output files (e.g., pipeline logs)
533632

534633

535634
### Environment Variables

cmd/harness-mcp-server/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type Config struct {
1111
LogFilePath string
1212
Debug bool
1313
EnableLicense bool
14+
OutputDir string
1415

1516
// Server configuration
1617
Transport enum.TransportType

cmd/harness-mcp-server/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ var (
8282
},
8383
Toolsets: toolsets,
8484
EnableModules: enableModules,
85+
OutputDir: viper.GetString("output_dir"),
8586
}
8687

8788
return runHTTPServer(ctx, cfg)
@@ -132,6 +133,7 @@ var (
132133
Debug: viper.GetBool("debug"),
133134
EnableModules: enableModules,
134135
EnableLicense: viper.GetBool("enable_license"),
136+
OutputDir: viper.GetString("output_dir"),
135137
}
136138

137139
if err := runStdioServer(ctx, cfg); err != nil {
@@ -192,6 +194,7 @@ var (
192194
Debug: viper.GetBool("debug"),
193195
EnableLicense: viper.GetBool("enable_license"),
194196
Internal: true,
197+
OutputDir: viper.GetString("output_dir"),
195198
AccountID: session.Principal.AccountID,
196199
// Internal mode specific fields
197200
BearerToken: viper.GetString("bearer_token"),
@@ -257,6 +260,7 @@ func init() {
257260
rootCmd.PersistentFlags().Bool("read-only", false, "Restrict the server to read-only operations")
258261
rootCmd.PersistentFlags().String("log-file", "", "Path to log file")
259262
rootCmd.PersistentFlags().Bool("debug", false, "Enable debug logging")
263+
rootCmd.PersistentFlags().String("output-dir", "", "Directory where the tool writes output files (e.g., pipeline logs)")
260264

261265
httpServerCmd.PersistentFlags().Int("http-port", 8080, "HTTP server port (when transport is 'http')")
262266
httpServerCmd.PersistentFlags().String("http-path", "/mcp", "HTTP server path (when transport is 'http')")
@@ -312,6 +316,7 @@ func init() {
312316
_ = viper.BindPFlag("read_only", rootCmd.PersistentFlags().Lookup("read-only"))
313317
_ = viper.BindPFlag("log_file", rootCmd.PersistentFlags().Lookup("log-file"))
314318
_ = viper.BindPFlag("debug", rootCmd.PersistentFlags().Lookup("debug"))
319+
_ = viper.BindPFlag("output_dir", rootCmd.PersistentFlags().Lookup("output-dir"))
315320

316321
// Bind transport configuration flags to viper
317322
_ = viper.BindPFlag("http_port", httpServerCmd.PersistentFlags().Lookup("http-port"))

pkg/harness/tools/logs.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import (
44
"context"
55
"fmt"
66
"io"
7+
"log/slog"
78
"net/http"
89
"os"
910
"path/filepath"
11+
"strings"
1012

1113
"github.com/harness/harness-mcp/client"
1214
"github.com/harness/harness-mcp/cmd/harness-mcp-server/config"
@@ -26,7 +28,7 @@ func DownloadExecutionLogsTool(config *config.Config, client *client.LogService)
2628
),
2729
mcp.WithString("logs_directory",
2830
mcp.Required(),
29-
mcp.Description("The absolute path to the directory where the logs should get downloaded"),
31+
mcp.Description("The absolute path to the directory where the logs should get downloaded."),
3032
),
3133
mcp.WithString("log_key",
3234
mcp.Description("Optional log key to be used for downloading logs directly"),
@@ -57,6 +59,22 @@ func DownloadExecutionLogsTool(config *config.Config, client *client.LogService)
5759
return mcp.NewToolResultError(err.Error()), nil
5860
}
5961

62+
// If OutputDir is configured, use it as the base directory for logs
63+
if config.OutputDir != "" {
64+
65+
if !strings.HasPrefix(logsDirectory, config.OutputDir) {
66+
// Create a subdirectory within the output directory for logs
67+
oldLogsDirectory := logsDirectory
68+
logsDirectoryName := filepath.Base(logsDirectory)
69+
// If the logs directory is just a root path like /tmp, use a more descriptive name
70+
if logsDirectoryName == "/" || logsDirectoryName == "" {
71+
logsDirectoryName = "pipeline-logs"
72+
}
73+
logsDirectory = filepath.Join(config.OutputDir, logsDirectoryName)
74+
slog.Info("Redirecting logs from %s to %s to ensure access", oldLogsDirectory, logsDirectory)
75+
}
76+
}
77+
6078
// Create the logs folder path (creates all parent directories if needed)
6179
logsFolderName := fmt.Sprintf("logs-%s", planExecutionID)
6280
logsFolderPath := filepath.Join(logsDirectory, logsFolderName)

0 commit comments

Comments
 (0)