| 1 | using System.Text.Json; |
| 2 | using ModelContextProtocol.Protocol; |
| 3 | using ModelContextProtocol.Server; |
| 4 | |
| 5 | namespace AgentForge.Mcp; |
| 6 | |
| 7 | internal static class ForgeMcpCapabilitiesPoller |
| 8 | { |
| 9 | internal static void StartIfEnabled( |
| 10 | McpServer server, |
| 11 | HttpClient http, |
| 12 | ForgeMcpSettings settings, |
| 13 | JsonSerializerOptions jsonOptions, |
| 14 | CancellationToken cancellationToken) |
| 15 | { |
| 16 | if (!settings.ToolsListChanged || settings.CapabilitiesPollSeconds <= 0) |
| 17 | return; |
| 18 | |
| 19 | _ = Task.Run(() => RunAsync(server, http, settings, jsonOptions, cancellationToken), cancellationToken); |
| 20 | } |
| 21 | |
| 22 | private static async Task RunAsync( |
| 23 | McpServer server, |
| 24 | HttpClient http, |
| 25 | ForgeMcpSettings settings, |
| 26 | JsonSerializerOptions jsonOptions, |
| 27 | CancellationToken cancellationToken) |
| 28 | { |
| 29 | string? previousFingerprint = null; |
| 30 | var interval = TimeSpan.FromSeconds(settings.CapabilitiesPollSeconds); |
| 31 | |
| 32 | while (!cancellationToken.IsCancellationRequested) |
| 33 | { |
| 34 | try |
| 35 | { |
| 36 | await Task.Delay(interval, cancellationToken).ConfigureAwait(false); |
| 37 | var fingerprint = await ForgeMcpToolLoader.FetchToolsFingerprintAsync(http, jsonOptions, cancellationToken) |
| 38 | .ConfigureAwait(false); |
| 39 | if (fingerprint is null || string.Equals(previousFingerprint, fingerprint, StringComparison.Ordinal)) |
| 40 | continue; |
| 41 | |
| 42 | previousFingerprint = fingerprint; |
| 43 | await server.SendNotificationAsync(NotificationMethods.ToolListChangedNotification).ConfigureAwait(false); |
| 44 | Console.Error.WriteLine("Forge MCP: capabilities changed — sent notifications/tools/list_changed."); |
| 45 | } |
| 46 | catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) |
| 47 | { |
| 48 | break; |
| 49 | } |
| 50 | catch (Exception ex) |
| 51 | { |
| 52 | Console.Error.WriteLine($"Forge MCP: capabilities poll loop error: {ex.Message}"); |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | |