Forge
csharp54977619
1using System.Text.Json;
2
3namespace McpToolManifest;
4
5public static class McpToolManifestReader
6{
7 private static readonly JsonSerializerOptions Options = new()
8 {
9 PropertyNameCaseInsensitive = true,
10 ReadCommentHandling = JsonCommentHandling.Skip,
11 AllowTrailingCommas = true
12 };
13
14 public static McpToolManifestDocument Load(string path)
15 {
16 if (string.IsNullOrWhiteSpace(path))
17 throw new ArgumentException("Path is required.", nameof(path));
18 if (!File.Exists(path))
19 throw new FileNotFoundException("Manifest not found.", path);
20
21 var json = File.ReadAllText(path);
22 var doc = JsonSerializer.Deserialize<McpToolManifestDocument>(json, Options);
23 if (doc is null)
24 throw new InvalidDataException("Manifest deserialized to null.");
25
26 return doc;
27 }
28
29 /// <summary>Возвращает ошибки или пустой список, если структура валидна.</summary>
30 public static IReadOnlyList<string> Validate(McpToolManifestDocument doc, int expectedSchemaVersion = 1)
31 {
32 var errors = new List<string>();
33 if (doc.SchemaVersion != expectedSchemaVersion)
34 errors.Add($"schema_version: expected {expectedSchemaVersion}, got {doc.SchemaVersion}.");
35
36 if (string.IsNullOrWhiteSpace(doc.McpId))
37 errors.Add("mcp_id: required non-empty string.");
38
39 if (doc.Tools.Count == 0)
40 errors.Add("tools: at least one tool required.");
41
42 var seen = new HashSet<string>(StringComparer.Ordinal);
43 foreach (var t in doc.Tools)
44 {
45 if (string.IsNullOrWhiteSpace(t.Name))
46 {
47 errors.Add("tools: entry with empty name.");
48 continue;
49 }
50
51 var n = t.Name.Trim();
52 if (!seen.Add(n))
53 errors.Add($"tools: duplicate name '{n}'.");
54 }
55
56 return errors;
57 }
58}
59
View only · write via MCP/CIDE