Forge
csharpf583a481
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 public static IReadOnlyList<string> Validate(McpToolManifestDocument doc, int expectedSchemaVersion = 1)
30 {
31 var errors = new List<string>();
32 if (doc.SchemaVersion != expectedSchemaVersion)
33 errors.Add($"schema_version: expected {expectedSchemaVersion}, got {doc.SchemaVersion}.");
34
35 if (string.IsNullOrWhiteSpace(doc.McpId))
36 errors.Add("mcp_id: required non-empty string.");
37
38 if (doc.Tools.Count == 0)
39 errors.Add("tools: at least one tool required.");
40
41 var seen = new HashSet<string>(StringComparer.Ordinal);
42 foreach (var t in doc.Tools)
43 {
44 if (string.IsNullOrWhiteSpace(t.Name))
45 {
46 errors.Add("tools: entry with empty name.");
47 continue;
48 }
49
50 var n = t.Name.Trim();
51 if (!seen.Add(n))
52 errors.Add($"tools: duplicate name '{n}'.");
53 }
54
55 return errors;
56 }
57}
58
59
View only · write via MCP/CIDE