forked from admin/VolcanicAgenticCore
McpOptions/McpServerConfig/PlaywrightOptions with ApplyEnvironment (PLAYWRIGHT_* variables, quote-aware ExtraArgs split) and Validate; ShellWords; mcpServers from the user settings.json. New project in the solution and referenced by the extension tests.
50 lines
2.3 KiB
C#
50 lines
2.3 KiB
C#
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Volcanic.AgenticCore.Extensions.Mcp;
|
|
|
|
/// <summary>Reads <c>"mcpServers"</c> from <c><agent dir>/settings.json</c> (the same file that lists extensions).</summary>
|
|
internal static class McpUserSettings
|
|
{
|
|
public const string AgentDirVariable = "VOLCANIC_AGENT_DIR";
|
|
|
|
private static readonly JsonSerializerOptions Json = new()
|
|
{
|
|
PropertyNameCaseInsensitive = true,
|
|
ReadCommentHandling = JsonCommentHandling.Skip,
|
|
AllowTrailingCommas = true,
|
|
Converters = { new JsonStringEnumConverter() },
|
|
};
|
|
|
|
/// <summary><c>VOLCANIC_AGENT_DIR</c>, else <c>~/.volcanic/agent</c>.</summary>
|
|
public static string AgentDir(Func<string, string?> getEnv) =>
|
|
getEnv(AgentDirVariable) is { Length: > 0 } dir
|
|
? dir
|
|
: Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".volcanic", "agent");
|
|
|
|
/// <summary>Servers in document order. A missing file or section is empty; a malformed file is logged and ignored.</summary>
|
|
public static IReadOnlyList<KeyValuePair<string, McpServerConfig>> Load(string agentDir, ILogger logger)
|
|
{
|
|
var path = Path.Combine(agentDir, "settings.json");
|
|
if (!File.Exists(path)) return [];
|
|
try
|
|
{
|
|
using var doc = JsonDocument.Parse(File.ReadAllText(path),
|
|
new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true });
|
|
if (doc.RootElement.ValueKind != JsonValueKind.Object
|
|
|| !doc.RootElement.TryGetProperty("mcpServers", out var servers)
|
|
|| servers.ValueKind != JsonValueKind.Object) return [];
|
|
var result = new List<KeyValuePair<string, McpServerConfig>>();
|
|
foreach (var server in servers.EnumerateObject())
|
|
result.Add(new(server.Name, server.Value.Deserialize<McpServerConfig>(Json) ?? new McpServerConfig()));
|
|
return result;
|
|
}
|
|
catch (Exception ex) when (ex is JsonException or IOException or UnauthorizedAccessException or NotSupportedException)
|
|
{
|
|
logger.LogWarning("Ignoring mcpServers in {Path}: {Message}", path, ex.Message);
|
|
return [];
|
|
}
|
|
}
|
|
}
|