feat(cli): add verbose logging option for CLI commands
Some checks failed
CI / build-and-test (push) Failing after -32m43s

* Introduced a new flag `--verbose` to enable detailed logging.
* Implemented logging for connection events in SSE and stdio commands.
* Added a utility function to handle verbose logging.
This commit is contained in:
2026-04-21 22:24:57 +02:00
parent 979afc909e
commit 9a9fa4f384
16 changed files with 317 additions and 87 deletions

View File

@@ -17,6 +17,7 @@ var (
serverFlag string
tokenFlag string
outputFlag string
verbose bool
cfg Config
)
@@ -42,6 +43,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&serverFlag, "server", "", "AMCS server URL")
rootCmd.PersistentFlags().StringVar(&tokenFlag, "token", "", "AMCS bearer token")
rootCmd.PersistentFlags().StringVar(&outputFlag, "output", "json", "Output format: json or yaml")
rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "Enable verbose logging to stderr")
}
func loadConfig() error {
@@ -122,6 +124,7 @@ func connectRemote(ctx context.Context) (*mcp.ClientSession, error) {
if err := requireServer(); err != nil {
return nil, err
}
verboseLogf("connecting to %s", endpointURL())
client := mcp.NewClient(&mcp.Implementation{Name: "amcs-cli", Version: "0.0.1"}, nil)
transport := &mcp.StreamableClientTransport{
Endpoint: endpointURL(),
@@ -133,5 +136,13 @@ func connectRemote(ctx context.Context) (*mcp.ClientSession, error) {
if err != nil {
return nil, fmt.Errorf("connect to AMCS server: %w", err)
}
verboseLogf("connected to %s", endpointURL())
return session, nil
}
func verboseLogf(format string, args ...any) {
if !verbose {
return
}
_, _ = fmt.Fprintf(os.Stderr, "[amcs-cli] "+format+"\n", args...)
}

View File

@@ -0,0 +1,31 @@
package cmd
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestBearerTransportFormatsBearerToken(t *testing.T) {
const want = "Bearer X"
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if got := r.Header.Get("Authorization"); got != want {
t.Fatalf("Authorization header = %q, want %q", got, want)
}
w.WriteHeader(http.StatusNoContent)
}))
defer ts.Close()
client := &http.Client{Transport: &bearerTransport{token: "X"}}
req, err := http.NewRequest(http.MethodGet, ts.URL, nil)
if err != nil {
t.Fatalf("NewRequest() error = %v", err)
}
res, err := client.Do(req)
if err != nil {
t.Fatalf("client.Do() error = %v", err)
}
_ = res.Body.Close()
}

View File

@@ -29,11 +29,13 @@ var sseCmd = &cobra.Command{
connectCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
verboseLogf("connecting to SSE endpoint %s", sseEndpointURL())
remote, err := client.Connect(connectCtx, transport, nil)
if err != nil {
return fmt.Errorf("connect to AMCS SSE endpoint: %w", err)
}
defer func() { _ = remote.Close() }()
verboseLogf("connected to SSE endpoint %s", sseEndpointURL())
tools, err := remote.ListTools(ctx, nil)
if err != nil {
@@ -67,6 +69,8 @@ var sseCmd = &cobra.Command{
return fmt.Errorf("start stdio bridge: %w", err)
}
defer func() { _ = session.Close() }()
verboseLogf("sse stdio bridge ready")
verboseLogf("waiting for MCP commands on stdin")
<-ctx.Done()
return nil

View File

@@ -51,6 +51,8 @@ var stdioCmd = &cobra.Command{
return fmt.Errorf("start stdio bridge: %w", err)
}
defer func() { _ = session.Close() }()
verboseLogf("stdio bridge connected to remote AMCS and ready")
verboseLogf("waiting for MCP commands on stdin")
<-ctx.Done()
return nil