| File: Agents\McpConfigFileHelper.cs | Web Access |
| Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; using System.Text.Json; using System.Text.Json.Nodes; using Aspire.Cli.Resources; namespace Aspire.Cli.Agents; /// <summary> /// Provides shared methods for reading and parsing MCP configuration files across agent environment scanners. /// </summary> internal static class McpConfigFileHelper { /// <summary> /// Checks if a specific server is configured in an MCP config file under the given container key. /// </summary> /// <param name="configFilePath">The path to the MCP configuration file.</param> /// <param name="serverContainerKey">The JSON property name that holds the servers object (e.g., "servers", "mcpServers", "mcp").</param> /// <param name="serverName">The name of the server to check for.</param> /// <param name="preprocessContent">Optional function to preprocess file content before parsing (e.g., to strip JSONC comments).</param> /// <returns><c>true</c> if the server is configured; <c>false</c> otherwise (including when the file is missing or malformed).</returns> public static bool HasServerConfigured(string configFilePath, string serverContainerKey, string serverName, Func<string, string>? preprocessContent = null) { if (!File.Exists(configFilePath)) { return false; } try { var content = File.ReadAllText(configFilePath); if (preprocessContent is not null) { content = preprocessContent(content); } var config = JsonNode.Parse(content)?.AsObject(); if (config is null) { return false; } if (config.TryGetPropertyValue(serverContainerKey, out var serversNode) && serversNode is JsonObject servers) { return servers.ContainsKey(serverName); } return false; } catch (JsonException) { return false; } } /// <summary> /// Reads an existing MCP config file and parses it into a <see cref="JsonObject"/>, or creates a new one if the file doesn't exist. /// </summary> /// <param name="configFilePath">The path to the MCP configuration file.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <param name="preprocessContent">Optional function to preprocess file content before parsing (e.g., to strip JSONC comments).</param> /// <returns>The parsed <see cref="JsonObject"/> from the file, or a new empty <see cref="JsonObject"/> if the file doesn't exist.</returns> /// <exception cref="InvalidOperationException">Thrown when the file exists but contains malformed JSON, wrapping the underlying <see cref="JsonException"/>.</exception> public static async Task<JsonObject> ReadConfigAsync(string configFilePath, CancellationToken cancellationToken, Func<string, string>? preprocessContent = null) { if (!File.Exists(configFilePath)) { return new JsonObject(); } var content = await File.ReadAllTextAsync(configFilePath, cancellationToken); if (preprocessContent is not null) { content = preprocessContent(content); } try { return JsonNode.Parse(content)?.AsObject() ?? new JsonObject(); } catch (JsonException ex) { throw new InvalidOperationException( string.Format(CultureInfo.CurrentCulture, AgentCommandStrings.MalformedConfigFileError, configFilePath), ex); } } }