|
| 1 | +namespace Dax.Formatter.McpServer; |
| 2 | + |
| 3 | +using Dax.Formatter; |
| 4 | +using Dax.Formatter.Models; |
| 5 | +using ModelContextProtocol.Server; |
| 6 | +using System.ComponentModel; |
| 7 | +using System.Reflection; |
| 8 | + |
| 9 | +[McpServerToolType] |
| 10 | +internal static class FormatDaxTool |
| 11 | +{ |
| 12 | + [McpServerTool( |
| 13 | + Name = "format_dax", |
| 14 | + Title = "Format DAX expressions", |
| 15 | + ReadOnly = true, |
| 16 | + Idempotent = true, |
| 17 | + OpenWorld = true, |
| 18 | + Destructive = false)] |
| 19 | + [Description(""" |
| 20 | + Formats DAX (Data Analysis Expressions) code. DAX comments are preserved. Supports both DAX queries and DAX expressions. |
| 21 | +
|
| 22 | + WHEN TO CALL: |
| 23 | + - The user asks to format, beautify, prettify or normalize DAX code. |
| 24 | +
|
| 25 | + RETURNS: |
| 26 | + An array of responses, one per input in the same order: |
| 27 | + { |
| 28 | + Formatted: string, |
| 29 | + Errors: [{ Line: int, Column: int, Message: string }] |
| 30 | + } |
| 31 | + A format failure (invalid DAX) results in null `Formatted` and a non-empty `Errors` array. |
| 32 | + A successful format results in a non-null `Formatted` and an empty or null `Errors` array. |
| 33 | +
|
| 34 | + NOTE: |
| 35 | + This tool calls an external HTTP service. Always batch multiple snippets |
| 36 | + in a single call — looping the tool wastes round-trips and is rate-limited upstream. |
| 37 | + """)] |
| 38 | + public static async Task<DaxFormatterResponse[]> FormatDax( |
| 39 | + IDaxFormatterClient client, |
| 40 | + [Description(""" |
| 41 | + The DAX expressions to format. Each array element must be a complete, |
| 42 | + independent piece of DAX code — either a DAX query or a DAX expression. |
| 43 | + """)] |
| 44 | + string[] expressions, |
| 45 | + [Description("List separator character.")] |
| 46 | + char listSeparator = ',', |
| 47 | + [Description("Decimal separator character.")] |
| 48 | + char decimalSeparator = '.', |
| 49 | + [Description(""" |
| 50 | + Controls how arguments and sub-expressions are wrapped across lines. |
| 51 | + - 'LongLine': keeps arguments compact horizontally where readable. |
| 52 | + - 'ShortLine': breaks each argument onto its own line for maximum vertical clarity. |
| 53 | + """)] |
| 54 | + DaxFormatterLineStyle lineStyle = DaxFormatterLineStyle.LongLine, |
| 55 | + [Description($""" |
| 56 | + Controls spacing between function names and their opening parentheses. |
| 57 | + - 'SpaceAfterFunction': adds a space for readability, e.g. 'SUM (x)'. |
| 58 | + - 'NoSpaceAfterFunction': removes the space for compactness, e.g. 'SUM(x)'. |
| 59 | + """)] |
| 60 | + DaxFormatterSpacingStyle spacingStyle = DaxFormatterSpacingStyle.SpaceAfterFunction, |
| 61 | + CancellationToken cancellationToken = default) |
| 62 | + { |
| 63 | + ArgumentNullException.ThrowIfNull(expressions); |
| 64 | + |
| 65 | + if (expressions.Length == 0) |
| 66 | + return []; |
| 67 | + |
| 68 | + var request = new DaxFormatterMultipleRequest(); |
| 69 | + { |
| 70 | + // Set formatting options |
| 71 | + request.DecimalSeparator = decimalSeparator; |
| 72 | + request.ListSeparator = listSeparator; |
| 73 | + request.MaxLineLength = lineStyle; |
| 74 | + request.SkipSpaceAfterFunctionName = spacingStyle; |
| 75 | + // Add caller info |
| 76 | + request.CallerApp = "Dax.Formatter.McpServer"; |
| 77 | + request.CallerVersion = typeof(Program).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion; |
| 78 | + } |
| 79 | + request.Dax.AddRange(expressions); |
| 80 | + |
| 81 | + var responses = await client.FormatAsync(request, cancellationToken).ConfigureAwait(false); |
| 82 | + return [.. responses]; |
| 83 | + } |
| 84 | +} |
0 commit comments