|
4 | 4 | using SeqMcpServer.Services; |
5 | 5 | using System.ComponentModel; |
6 | 6 | using System.ComponentModel.DataAnnotations; |
| 7 | +using System.Text.Json.Serialization; |
7 | 8 |
|
8 | 9 | namespace SeqMcpServer.Mcp; |
9 | 10 |
|
| 11 | +/// <summary> |
| 12 | +/// Result of converting a fuzzy filter expression to a strict Seq filter expression. |
| 13 | +/// </summary> |
| 14 | +/// <param name="StrictExpression">The strict filter expression (the original input if no conversion was needed).</param> |
| 15 | +/// <param name="MatchedAsText">True if Seq interpreted the input as a free-text search rather than a filter expression.</param> |
| 16 | +/// <param name="ReasonIfMatchedAsText">Explanation of why the input was interpreted as text, or null when it wasn't.</param> |
| 17 | +public sealed record SeqConvertFilterResult( |
| 18 | + [property: JsonPropertyName("strictExpression")] string StrictExpression, |
| 19 | + [property: JsonPropertyName("matchedAsText")] bool MatchedAsText, |
| 20 | + [property: JsonPropertyName("reasonIfMatchedAsText"), JsonIgnore(Condition = JsonIgnoreCondition.Never)] string? ReasonIfMatchedAsText); |
| 21 | + |
10 | 22 | /// <summary> |
11 | 23 | /// MCP tools for interacting with Seq structured logging server. |
12 | 24 | /// </summary> |
@@ -173,4 +185,49 @@ public static async Task<List<SignalEntity>> SignalList( |
173 | 185 | throw; |
174 | 186 | } |
175 | 187 | } |
| 188 | + |
| 189 | + /// <summary> |
| 190 | + /// Convert a fuzzy filter expression to a strict Seq filter expression. |
| 191 | + /// </summary> |
| 192 | + /// <remarks> |
| 193 | + /// Seq supports both "fuzzy" filters (like typing in the UI search box) and "strict" filters |
| 194 | + /// (formal filter expressions). This tool converts fuzzy filters to strict ones, helping users |
| 195 | + /// write correct filter expressions. For example, "error" becomes a proper filter expression. |
| 196 | + /// The result includes whether the filter was interpreted as a text search and the reason if so. |
| 197 | + /// </remarks> |
| 198 | + /// <param name="fac">Factory for creating Seq connections</param> |
| 199 | + /// <param name="fuzzyFilter">The fuzzy filter expression to convert (e.g., "error", "timeout")</param> |
| 200 | + /// <param name="workspace">Optional workspace identifier for multi-tenant scenarios</param> |
| 201 | + /// <param name="ct">Cancellation token</param> |
| 202 | + /// <returns>Conversion result including the strict expression and metadata about the conversion</returns> |
| 203 | + [McpServerTool, Description("Convert a fuzzy filter expression to a strict Seq filter expression. Helps write correct filters for SeqSearch.")] |
| 204 | + public static async Task<SeqConvertFilterResult> SeqConvertFilter( |
| 205 | + SeqConnectionFactory fac, |
| 206 | + [Required] string fuzzyFilter, |
| 207 | + string? workspace = null, |
| 208 | + CancellationToken ct = default) |
| 209 | + { |
| 210 | + try |
| 211 | + { |
| 212 | + var conn = fac.Create(workspace); |
| 213 | + var result = await conn.Expressions.ToStrictAsync(fuzzyFilter, cancellationToken: ct); |
| 214 | + |
| 215 | + if (result == null) |
| 216 | + { |
| 217 | + return new SeqConvertFilterResult(fuzzyFilter, false, null); |
| 218 | + } |
| 219 | + |
| 220 | + return new SeqConvertFilterResult( |
| 221 | + result.StrictExpression ?? fuzzyFilter, |
| 222 | + result.MatchedAsText, |
| 223 | + result.ReasonIfMatchedAsText); |
| 224 | + } |
| 225 | + catch (Exception) |
| 226 | + { |
| 227 | + // Re-throw to let MCP handle the error. Unlike the list-returning tools in this |
| 228 | + // file, there is no unambiguous "empty" SeqConvertFilterResult value, so cancellation |
| 229 | + // also propagates rather than being swallowed. |
| 230 | + throw; |
| 231 | + } |
| 232 | + } |
176 | 233 | } |
0 commit comments