| | | 1 | | @using Shared.Contracts.Mcp |
| | | 2 | | @using System.Dynamic |
| | | 3 | | |
| | | 4 | | <Details Text=@SharedResource.Description" IsRounded> |
| | | 5 | | <MarkdownBlock Content="@Tool.Description" /> |
| | | 6 | | </Details> |
| | | 7 | | |
| | | 8 | | <RadzenTemplateForm TItem="JsonSchemaProperty" Data="@_jsonSchemaProperty" Submit="RunMcpToolAsync"> |
| | | 9 | | <RadzenStack Gap="1em"> |
| | | 10 | | <MCPShemaProperties SchemaProperty="_jsonSchemaProperty" Values="@_formData" /> |
| | | 11 | | <RadzenButton ButtonType="ButtonType.Submit" Text="@Tool.Name" IsBusy="@IsBusy" /> |
| | | 12 | | </RadzenStack> |
| | | 13 | | </RadzenTemplateForm> |
| | | 14 | | |
| | 0 | 15 | | @if (!string.IsNullOrEmpty(Result)) |
| | | 16 | | { |
| | | 17 | | <RadzenText Text="Result" TextStyle="TextStyle.Overline" /> |
| | | 18 | | <MarkdownBlock Content="@Result" /> |
| | | 19 | | } |
| | | 20 | | |
| | | 21 | | @code { |
| | 0 | 22 | | [Inject] IToolManager ToolManager { get; set; } = null!; |
| | 0 | 23 | | [Parameter] public string ServerName { get; set; } = null!; |
| | 0 | 24 | | [Parameter] public McpToolConfig Tool { get; set; } = null!; |
| | | 25 | | |
| | | 26 | | private JsonSchemaProperty? _jsonSchemaProperty; |
| | 0 | 27 | | private Dictionary<string, object?> _formData = []; |
| | 0 | 28 | | private string Result = string.Empty; |
| | | 29 | | private bool IsBusy = false; |
| | | 30 | | |
| | | 31 | | protected override void OnParametersSet() |
| | | 32 | | { |
| | 0 | 33 | | base.OnParametersSet(); |
| | 0 | 34 | | _jsonSchemaProperty = SchemaProcessor.DeserializeSchema(Tool.InputSchema); |
| | 0 | 35 | | } |
| | | 36 | | |
| | | 37 | | private async Task RunMcpToolAsync() |
| | | 38 | | { |
| | 0 | 39 | | IsBusy = true; |
| | 0 | 40 | | var tool = ToolManager.GetMcpTools().FirstOrDefault(t => t.Name == $"mcp__{ServerName}__{Tool.Name}"); |
| | | 41 | | |
| | 0 | 42 | | if (tool is not null) |
| | | 43 | | { |
| | 0 | 44 | | var filterdArgs = _formData |
| | 0 | 45 | | .Where(f => f.Value is not null) |
| | 0 | 46 | | .ToDictionary(f => f.Key, f => f.Value!); |
| | | 47 | | |
| | 0 | 48 | | var vsToolResult = await tool.ExecuteAsync(filterdArgs, CancellationToken.None); |
| | | 49 | | #if DEBUG |
| | | 50 | | vsToolResult = HeadlessMocker.GetVsToolResult(vsToolResult); |
| | | 51 | | #endif |
| | 0 | 52 | | if (vsToolResult.Success) |
| | | 53 | | { |
| | | 54 | | try |
| | | 55 | | { |
| | 0 | 56 | | var mcpToolResult = JsonUtils.Deserialize<MCPToolResult>(vsToolResult.Result); |
| | 0 | 57 | | if (mcpToolResult is null) |
| | | 58 | | { |
| | 0 | 59 | | Result = "## Error"; |
| | | 60 | | } |
| | | 61 | | else |
| | | 62 | | { |
| | 0 | 63 | | var sb = new StringBuilder(); |
| | 0 | 64 | | foreach (var content in mcpToolResult.Content) |
| | | 65 | | { |
| | 0 | 66 | | sb.AppendLine( |
| | 0 | 67 | | content.Type switch |
| | 0 | 68 | | { |
| | 0 | 69 | | "text" => content.Text, |
| | 0 | 70 | | "image" => $"## Image\n{content.Data}\n##MimeType\n{content.MimeType}", |
| | 0 | 71 | | "resource" => $"## Resource\n{(content.Resource != null ? JsonUtils.Serialize(conten |
| | 0 | 72 | | _ => "## Error - undefined content type" |
| | 0 | 73 | | } |
| | 0 | 74 | | ); |
| | | 75 | | } |
| | 0 | 76 | | Result = sb.ToString(); |
| | | 77 | | } |
| | 0 | 78 | | } |
| | 0 | 79 | | catch |
| | | 80 | | { |
| | 0 | 81 | | Result = vsToolResult.Result; |
| | 0 | 82 | | } |
| | | 83 | | } |
| | | 84 | | else |
| | | 85 | | { |
| | 0 | 86 | | Result = $"## Error: {vsToolResult.ErrorMessage}"; |
| | | 87 | | } |
| | | 88 | | } |
| | | 89 | | else |
| | | 90 | | { |
| | 0 | 91 | | Result = "## Error: Tool is not find"; |
| | | 92 | | } |
| | | 93 | | |
| | 0 | 94 | | IsBusy = false; |
| | 0 | 95 | | await InvokeAsync(StateHasChanged); |
| | 0 | 96 | | } |
| | | 97 | | } |