This is an automated email from the ASF dual-hosted git repository.

qiuxiafan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-mcp.git


The following commit(s) were added to refs/heads/main by this push:
     new 586f684  feat: add session-based SkyWalking URL and basic auth support 
(#29)
586f684 is described below

commit 586f684aa0642f4b9850d930b2a2c4a368c98c36
Author: 吴晟 Wu Sheng <[email protected]>
AuthorDate: Fri Mar 13 20:12:16 2026 +0800

    feat: add session-based SkyWalking URL and basic auth support (#29)
---
 CLAUDE.md                  |   6 +-
 README.md                  |  28 +++++++---
 cmd/skywalking-mcp/main.go |   4 ++
 internal/swmcp/server.go   |  98 ++++++++++++++++++++++++++------
 internal/swmcp/session.go  | 136 +++++++++++++++++++++++++++++++++++++++++++++
 internal/swmcp/stdio.go    |   8 +--
 internal/tools/mqe.go      |  35 +++++++++---
 7 files changed, 271 insertions(+), 44 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 52625b5..483758e 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -41,9 +41,11 @@ No unit tests exist yet. CI runs license checks, lint, and 
docker build.
 Three MCP transport modes as cobra subcommands: `stdio`, `sse`, `streamable`.
 
 The SkyWalking OAP URL is resolved in priority order:
-`--sw-url` flag > `SW_URL` env > `SW-URL` HTTP header > 
`http://localhost:12800/graphql`
+`set_skywalking_url` session tool > `--sw-url` flag > `SW-URL` HTTP header > 
`http://localhost:12800/graphql`
 
-Each transport injects the OAP URL into the request context via 
`WithSkyWalkingURLAndInsecure()`. Tools extract it downstream using 
`skywalking-cli`'s `contextkey.BaseURL{}`.
+Basic auth is configured via `--sw-username` / `--sw-password` flags. Both 
flags (and the `set_skywalking_url` tool) support `${ENV_VAR}` syntax to 
resolve credentials from environment variables (e.g. `--sw-password 
${MY_SECRET}`).
+
+Each transport injects the OAP URL and auth into the request context via 
`WithSkyWalkingURLAndInsecure()` and `WithSkyWalkingAuth()`. Tools extract them 
downstream using `skywalking-cli`'s `contextkey.BaseURL{}`, 
`contextkey.Username{}`, and `contextkey.Password{}`.
 
 ### Server Wiring (`internal/swmcp/server.go`)
 
diff --git a/README.md b/README.md
index 908331b..75701ef 100644
--- a/README.md
+++ b/README.md
@@ -36,13 +36,15 @@ Available Commands:
   streamable  Start Streamable server
 
 Flags:
-  -h, --help               help for swmcp
-      --log-command        When true, log commands to the log file
-      --log-file string    Path to log file
-      --log-level string   Logging level (debug, info, warn, error) (default 
"info")
-      --read-only          Restrict the server to read-only operations
-      --sw-url string      Specify the OAP URL to connect to (e.g. 
http://localhost:12800)
-  -v, --version            version for swmcp
+  -h, --help                 help for swmcp
+      --log-command          When true, log commands to the log file
+      --log-file string      Path to log file
+      --log-level string     Logging level (debug, info, warn, error) (default 
"info")
+      --read-only            Restrict the server to read-only operations
+      --sw-url string        Specify the OAP URL to connect to (e.g. 
http://localhost:12800)
+      --sw-username string   Username for basic auth to SkyWalking OAP 
(supports ${ENV_VAR} syntax)
+      --sw-password string   Password for basic auth to SkyWalking OAP 
(supports ${ENV_VAR} syntax)
+  -v, --version              version for swmcp
 
 Use "swmcp [command] --help" for more information about a command.
 ```
@@ -53,6 +55,12 @@ You could start the MCP server with the following command:
 # use stdio server
 bin/swmcp stdio --sw-url http://localhost:12800
 
+# with basic auth (raw password)
+bin/swmcp stdio --sw-url http://localhost:12800 --sw-username admin 
--sw-password admin
+
+# with basic auth (password from environment variable)
+bin/swmcp stdio --sw-url http://localhost:12800 --sw-username admin 
--sw-password '${SW_PASSWORD}'
+
 # or use SSE server
 bin/swmcp sse --sse-address localhost:8000 --base-path /mcp --sw-url 
http://localhost:12800
 ```
@@ -65,8 +73,9 @@ bin/swmcp sse --sse-address localhost:8000 --base-path /mcp 
--sw-url http://loca
     "skywalking": {
       "command": "swmcp stdio",
       "args": [
-        "--sw-url",
-        "http://localhost:12800";
+        "--sw-url", "http://localhost:12800";,
+        "--sw-username", "admin",
+        "--sw-password", "${SW_PASSWORD}"
       ]
     }
   }
@@ -101,6 +110,7 @@ SkyWalking MCP provides the following tools to query and 
analyze SkyWalking OAP
 
 | Category     | Tool Name                      | Description                  
                                                                     |
 
|--------------|--------------------------------|---------------------------------------------------------------------------------------------------|
+| **Session**  | `set_skywalking_url`           | Set the SkyWalking OAP 
server URL and optional basic auth credentials for the current session. 
Supports `${ENV_VAR}` syntax for credentials. |
 | **Trace**    | `query_traces`                 | Query traces with 
multi-condition filtering (service, endpoint, state, tags, and time range via 
start/end/step). Supports `full`, `summary`, and `errors_only` views with 
performance insights. |
 | **Log**      | `query_logs`                   | Query logs with filters for 
service, instance, endpoint, trace ID, tags, and time range. Supports cold 
storage and pagination. |
 | **MQE**      | `execute_mqe_expression`       | Execute MQE (Metrics Query 
Expression) to query and calculate metrics data. Supports calculations, 
aggregations, TopN, trend analysis, and multiple result types. |
diff --git a/cmd/skywalking-mcp/main.go b/cmd/skywalking-mcp/main.go
index 8ad4014..66babdc 100644
--- a/cmd/skywalking-mcp/main.go
+++ b/cmd/skywalking-mcp/main.go
@@ -57,6 +57,8 @@ func init() {
 
        // Add global Flags
        rootCmd.PersistentFlags().String("sw-url", "", "Specify the OAP URL to 
connect to (e.g. http://localhost:12800)")
+       rootCmd.PersistentFlags().String("sw-username", "", "Username for basic 
auth to SkyWalking OAP (supports ${ENV_VAR} syntax)")
+       rootCmd.PersistentFlags().String("sw-password", "", "Password for basic 
auth to SkyWalking OAP (supports ${ENV_VAR} syntax)")
        rootCmd.PersistentFlags().String("log-level", "info", "Logging level 
(debug, info, warn, error)")
        rootCmd.PersistentFlags().Bool("read-only", false, "Restrict the server 
to read-only operations")
        rootCmd.PersistentFlags().Bool("log-command", false, "When true, log 
commands to the log file")
@@ -64,6 +66,8 @@ func init() {
 
        // Bind flag to viper
        _ = viper.BindPFlag("url", rootCmd.PersistentFlags().Lookup("sw-url"))
+       _ = viper.BindPFlag("username", 
rootCmd.PersistentFlags().Lookup("sw-username"))
+       _ = viper.BindPFlag("password", 
rootCmd.PersistentFlags().Lookup("sw-password"))
        _ = viper.BindPFlag("log-level", 
rootCmd.PersistentFlags().Lookup("log-level"))
        _ = viper.BindPFlag("read-only", 
rootCmd.PersistentFlags().Lookup("read-only"))
        _ = viper.BindPFlag("log-command", 
rootCmd.PersistentFlags().Lookup("log-command"))
diff --git a/internal/swmcp/server.go b/internal/swmcp/server.go
index 21edfbc..6da1bf8 100644
--- a/internal/swmcp/server.go
+++ b/internal/swmcp/server.go
@@ -22,6 +22,7 @@ import (
        "fmt"
        "net/http"
        "os"
+       "strings"
 
        "github.com/mark3labs/mcp-go/server"
        "github.com/sirupsen/logrus"
@@ -43,6 +44,7 @@ func newMCPServer() *server.MCPServer {
                server.WithPromptCapabilities(true),
                server.WithLogging(),
        )
+       AddSessionTools(s)
        tools.AddTraceTools(s)
        tools.AddLogTools(s)
        tools.AddMQETools(s)
@@ -73,14 +75,21 @@ func initLogger(logFilePath string) (*logrus.Logger, error) 
{
        return logrusLogger, nil
 }
 
-// WithSkyWalkingURLAndInsecure adds SkyWalking URL and insecure flag to the 
context
-// This ensures all downstream requests will have contextkey.BaseURL{} and 
contextkey.Insecure{}
+// WithSkyWalkingURLAndInsecure adds SkyWalking URL and insecure flag to the 
context.
+// This ensures all downstream requests will have contextkey.BaseURL{} and 
contextkey.Insecure{}.
 func WithSkyWalkingURLAndInsecure(ctx context.Context, url string, insecure 
bool) context.Context {
        ctx = context.WithValue(ctx, contextkey.BaseURL{}, url)
        ctx = context.WithValue(ctx, contextkey.Insecure{}, insecure)
        return ctx
 }
 
+// WithSkyWalkingAuth adds username and password to the context for basic auth.
+func WithSkyWalkingAuth(ctx context.Context, username, password string) 
context.Context {
+       ctx = context.WithValue(ctx, contextkey.Username{}, username)
+       ctx = context.WithValue(ctx, contextkey.Password{}, password)
+       return ctx
+}
+
 // configuredSkyWalkingURL returns the configured SkyWalking OAP URL.
 // The value is sourced from the CLI/config binding for `--sw-url`,
 // falling back to the built-in default when unset.
@@ -92,6 +101,32 @@ func configuredSkyWalkingURL() string {
        return tools.FinalizeURL(urlStr)
 }
 
+// resolveEnvVar resolves a value that may contain an environment variable 
reference
+// in the form ${VAR_NAME}. If the value matches this pattern, it returns the
+// environment variable's value. Otherwise, it returns the raw value as-is.
+func resolveEnvVar(value string) string {
+       trimmed := strings.TrimSpace(value)
+       if strings.HasPrefix(trimmed, "${") && strings.HasSuffix(trimmed, "}") {
+               envName := trimmed[2 : len(trimmed)-1]
+               return os.Getenv(envName)
+       }
+       return value
+}
+
+// configuredAuth returns the configured username and password from CLI flags 
or env vars.
+func configuredAuth() (username, password string) {
+       return resolveEnvVar(viper.GetString("username")), 
resolveEnvVar(viper.GetString("password"))
+}
+
+// withConfiguredAuth injects the configured auth credentials into the context 
if present.
+func withConfiguredAuth(ctx context.Context) context.Context {
+       username, password := configuredAuth()
+       if username != "" {
+               ctx = WithSkyWalkingAuth(ctx, username, password)
+       }
+       return ctx
+}
+
 // urlFromHeaders extracts URL for a request.
 // URL is sourced from Header > configured value > Default.
 func urlFromHeaders(req *http.Request) string {
@@ -103,32 +138,59 @@ func urlFromHeaders(req *http.Request) string {
        return tools.FinalizeURL(urlStr)
 }
 
-// WithSkyWalkingContextFromConfig injects the SkyWalking URL and insecure
-// settings from global configuration into the context.
-var WithSkyWalkingContextFromConfig server.StdioContextFunc = func(ctx 
context.Context) context.Context {
-       return WithSkyWalkingURLAndInsecure(ctx, configuredSkyWalkingURL(), 
false)
-}
-
-// withSkyWalkingContextFromRequest is the shared logic for enriching context 
from an http.Request.
-func withSkyWalkingContextFromRequest(ctx context.Context, req *http.Request) 
context.Context {
-       urlStr := urlFromHeaders(req)
-       return WithSkyWalkingURLAndInsecure(ctx, urlStr, false)
+// applySessionOverrides checks for a session in the context and applies any
+// URL or auth overrides that were set via the set_skywalking_url tool.
+func applySessionOverrides(ctx context.Context) context.Context {
+       session := SessionFromContext(ctx)
+       if session == nil {
+               return ctx
+       }
+       if url := session.URL(); url != "" {
+               ctx = context.WithValue(ctx, contextkey.BaseURL{}, url)
+       }
+       if username := session.Username(); username != "" {
+               ctx = WithSkyWalkingAuth(ctx, username, session.Password())
+       }
+       return ctx
 }
 
 // EnhanceStdioContextFunc returns a StdioContextFunc that enriches the context
-// with SkyWalking settings from the global configuration.
+// with SkyWalking settings from the global configuration and a per-session 
store.
 func EnhanceStdioContextFunc() server.StdioContextFunc {
-       return WithSkyWalkingContextFromConfig
+       session := &Session{}
+       return func(ctx context.Context) context.Context {
+               ctx = WithSession(ctx, session)
+               ctx = WithSkyWalkingURLAndInsecure(ctx, 
configuredSkyWalkingURL(), false)
+               ctx = withConfiguredAuth(ctx)
+               ctx = applySessionOverrides(ctx)
+               return ctx
+       }
 }
 
 // EnhanceSSEContextFunc returns a SSEContextFunc that enriches the context
-// with SkyWalking settings from SSE request headers.
+// with SkyWalking settings from SSE request headers and a per-session store.
 func EnhanceSSEContextFunc() server.SSEContextFunc {
-       return withSkyWalkingContextFromRequest
+       session := &Session{}
+       return func(ctx context.Context, req *http.Request) context.Context {
+               ctx = WithSession(ctx, session)
+               urlStr := urlFromHeaders(req)
+               ctx = WithSkyWalkingURLAndInsecure(ctx, urlStr, false)
+               ctx = withConfiguredAuth(ctx)
+               ctx = applySessionOverrides(ctx)
+               return ctx
+       }
 }
 
 // EnhanceHTTPContextFunc returns a HTTPContextFunc that enriches the context
-// with SkyWalking settings from HTTP request headers.
+// with SkyWalking settings from HTTP request headers and a per-session store.
 func EnhanceHTTPContextFunc() server.HTTPContextFunc {
-       return withSkyWalkingContextFromRequest
+       session := &Session{}
+       return func(ctx context.Context, req *http.Request) context.Context {
+               ctx = WithSession(ctx, session)
+               urlStr := urlFromHeaders(req)
+               ctx = WithSkyWalkingURLAndInsecure(ctx, urlStr, false)
+               ctx = withConfiguredAuth(ctx)
+               ctx = applySessionOverrides(ctx)
+               return ctx
+       }
 }
diff --git a/internal/swmcp/session.go b/internal/swmcp/session.go
new file mode 100644
index 0000000..847504a
--- /dev/null
+++ b/internal/swmcp/session.go
@@ -0,0 +1,136 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package swmcp
+
+import (
+       "context"
+       "fmt"
+       "sync"
+
+       "github.com/mark3labs/mcp-go/mcp"
+       "github.com/mark3labs/mcp-go/server"
+
+       "github.com/apache/skywalking-mcp/internal/tools"
+)
+
+// sessionKey is the context key for looking up the session store.
+type sessionKey struct{}
+
+// Session holds per-session SkyWalking connection configuration.
+type Session struct {
+       mu       sync.RWMutex
+       url      string
+       username string
+       password string
+}
+
+// SetConnection updates the session's connection parameters.
+func (s *Session) SetConnection(url, username, password string) {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       s.url = url
+       s.username = username
+       s.password = password
+}
+
+// URL returns the session's configured URL, or empty if not set.
+func (s *Session) URL() string {
+       s.mu.RLock()
+       defer s.mu.RUnlock()
+       return s.url
+}
+
+// Username returns the session's configured username.
+func (s *Session) Username() string {
+       s.mu.RLock()
+       defer s.mu.RUnlock()
+       return s.username
+}
+
+// Password returns the session's configured password.
+func (s *Session) Password() string {
+       s.mu.RLock()
+       defer s.mu.RUnlock()
+       return s.password
+}
+
+// SessionFromContext retrieves the session from the context, or nil if not 
present.
+func SessionFromContext(ctx context.Context) *Session {
+       s, _ := ctx.Value(sessionKey{}).(*Session)
+       return s
+}
+
+// WithSession attaches a session to the context.
+func WithSession(ctx context.Context, s *Session) context.Context {
+       return context.WithValue(ctx, sessionKey{}, s)
+}
+
+// SetSkyWalkingURLRequest represents the request for the set_skywalking_url 
tool.
+type SetSkyWalkingURLRequest struct {
+       URL      string `json:"url"`
+       Username string `json:"username,omitempty"`
+       Password string `json:"password,omitempty"`
+}
+
+func setSkyWalkingURL(ctx context.Context, req *SetSkyWalkingURLRequest) 
(*mcp.CallToolResult, error) {
+       if req.URL == "" {
+               return mcp.NewToolResultError("url is required"), nil
+       }
+
+       session := SessionFromContext(ctx)
+       if session == nil {
+               return mcp.NewToolResultError("session not available"), nil
+       }
+
+       finalURL := tools.FinalizeURL(req.URL)
+       session.SetConnection(finalURL, resolveEnvVar(req.Username), 
resolveEnvVar(req.Password))
+
+       msg := fmt.Sprintf("SkyWalking URL set to %s", finalURL)
+       if req.Username != "" {
+               msg += " with basic auth credentials"
+       }
+       return mcp.NewToolResultText(msg), nil
+}
+
+// AddSessionTools registers session management tools with the MCP server.
+func AddSessionTools(s *server.MCPServer) {
+       tool := tools.NewTool(
+               "set_skywalking_url",
+               `Set the SkyWalking OAP server URL and optional basic auth 
credentials for this session.
+
+This tool configures the connection to SkyWalking OAP for all subsequent tool 
calls in the current session.
+The URL and credentials persist for the lifetime of the session.
+
+Priority: session URL (set by this tool) > --sw-url flag > default 
(http://localhost:12800/graphql)
+
+Credentials support raw values or environment variable references using 
${ENV_VAR} syntax.
+
+Examples:
+- {"url": "http://demo.skywalking.apache.org:12800"}: Connect without auth
+- {"url": "http://oap.internal:12800";, "username": "admin", "password": 
"admin"}: Connect with basic auth
+- {"url": "https://skywalking.example.com:443";, "username": "${SW_USER}", 
"password": "${SW_PASS}"}: Auth via env vars`,
+               setSkyWalkingURL,
+               mcp.WithString("url", mcp.Required(),
+                       mcp.Description("SkyWalking OAP server URL (required). 
Example: http://localhost:12800";)),
+               mcp.WithString("username",
+                       mcp.Description("Username for basic auth (optional). 
Supports ${ENV_VAR} syntax.")),
+               mcp.WithString("password",
+                       mcp.Description("Password for basic auth (optional). 
Supports ${ENV_VAR} syntax.")),
+       )
+       tool.Register(s)
+}
diff --git a/internal/swmcp/stdio.go b/internal/swmcp/stdio.go
index 33a3529..02abb4a 100644
--- a/internal/swmcp/stdio.go
+++ b/internal/swmcp/stdio.go
@@ -19,7 +19,6 @@ package swmcp
 
 import (
        "context"
-       "errors"
        "fmt"
        "io"
        "log"
@@ -42,13 +41,8 @@ func NewStdioServer() *cobra.Command {
                Short: "Start stdio server",
                Long:  `Start a server that communicates via standard 
input/output streams using JSON-RPC messages.`,
                RunE: func(_ *cobra.Command, _ []string) error {
-                       url := viper.GetString("url")
-                       if url == "" {
-                               return errors.New("--sw-url must be specified")
-                       }
-
                        stdioServerConfig := config.StdioServerConfig{
-                               URL:         url,
+                               URL:         viper.GetString("url"),
                                ReadOnly:    viper.GetBool("read-only"),
                                LogFilePath: viper.GetString("log-file"),
                                LogCommands: viper.GetBool("log-command"),
diff --git a/internal/tools/mqe.go b/internal/tools/mqe.go
index f152d49..0f4189a 100644
--- a/internal/tools/mqe.go
+++ b/internal/tools/mqe.go
@@ -20,6 +20,7 @@ package tools
 import (
        "bytes"
        "context"
+       "encoding/base64"
        "encoding/json"
        "fmt"
        "io"
@@ -29,7 +30,8 @@ import (
 
        "github.com/mark3labs/mcp-go/mcp"
        "github.com/mark3labs/mcp-go/server"
-       "github.com/spf13/viper"
+
+       "github.com/apache/skywalking-cli/pkg/contextkey"
 )
 
 // AddMQETools registers MQE-related tools with the MCP server
@@ -53,8 +55,17 @@ type GraphQLResponse struct {
        } `json:"errors,omitempty"`
 }
 
-// executeGraphQL executes a GraphQL query against SkyWalking OAP
-func executeGraphQL(ctx context.Context, url, query string, variables 
map[string]interface{}) (*GraphQLResponse, error) {
+// getContextString safely extracts a string value from context.
+func getContextString(ctx context.Context, key any) string {
+       if v, ok := ctx.Value(key).(string); ok {
+               return v
+       }
+       return ""
+}
+
+// executeGraphQLWithContext executes a GraphQL query using URL and auth from 
context.
+func executeGraphQLWithContext(ctx context.Context, query string, variables 
map[string]interface{}) (*GraphQLResponse, error) {
+       url := getContextString(ctx, contextkey.BaseURL{})
        url = FinalizeURL(url)
 
        reqBody := GraphQLRequest{
@@ -74,6 +85,14 @@ func executeGraphQL(ctx context.Context, url, query string, 
variables map[string
 
        req.Header.Set("Content-Type", "application/json")
 
+       // Add basic auth from context if present
+       username := getContextString(ctx, contextkey.Username{})
+       password := getContextString(ctx, contextkey.Password{})
+       if username != "" && password != "" {
+               auth := "Basic " + 
base64.StdEncoding.EncodeToString([]byte(username+":"+password))
+               req.Header.Set("Authorization", auth)
+       }
+
        client := &http.Client{Timeout: 30 * time.Second}
        resp, err := client.Do(req)
        if err != nil {
@@ -186,7 +205,7 @@ func getServiceByName(ctx context.Context, serviceName, 
layer string) (*bool, er
                "serviceId": serviceID,
        }
 
-       result, err := executeGraphQL(ctx, viper.GetString("url"), query, 
variables)
+       result, err := executeGraphQLWithContext(ctx, query, variables)
        if err != nil {
                return nil, fmt.Errorf("failed to get service details: %w", err)
        }
@@ -217,7 +236,7 @@ func findServiceID(ctx context.Context, serviceName, layer 
string) (string, erro
                "layer": layer,
        }
 
-       result, err := executeGraphQL(ctx, viper.GetString("url"), query, 
variables)
+       result, err := executeGraphQLWithContext(ctx, query, variables)
        if err != nil {
                return "", err
        }
@@ -353,7 +372,7 @@ func executeMQEExpression(ctx context.Context, req 
*MQEExpressionRequest) (*mcp.
                "dumpDBRsp": req.DumpDBRsp,
        }
 
-       result, err := executeGraphQL(ctx, viper.GetString("url"), query, 
variables)
+       result, err := executeGraphQLWithContext(ctx, query, variables)
        if err != nil {
                return mcp.NewToolResultError(fmt.Sprintf("failed to execute 
MQE expression: %v", err)), nil
        }
@@ -383,7 +402,7 @@ func listMQEMetrics(ctx context.Context, req 
*MQEMetricsListRequest) (*mcp.CallT
                variables["regex"] = req.Regex
        }
 
-       result, err := executeGraphQL(ctx, viper.GetString("url"), query, 
variables)
+       result, err := executeGraphQLWithContext(ctx, query, variables)
        if err != nil {
                return mcp.NewToolResultError(fmt.Sprintf("failed to list 
metrics: %v", err)), nil
        }
@@ -431,7 +450,7 @@ func getMQEMetricsType(ctx context.Context, req 
*MQEMetricsTypeRequest) (*mcp.Ca
                "name": req.MetricName,
        }
 
-       result, err := executeGraphQL(ctx, viper.GetString("url"), query, 
variables)
+       result, err := executeGraphQLWithContext(ctx, query, variables)
        if err != nil {
                return mcp.NewToolResultError(fmt.Sprintf("failed to get metric 
type: %v", err)), nil
        }

Reply via email to