Add mcp logs command for streaming container logs
New server-streaming Logs RPC streams container output to the CLI. Supports --tail/-n, --follow/-f, --timestamps/-t, --since. Detects journald log driver and falls back to journalctl (podman logs can't read journald outside the originating user session). New containers default to k8s-file via mcp user's containers.conf. Also adds stream auth interceptor for the agent gRPC server (required for streaming RPCs). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -255,6 +255,52 @@ func AuthInterceptor(validator TokenValidator) grpc.UnaryServerInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
// StreamAuthInterceptor returns a gRPC stream server interceptor with
|
||||
// the same authentication rules as AuthInterceptor.
|
||||
func StreamAuthInterceptor(validator TokenValidator) grpc.StreamServerInterceptor {
|
||||
return func(
|
||||
srv any,
|
||||
ss grpc.ServerStream,
|
||||
info *grpc.StreamServerInfo,
|
||||
handler grpc.StreamHandler,
|
||||
) error {
|
||||
md, ok := metadata.FromIncomingContext(ss.Context())
|
||||
if !ok {
|
||||
return status.Error(codes.Unauthenticated, "missing metadata")
|
||||
}
|
||||
|
||||
authValues := md.Get("authorization")
|
||||
if len(authValues) == 0 {
|
||||
return status.Error(codes.Unauthenticated, "missing authorization header")
|
||||
}
|
||||
|
||||
authHeader := authValues[0]
|
||||
if !strings.HasPrefix(authHeader, "Bearer ") {
|
||||
return status.Error(codes.Unauthenticated, "malformed authorization header")
|
||||
}
|
||||
token := strings.TrimPrefix(authHeader, "Bearer ")
|
||||
|
||||
tokenInfo, err := validator.ValidateToken(ss.Context(), token)
|
||||
if err != nil {
|
||||
slog.Error("token validation failed", "method", info.FullMethod, "error", err)
|
||||
return status.Error(codes.Unauthenticated, "token validation failed")
|
||||
}
|
||||
|
||||
if !tokenInfo.Valid {
|
||||
return status.Error(codes.Unauthenticated, "invalid token")
|
||||
}
|
||||
|
||||
if tokenInfo.HasRole("guest") {
|
||||
slog.Warn("guest access denied", "method", info.FullMethod, "user", tokenInfo.Username)
|
||||
return status.Error(codes.PermissionDenied, "guest access not permitted")
|
||||
}
|
||||
|
||||
slog.Info("rpc", "method", info.FullMethod, "user", tokenInfo.Username, "account_type", tokenInfo.AccountType)
|
||||
|
||||
return handler(srv, ss)
|
||||
}
|
||||
}
|
||||
|
||||
// Login authenticates with MCIAS and returns a bearer token.
|
||||
func Login(serverURL, caCertPath, username, password string) (string, error) {
|
||||
client, err := newHTTPClient(caCertPath)
|
||||
|
||||
Reference in New Issue
Block a user