Skip to content

Commit dcbc3bf

Browse files
committed
feat: Update ModelContextProtocol and refactor tool parameter handling
- Updated `ModelContextProtocol` package version to `0.1.0-preview.2` in both client and server projects. - Refactored tool calls in `Program.cs` and various service files to use `Dictionary<string, object?>` for parameter passing, enhancing type safety and nullability handling. - Adjusted unit tests to align with the new parameter structure, ensuring consistent behavior across tool interactions.
1 parent 65324e6 commit dcbc3bf

18 files changed

Lines changed: 202 additions & 168 deletions

src/NetContextClient/NetContextClient.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="ModelContextProtocol" Version="0.1.0-preview.1.25171.12" />
12+
<PackageReference Include="ModelContextProtocol" Version="0.1.0-preview.2" />
1313
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
1414
</ItemGroup>
1515

src/NetContextClient/Program.cs

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ static async Task<int> Main(string[] args)
9595
{
9696
try
9797
{
98-
var result = await client.CallToolAsync("hello", []);
98+
var result = await client.CallToolAsync("hello", new Dictionary<string, object?>());
9999
var content = result.Content.First(c => c.Type == "text");
100100
await Console.Out.WriteLineAsync(content.Text);
101101
}
@@ -114,7 +114,8 @@ static async Task<int> Main(string[] args)
114114
{
115115
try
116116
{
117-
var result = await client.CallToolAsync("set_base_directory", new() { ["directory"] = directory });
117+
var args = new Dictionary<string, object?> { ["directory"] = directory };
118+
var result = await client.CallToolAsync("set_base_directory", args);
118119
await Console.Out.WriteLineAsync("Base directory set successfully. ");
119120

120121
if (result != null && result.Content != null && result.Content.Count > 0)
@@ -136,7 +137,7 @@ static async Task<int> Main(string[] args)
136137
{
137138
try
138139
{
139-
var result = await client.CallToolAsync("get_base_directory", []);
140+
var result = await client.CallToolAsync("get_base_directory", new Dictionary<string, object?>());
140141
var jsonResponse = result.Content.First(c => c.Type == "text").Text;
141142

142143
try
@@ -194,7 +195,7 @@ static async Task<int> Main(string[] args)
194195
{
195196
try
196197
{
197-
var result = await client.CallToolAsync("list_projects", []);
198+
var result = await client.CallToolAsync("list_projects", new Dictionary<string, object?>());
198199
var jsonText = result.Content.First(c => c.Type == "text").Text;
199200
if (jsonText != null)
200201
{
@@ -220,7 +221,8 @@ static async Task<int> Main(string[] args)
220221
{
221222
try
222223
{
223-
var result = await client.CallToolAsync("list_files", new() { ["projectPath"] = projectPath });
224+
var args = new Dictionary<string, object?> { ["projectPath"] = projectPath };
225+
var result = await client.CallToolAsync("list_files", args);
224226
var jsonText = result.Content.First(c => c.Type == "text").Text;
225227
if (jsonText != null)
226228
{
@@ -246,7 +248,8 @@ static async Task<int> Main(string[] args)
246248
{
247249
try
248250
{
249-
var result = await client.CallToolAsync("open_file", new() { ["filePath"] = filePath });
251+
var args = new Dictionary<string, object?> { ["filePath"] = filePath };
252+
var result = await client.CallToolAsync("open_file", args);
250253
await Console.Out.WriteLineAsync(result.Content.First(c => c.Type == "text").Text);
251254
}
252255
catch (Exception ex)
@@ -264,7 +267,8 @@ static async Task<int> Main(string[] args)
264267
{
265268
try
266269
{
267-
var result = await client.CallToolAsync("search_code", new() { ["searchText"] = searchText });
270+
var args = new Dictionary<string, object?> { ["searchText"] = searchText };
271+
var result = await client.CallToolAsync("search_code", args);
268272
var jsonText = result.Content.First(c => c.Type == "text").Text;
269273
if (jsonText != null)
270274
{
@@ -288,7 +292,7 @@ static async Task<int> Main(string[] args)
288292
{
289293
try
290294
{
291-
var result = await client.CallToolAsync("list_solutions", []);
295+
var result = await client.CallToolAsync("list_solutions", new Dictionary<string, object?>());
292296
var jsonText = result.Content.First(c => c.Type == "text").Text;
293297
if (jsonText != null)
294298
{
@@ -314,7 +318,8 @@ static async Task<int> Main(string[] args)
314318
{
315319
try
316320
{
317-
var result = await client.CallToolAsync("list_projects_in_dir", new() { ["directory"] = directory });
321+
var args = new Dictionary<string, object?> { ["directory"] = directory };
322+
var result = await client.CallToolAsync("list_projects_in_dir", args);
318323
var jsonText = result.Content.First(c => c.Type == "text").Text;
319324
if (jsonText != null)
320325
{
@@ -340,7 +345,8 @@ static async Task<int> Main(string[] args)
340345
{
341346
try
342347
{
343-
var result = await client.CallToolAsync("list_source_files", new() { ["projectDir"] = projectDir });
348+
var args = new Dictionary<string, object?> { ["projectDir"] = projectDir };
349+
var result = await client.CallToolAsync("list_source_files", args);
344350
var jsonText = result.Content.First(c => c.Type == "text").Text;
345351
if (jsonText != null)
346352
{
@@ -366,7 +372,8 @@ static async Task<int> Main(string[] args)
366372
{
367373
try
368374
{
369-
var result = await client.CallToolAsync("add_ignore_patterns", new() { ["patterns"] = patterns });
375+
var args = new Dictionary<string, object?> { ["patterns"] = patterns };
376+
var result = await client.CallToolAsync("add_ignore_patterns", args);
370377
var jsonText = result.Content.First(c => c.Type == "text").Text;
371378
if (jsonText != null)
372379
{
@@ -414,7 +421,8 @@ static async Task<int> Main(string[] args)
414421
{
415422
try
416423
{
417-
var result = await client.CallToolAsync("remove_ignore_patterns", new() { ["patterns"] = patterns });
424+
var args = new Dictionary<string, object?> { ["patterns"] = patterns };
425+
var result = await client.CallToolAsync("remove_ignore_patterns", args);
418426
var jsonText = result.Content.First(c => c.Type == "text").Text;
419427
if (jsonText != null)
420428
{
@@ -470,7 +478,7 @@ static async Task<int> Main(string[] args)
470478
{
471479
try
472480
{
473-
var result = await client.CallToolAsync("get_state_file_location", []);
481+
var result = await client.CallToolAsync("get_state_file_location", new Dictionary<string, object?>());
474482
var jsonText = result.Content.First(c => c.Type == "text").Text;
475483
if (jsonText != null)
476484
{
@@ -491,7 +499,7 @@ static async Task<int> Main(string[] args)
491499
{
492500
try
493501
{
494-
var result = await client.CallToolAsync("get_ignore_patterns", []);
502+
var result = await client.CallToolAsync("get_ignore_patterns", new Dictionary<string, object?>());
495503
var jsonText = result.Content.First(c => c.Type == "text").Text;
496504
if (jsonText != null)
497505
{
@@ -526,7 +534,7 @@ static async Task<int> Main(string[] args)
526534
{
527535
try
528536
{
529-
var result = await client.CallToolAsync("clear_ignore_patterns", []);
537+
var result = await client.CallToolAsync("clear_ignore_patterns", new Dictionary<string, object?>());
530538
var jsonText = result.Content.First(c => c.Type == "text").Text;
531539
if (jsonText != null)
532540
{
@@ -557,7 +565,7 @@ static async Task<int> Main(string[] args)
557565
{
558566
try
559567
{
560-
var args = new Dictionary<string, object> { ["query"] = query };
568+
var args = new Dictionary<string, object?> { ["query"] = query };
561569
if (top.HasValue)
562570
{
563571
args["topK"] = top.Value;
@@ -600,7 +608,8 @@ static async Task<int> Main(string[] args)
600608
{
601609
try
602610
{
603-
var result = await client.CallToolAsync("analyze_packages", new() { ["includePreviewVersions"] = includePreview });
611+
var args = new Dictionary<string, object?> { ["includePreviewVersions"] = includePreview };
612+
var result = await client.CallToolAsync("analyze_packages", args);
604613
var jsonText = result.Content.First(c => c.Type == "text").Text;
605614

606615
// Try to deserialize to our expected type
@@ -759,7 +768,8 @@ static async Task<int> Main(string[] args)
759768
{
760769
try
761770
{
762-
var result = await client.CallToolAsync("think", new() { ["thought"] = thought });
771+
var args = new Dictionary<string, object?> { ["thought"] = thought };
772+
var result = await client.CallToolAsync("think", args);
763773
var jsonText = result.Content.First(c => c.Type == "text").Text;
764774
if (jsonText != null)
765775
{

src/NetContextServer/NetContextServer.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
<ItemGroup>
1515
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.3" />
16-
<PackageReference Include="Microsoft.SemanticKernel" Version="1.42.0" />
17-
<PackageReference Include="ModelContextProtocol" Version="0.1.0-preview.1.25171.12" />
16+
<PackageReference Include="Microsoft.SemanticKernel" Version="1.44.0" />
17+
<PackageReference Include="ModelContextProtocol" Version="0.1.0-preview.2" />
1818
<PackageReference Include="NuGet.Protocol" Version="6.13.2" />
1919
</ItemGroup>
2020

src/NetContextServer/Services/PackageAnalyzerService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public async Task<PackageAnalysis> AnalyzePackageAsync(PackageReference package,
180180
// Filter versions based on includePreviewVersions parameter
181181
var versions = includePreviewVersions
182182
? allVersions
183-
: allVersions.Where(v => !v.IsPrerelease).ToList();
183+
: [.. allVersions.Where(v => !v.IsPrerelease)];
184184

185185
if (versions.Any())
186186
{
@@ -196,7 +196,7 @@ public async Task<PackageAnalysis> AnalyzePackageAsync(PackageReference package,
196196
if (!includePreviewVersions && allVersions.Any(v => v.IsPrerelease && v > latestVersion))
197197
{
198198
var previewVersions = allVersions.Where(v => v.IsPrerelease).ToList();
199-
if (previewVersions.Any())
199+
if (previewVersions.Count != 0)
200200
{
201201
var latestPreviewVersion = previewVersions.Max();
202202
if (latestPreviewVersion != null)
@@ -211,7 +211,7 @@ public async Task<PackageAnalysis> AnalyzePackageAsync(PackageReference package,
211211
{
212212
// Check if there are preview updates available when not including them in regular updates
213213
var previewVersions = allVersions.Where(v => v.IsPrerelease && v > currentVersion).ToList();
214-
if (previewVersions.Any())
214+
if (previewVersions.Count != 0)
215215
{
216216
var latestPreviewVersion = previewVersions.Max();
217217
if (latestPreviewVersion != null)

src/NetContextServer/Tools/FileTools.cs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace NetContextServer.Tools;
88
/// <summary>
99
/// Provides MCP tools for file system operations, including file listing, project discovery, and file access.
1010
/// </summary>
11-
[McpToolType]
11+
[McpServerToolType]
1212
public static class FileTools
1313
{
1414
/// <summary>
@@ -29,7 +29,7 @@ public static class FileTools
2929
/// </summary>
3030
/// <param name="projectPath">Absolute path to the project directory containing the .cs files.</param>
3131
/// <returns>A JSON string containing an array of file paths.</returns>
32-
[McpTool("list_files")]
32+
[McpServerTool("list_files")]
3333
[Description("Lists all .NET source files in the specified project directory.")]
3434
public static string ListFiles(
3535
[Description("Absolute path to the project directory containing the .cs files")]
@@ -40,7 +40,7 @@ public static string ListFiles(
4040
/// Scans the current solution and returns all .csproj files found.
4141
/// </summary>
4242
/// <returns>A JSON string containing an array of project file paths.</returns>
43-
[McpTool("list_projects")]
43+
[McpServerTool("list_projects")]
4444
[Description("Scans the current solution and returns all .csproj files found.")]
4545
public static string ListProjects() =>
4646
JsonSerializer.Serialize(FileService.ListProjects(), DefaultJsonOptions);
@@ -50,7 +50,7 @@ public static string ListProjects() =>
5050
/// </summary>
5151
/// <param name="directory">Absolute path to the directory to search for .csproj files.</param>
5252
/// <returns>A JSON string containing an array of project file paths.</returns>
53-
[McpTool("list_projects_in_dir")]
53+
[McpServerTool("list_projects_in_dir")]
5454
[Description("Searches a specific directory for .csproj files.")]
5555
public static string ListProjectsInDirectory(
5656
[Description("Absolute path to the directory to search for .csproj files")]
@@ -61,7 +61,7 @@ public static string ListProjectsInDirectory(
6161
/// Returns all .sln files found in the base directory.
6262
/// </summary>
6363
/// <returns>A JSON string containing an array of solution file paths.</returns>
64-
[McpTool("list_solutions")]
64+
[McpServerTool("list_solutions")]
6565
[Description("Returns all .sln files found in the base directory.")]
6666
public static string ListSolutions() =>
6767
JsonSerializer.Serialize(FileService.ListSolutions(), DefaultJsonOptions);
@@ -71,19 +71,27 @@ public static string ListSolutions() =>
7171
/// </summary>
7272
/// <param name="projectDir">Absolute path to the project directory to scan for source files.</param>
7373
/// <returns>A JSON string containing an array of source file paths.</returns>
74-
[McpTool("list_source_files")]
74+
[McpServerTool("list_source_files")]
7575
[Description("Lists all source files in a project directory.")]
7676
public static string ListSourceFiles(
7777
[Description("Absolute path to the project directory to scan for source files")]
78-
string projectDir) =>
79-
JsonSerializer.Serialize(FileService.ListSourceFiles(projectDir), DefaultJsonOptions);
78+
string projectDir)
79+
{
80+
var result = FileService.ListSourceFiles(projectDir);
81+
// If it's a single item array starting with "Error:", return it as plain text
82+
if (result.Length == 1 && result[0].StartsWith("Error:"))
83+
{
84+
return result[0];
85+
}
86+
return JsonSerializer.Serialize(result, DefaultJsonOptions);
87+
}
8088

8189
/// <summary>
8290
/// Reads and returns the contents of a specified file.
8391
/// </summary>
8492
/// <param name="filePath">Absolute path to the file to read.</param>
8593
/// <returns>The contents of the file, or an error message if the file cannot be read.</returns>
86-
[McpTool("open_file")]
94+
[McpServerTool("open_file")]
8795
[Description("Reads and returns the contents of a specified file.")]
8896
public static string OpenFile(
8997
[Description("Absolute path to the file to read")]
@@ -95,7 +103,7 @@ public static string OpenFile(
95103
/// </summary>
96104
/// <param name="directory">Absolute path to set as the new base directory. Must be a valid, existing directory.</param>
97105
/// <returns>A JSON string containing a confirmation message or an error message.</returns>
98-
[McpTool("set_base_directory")]
106+
[McpServerTool("set_base_directory")]
99107
[Description("Sets the base directory for all file operations.")]
100108
public static string SetBaseDirectory(
101109
[Description("Absolute path to set as the new base directory. Must be a valid, existing directory")]
@@ -115,7 +123,7 @@ public static string SetBaseDirectory(
115123
/// Returns the current base directory used for all file operations.
116124
/// </summary>
117125
/// <returns>A JSON string containing the current base directory and whether it exists.</returns>
118-
[McpTool("get_base_directory")]
126+
[McpServerTool("get_base_directory")]
119127
[Description("Returns the current base directory used for all file operations.")]
120128
public static string GetBaseDirectory()
121129
{

src/NetContextServer/Tools/GeneralTools.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ namespace NetContextServer.Tools;
66
/// <summary>
77
/// Provides general utility tools for the MCP server.
88
/// </summary>
9-
[McpToolType]
9+
[McpServerToolType]
1010
public static class GeneralTools
1111
{
1212
/// <summary>
1313
/// Simple health check endpoint that returns a greeting message.
1414
/// </summary>
1515
/// <returns>A greeting message indicating the server is operational.</returns>
16-
[McpTool("hello")]
16+
[McpServerTool("hello")]
1717
[Description("Simple health check endpoint that returns a greeting message.")]
1818
public static string Hello() => "hello, claude.";
1919
}

src/NetContextServer/Tools/IgnorePatternTools.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ namespace NetContextServer.Tools;
77
/// <summary>
88
/// Provides MCP tools for managing file ignore patterns used during file operations.
99
/// </summary>
10-
[McpToolType]
10+
[McpServerToolType]
1111
public static class IgnorePatternTools
1212
{
1313
/// <summary>
1414
/// Adds new patterns to the ignore list for file scanning operations.
1515
/// </summary>
1616
/// <param name="patterns">Array of glob patterns to ignore (e.g. ['*.generated.cs', 'bin/*']).</param>
1717
/// <returns>A JSON string containing the results of the operation, including any invalid patterns.</returns>
18-
[McpTool("add_ignore_patterns")]
18+
[McpServerTool("add_ignore_patterns")]
1919
[Description("Adds new patterns to the ignore list for file scanning operations.")]
2020
public static string AddIgnorePatterns(
2121
[Description("Array of glob patterns to ignore (e.g. ['*.generated.cs', 'bin/*'])")]
@@ -26,7 +26,7 @@ public static string AddIgnorePatterns(
2626
/// Removes all user-defined ignore patterns from both memory and the persistent state file.
2727
/// </summary>
2828
/// <returns>A JSON string containing the updated pattern lists after clearing.</returns>
29-
[McpTool("clear_ignore_patterns")]
29+
[McpServerTool("clear_ignore_patterns")]
3030
[Description("Removes all user-defined ignore patterns from both memory and the persistent state file.")]
3131
public static string ClearIgnorePatterns() =>
3232
IgnorePatternService.ClearIgnorePatterns();
@@ -35,7 +35,7 @@ public static string ClearIgnorePatterns() =>
3535
/// Retrieves the current list of active ignore patterns from memory.
3636
/// </summary>
3737
/// <returns>A JSON string containing all active ignore patterns, including both default and user-defined patterns.</returns>
38-
[McpTool("get_ignore_patterns")]
38+
[McpServerTool("get_ignore_patterns")]
3939
[Description("Retrieves the current list of active ignore patterns from memory.")]
4040
public static string GetIgnorePatterns() =>
4141
IgnorePatternService.GetIgnorePatterns();
@@ -44,7 +44,7 @@ public static string GetIgnorePatterns() =>
4444
/// Returns the absolute path to the ignore_patterns.json state file.
4545
/// </summary>
4646
/// <returns>A JSON string containing the path to the state file.</returns>
47-
[McpTool("get_state_file_location")]
47+
[McpServerTool("get_state_file_location")]
4848
[Description("Returns the absolute path to the ignore_patterns.json state file.")]
4949
public static string GetStateFileLocation() =>
5050
IgnorePatternService.GetStateFileLocation();
@@ -54,10 +54,10 @@ public static string GetStateFileLocation() =>
5454
/// </summary>
5555
/// <param name="patterns">Array of glob patterns to remove from the ignore list.</param>
5656
/// <returns>A JSON string containing the results of the operation and updated pattern lists.</returns>
57-
[McpTool("remove_ignore_patterns")]
57+
[McpServerTool("remove_ignore_patterns")]
5858
[Description("Removes specific patterns from the ignore list.")]
5959
public static string RemoveIgnorePatterns(
6060
[Description("Array of glob patterns to remove from the ignore list")]
6161
string[] patterns) =>
6262
IgnorePatternService.RemoveIgnorePatterns(patterns);
63-
}
63+
}

0 commit comments

Comments
 (0)