This is an automated email from the ASF dual-hosted git repository. wusheng pushed a commit to branch fix/session-stdio-only in repository https://gitbox.apache.org/repos/asf/skywalking-mcp.git
commit 9a041a4d672f4541d8befbd76cfa12a86a939481 Author: Wu Sheng <[email protected]> AuthorDate: Fri Mar 13 20:36:42 2026 +0800 fix: restrict set_skywalking_url tool to stdio transport only Reverts the session-in-all-transports behavior from PR #29. The set_skywalking_url tool is now only registered for stdio mode, where single-client session semantics are well-defined. SSE and HTTP transports rely on per-request SW-URL headers and CLI flags instead, avoiding the shared-session issue where one client could override another's credentials. Co-Authored-By: Claude Opus 4.6 <[email protected]> --- CLAUDE.md | 5 ++++- README.md | 2 +- internal/swmcp/server.go | 18 ++++++++---------- internal/swmcp/session.go | 2 ++ internal/swmcp/sse.go | 2 +- internal/swmcp/stdio.go | 2 +- internal/swmcp/streamable.go | 2 +- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 483758e..5de6db1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,7 +41,10 @@ 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: -`set_skywalking_url` session tool > `--sw-url` flag > `SW-URL` HTTP header > `http://localhost:12800/graphql` +- **stdio**: `set_skywalking_url` session tool > `--sw-url` flag > `http://localhost:12800/graphql` +- **SSE/HTTP**: `SW-URL` HTTP header > `--sw-url` flag > `http://localhost:12800/graphql` + +The `set_skywalking_url` tool is only available in stdio mode (single client, well-defined session). SSE and HTTP transports use per-request headers instead. 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}`). diff --git a/README.md b/README.md index 75701ef..5d9e8f5 100644 --- a/README.md +++ b/README.md @@ -110,7 +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. | +| **Session** | `set_skywalking_url` | Set the SkyWalking OAP server URL and optional basic auth credentials for the current session (stdio mode only). 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/internal/swmcp/server.go b/internal/swmcp/server.go index 6da1bf8..8b4a740 100644 --- a/internal/swmcp/server.go +++ b/internal/swmcp/server.go @@ -37,14 +37,18 @@ import ( ) // newMCPServer creates a new MCP server with all tools, resources, and prompts registered. -func newMCPServer() *server.MCPServer { +// When stdio is true, session management tools (set_skywalking_url) are also registered, +// since stdio has a single client and session semantics are well-defined. +func newMCPServer(stdio bool) *server.MCPServer { s := server.NewMCPServer( "skywalking-mcp", "0.1.0", server.WithResourceCapabilities(true, true), server.WithPromptCapabilities(true), server.WithLogging(), ) - AddSessionTools(s) + if stdio { + AddSessionTools(s) + } tools.AddTraceTools(s) tools.AddLogTools(s) tools.AddMQETools(s) @@ -168,29 +172,23 @@ func EnhanceStdioContextFunc() server.StdioContextFunc { } // EnhanceSSEContextFunc returns a SSEContextFunc that enriches the context -// with SkyWalking settings from SSE request headers and a per-session store. +// with SkyWalking settings from SSE request headers and CLI-configured auth. func EnhanceSSEContextFunc() server.SSEContextFunc { - 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 and a per-session store. +// with SkyWalking settings from HTTP request headers and CLI-configured auth. func EnhanceHTTPContextFunc() server.HTTPContextFunc { - 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 index 847504a..5a684c1 100644 --- a/internal/swmcp/session.go +++ b/internal/swmcp/session.go @@ -112,11 +112,13 @@ 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 is only available in stdio transport mode. 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) +For SSE/HTTP transports, use the SW-URL HTTP header or --sw-url flag instead. Credentials support raw values or environment variable references using ${ENV_VAR} syntax. diff --git a/internal/swmcp/sse.go b/internal/swmcp/sse.go index 14365a9..1e9a04e 100644 --- a/internal/swmcp/sse.go +++ b/internal/swmcp/sse.go @@ -72,7 +72,7 @@ func runSSEServer(ctx context.Context, cfg *config.SSEServerConfig) error { } sseServer := server.NewSSEServer( - newMCPServer(), + newMCPServer(false), server.WithStaticBasePath(cfg.BasePath), server.WithSSEContextFunc(EnhanceSSEContextFunc()), ) diff --git a/internal/swmcp/stdio.go b/internal/swmcp/stdio.go index 02abb4a..9dd58df 100644 --- a/internal/swmcp/stdio.go +++ b/internal/swmcp/stdio.go @@ -60,7 +60,7 @@ func runStdioServer(ctx context.Context, cfg *config.StdioServerConfig) error { ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM) defer stop() - stdioServer := server.NewStdioServer(newMCPServer()) + stdioServer := server.NewStdioServer(newMCPServer(true)) logger, err := initLogger(cfg.LogFilePath) if err != nil { diff --git a/internal/swmcp/streamable.go b/internal/swmcp/streamable.go index 0500352..8f41194 100644 --- a/internal/swmcp/streamable.go +++ b/internal/swmcp/streamable.go @@ -57,7 +57,7 @@ func NewStreamable() *cobra.Command { // runStreamableServer starts the Streamable server with the provided configuration. func runStreamableServer(cfg *config.StreamableServerConfig) error { httpServer := server.NewStreamableHTTPServer( - newMCPServer(), + newMCPServer(false), server.WithStateLess(true), server.WithLogger(log.StandardLogger()), server.WithHTTPContextFunc(EnhanceHTTPContextFunc()),
