Skip to content

Commit c53a364

Browse files
authored
fix: honour paths in Grafana URLs (#95)
Previously we assumed that the Grafana instance lived at the root of the domain provided in GRAFANA_URL (or the equivalent header). This commit changes that so we support Grafana instances living at subpaths, such as http://example.com/grafana. Fixes #79.
1 parent eee52cc commit c53a364

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

mcpgrafana.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ func GrafanaAPIKeyFromContext(ctx context.Context) string {
101101

102102
type grafanaClientKey struct{}
103103

104+
func makeBasePath(path string) string {
105+
return strings.Join([]string{strings.TrimRight(path, "/"), "api"}, "/")
106+
}
107+
104108
// ExtractGrafanaClientFromEnv is a StdioContextFunc that extracts Grafana configuration
105109
// from environment variables and injects a configured client into the context.
106110
var ExtractGrafanaClientFromEnv server.StdioContextFunc = func(ctx context.Context) context.Context {
@@ -116,6 +120,7 @@ var ExtractGrafanaClientFromEnv server.StdioContextFunc = func(ctx context.Conte
116120
panic(fmt.Errorf("invalid %s: %w", grafanaURLEnvVar, err))
117121
}
118122
cfg.Host = parsedURL.Host
123+
cfg.BasePath = makeBasePath(parsedURL.Path)
119124
// The Grafana client will always prefer HTTPS even if the URL is HTTP,
120125
// so we need to limit the schemes to HTTP if the URL is HTTP.
121126
if parsedURL.Scheme == "http" {
@@ -144,6 +149,7 @@ var ExtractGrafanaClientFromHeaders server.SSEContextFunc = func(ctx context.Con
144149
if u != "" {
145150
if url, err := url.Parse(u); err == nil {
146151
cfg.Host = url.Host
152+
cfg.BasePath = makeBasePath(url.Path)
147153
if url.Scheme == "http" {
148154
cfg.Schemes = []string{"http"}
149155
}

mcpgrafana_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99
"testing"
1010

11+
"github.com/go-openapi/runtime/client"
1112
"github.com/stretchr/testify/assert"
1213
"github.com/stretchr/testify/require"
1314
)
@@ -73,3 +74,35 @@ func TestExtractGrafanaInfoFromHeaders(t *testing.T) {
7374
assert.Equal(t, "my-test-api-key", apiKey)
7475
})
7576
}
77+
78+
func TestExtractGrafanaClientPath(t *testing.T) {
79+
t.Run("no custom path", func(t *testing.T) {
80+
t.Setenv("GRAFANA_URL", "http://my-test-url.grafana.com/")
81+
ctx := ExtractGrafanaClientFromEnv(context.Background())
82+
83+
c := GrafanaClientFromContext(ctx)
84+
require.NotNil(t, c)
85+
rt := c.Transport.(*client.Runtime)
86+
assert.Equal(t, "/api", rt.BasePath)
87+
})
88+
89+
t.Run("custom path", func(t *testing.T) {
90+
t.Setenv("GRAFANA_URL", "http://my-test-url.grafana.com/grafana")
91+
ctx := ExtractGrafanaClientFromEnv(context.Background())
92+
93+
c := GrafanaClientFromContext(ctx)
94+
require.NotNil(t, c)
95+
rt := c.Transport.(*client.Runtime)
96+
assert.Equal(t, "/grafana/api", rt.BasePath)
97+
})
98+
99+
t.Run("custom path, trailing slash", func(t *testing.T) {
100+
t.Setenv("GRAFANA_URL", "http://my-test-url.grafana.com/grafana/")
101+
ctx := ExtractGrafanaClientFromEnv(context.Background())
102+
103+
c := GrafanaClientFromContext(ctx)
104+
require.NotNil(t, c)
105+
rt := c.Transport.(*client.Runtime)
106+
assert.Equal(t, "/grafana/api", rt.BasePath)
107+
})
108+
}

0 commit comments

Comments
 (0)