@@ -448,7 +448,63 @@ public void Dispose()
448448 _cleanupTimer ? . Dispose ( ) ;
449449 }
450450
451- private static string GenerateTaskId ( ) => Guid . NewGuid ( ) . ToString ( "N" ) ;
451+ #if NET9_0_OR_GREATER
452+ private static string GenerateTaskId ( ) => Guid . CreateVersion7 ( ) . ToString ( "N" ) ;
453+ #else
454+ private static string GenerateTaskId ( ) => CreateVersion7Guid ( ) . ToString ( "N" ) ;
455+
456+ /// <summary>
457+ /// Polyfill for Guid.CreateVersion7() on targets earlier than .NET 9.
458+ /// Generates a UUID v7 with embedded timestamp for monotonic ordering.
459+ /// </summary>
460+ private static Guid CreateVersion7Guid ( )
461+ {
462+ // UUID v7 format (RFC 9562):
463+ // - 48 bits: Unix timestamp in milliseconds (big-endian)
464+ // - 4 bits: version (0111 = 7)
465+ // - 12 bits: random
466+ // - 2 bits: variant (10)
467+ // - 62 bits: random
468+
469+ var timestamp = DateTimeOffset . UtcNow . ToUnixTimeMilliseconds ( ) ;
470+ byte [ ] bytes = new byte [ 16 ] ;
471+
472+ // Fill with random data first
473+ #if NETSTANDARD2_0
474+ using ( var rng = System . Security . Cryptography . RandomNumberGenerator . Create ( ) )
475+ {
476+ rng . GetBytes ( bytes ) ;
477+ }
478+ #else
479+ System . Security . Cryptography . RandomNumberGenerator . Fill ( bytes ) ;
480+ #endif
481+
482+ // Set timestamp (48 bits, big-endian) in first 6 bytes
483+ bytes [ 0 ] = ( byte ) ( timestamp >> 40 ) ;
484+ bytes [ 1 ] = ( byte ) ( timestamp >> 32 ) ;
485+ bytes [ 2 ] = ( byte ) ( timestamp >> 24 ) ;
486+ bytes [ 3 ] = ( byte ) ( timestamp >> 16 ) ;
487+ bytes [ 4 ] = ( byte ) ( timestamp >> 8 ) ;
488+ bytes [ 5 ] = ( byte ) timestamp ;
489+
490+ // Set version 7 (0111) in high nibble of byte 6
491+ bytes [ 6 ] = ( byte ) ( ( bytes [ 6 ] & 0x0F ) | 0x70 ) ;
492+
493+ // Set variant (10) in high 2 bits of byte 8
494+ bytes [ 8 ] = ( byte ) ( ( bytes [ 8 ] & 0x3F ) | 0x80 ) ;
495+
496+ // Convert from big-endian byte array to Guid
497+ // Guid constructor expects bytes in a specific order for the first 8 bytes
498+ // (little-endian for the first three components on Windows)
499+ // We need to swap bytes to match the Guid's internal layout
500+ return new Guid (
501+ ( int ) ( bytes [ 0 ] << 24 | bytes [ 1 ] << 16 | bytes [ 2 ] << 8 | bytes [ 3 ] ) , // a (big-endian to int)
502+ ( short ) ( bytes [ 4 ] << 8 | bytes [ 5 ] ) , // b (big-endian to short)
503+ ( short ) ( bytes [ 6 ] << 8 | bytes [ 7 ] ) , // c (big-endian to short)
504+ bytes [ 8 ] , bytes [ 9 ] , bytes [ 10 ] , bytes [ 11 ] ,
505+ bytes [ 12 ] , bytes [ 13 ] , bytes [ 14 ] , bytes [ 15 ] ) ;
506+ }
507+ #endif
452508
453509 private static bool IsTerminalStatus ( McpTaskStatus status ) =>
454510 status is McpTaskStatus . Completed or McpTaskStatus . Failed or McpTaskStatus . Cancelled ;
0 commit comments