Skip to content

Commit b48015f

Browse files
authored
Merge pull request #2557 from nagilson/nagilson-mcp-for-installing
Provide `Language Model Tools` for LLM/VS Code Agent to Manage .NET
2 parents d38889f + 4b30efc commit b48015f

39 files changed

Lines changed: 3950 additions & 234 deletions

sample/src/extension.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,17 @@ ${stderr}`);
107107
}
108108
}
109109

110-
const sampleAcquireRegistration = vscode.commands.registerCommand('sample.dotnet.acquire', async (version) =>
110+
const sampleAcquireRegistration = vscode.commands.registerCommand('sample.dotnet.acquire', async (version: string | undefined) =>
111111
{
112112
await callAcquireAPI(version, undefined);
113113
});
114114

115-
const sampleAcquireASPNETRegistration = vscode.commands.registerCommand('sample.dotnet.acquireASPNET', async (version) =>
115+
const sampleAcquireASPNETRegistration = vscode.commands.registerCommand('sample.dotnet.acquireASPNET', async (version: string | undefined) =>
116116
{
117117
await callAcquireAPI(version, 'aspnetcore');
118118
});
119119

120-
const sampleAcquireNoForceRegistration = vscode.commands.registerCommand('sample.dotnet.acquireNoForce', async (version) =>
120+
const sampleAcquireNoForceRegistration = vscode.commands.registerCommand('sample.dotnet.acquireNoForce', async (version: string | undefined) =>
121121
{
122122
const mode = await vscode.window.showInputBox({
123123
placeHolder: 'runtime',
@@ -128,7 +128,7 @@ ${stderr}`);
128128
await callAcquireAPI(undefined, mode as DotnetInstallMode, false);
129129
});
130130

131-
const sampleAcquireStatusRegistration = vscode.commands.registerCommand('sample.dotnet.acquireStatus', async (version) =>
131+
const sampleAcquireStatusRegistration = vscode.commands.registerCommand('sample.dotnet.acquireStatus', async (version: string | undefined) =>
132132
{
133133
if (!version)
134134
{
@@ -236,7 +236,7 @@ ${stderr}`);
236236
}
237237
});
238238

239-
const sampleGlobalSDKFromRuntimeRegistration = vscode.commands.registerCommand('sample.dotnet.acquireGlobalSDK', async (version) =>
239+
const sampleGlobalSDKFromRuntimeRegistration = vscode.commands.registerCommand('sample.dotnet.acquireGlobalSDK', async (version: string | undefined) =>
240240
{
241241
if (!version)
242242
{
@@ -247,6 +247,11 @@ ${stderr}`);
247247
});
248248
}
249249

250+
if (!version)
251+
{
252+
return;
253+
}
254+
250255
try
251256
{
252257
await vscode.commands.executeCommand('dotnet.showAcquisitionLog');
@@ -303,7 +308,7 @@ ${stderr}`);
303308
${JSON.stringify(result) ?? 'undefined'}`);
304309
});
305310

306-
const sampleAvailableInstallsRegistration = vscode.commands.registerCommand('sample.dotnet.availableInstalls', async (version) =>
311+
const sampleAvailableInstallsRegistration = vscode.commands.registerCommand('sample.dotnet.availableInstalls', async (version: string | undefined) =>
307312
{
308313
let dotnetPath = await vscode.window.showInputBox({
309314
placeHolder: 'undefined',
@@ -357,7 +362,7 @@ ${JSON.stringify(result) ?? 'undefined'}`);
357362

358363
// ---------------------sdk extension registrations--------------------------
359364

360-
const sampleSDKAcquireRegistration = vscode.commands.registerCommand('sample.dotnet-sdk.acquire', async (version) =>
365+
const sampleSDKAcquireRegistration = vscode.commands.registerCommand('sample.dotnet-sdk.acquire', async (version: string | undefined) =>
361366
{
362367
if (!version)
363368
{
@@ -379,7 +384,7 @@ ${JSON.stringify(result) ?? 'undefined'}`);
379384
}
380385
});
381386

382-
const sampleSDKGlobalAcquireRegistration = vscode.commands.registerCommand('sample.dotnet-sdk.acquireGlobal', async (version) =>
387+
const sampleSDKGlobalAcquireRegistration = vscode.commands.registerCommand('sample.dotnet-sdk.acquireGlobal', async (version: string | undefined) =>
383388
{
384389
if (!version)
385390
{
@@ -390,6 +395,11 @@ ${JSON.stringify(result) ?? 'undefined'}`);
390395
});
391396
}
392397

398+
if (!version)
399+
{
400+
return;
401+
}
402+
393403
try
394404
{
395405
await vscode.commands.executeCommand('dotnet-sdk.showAcquisitionLog');
@@ -402,7 +412,7 @@ ${JSON.stringify(result) ?? 'undefined'}`);
402412
}
403413
});
404414

405-
const sampleSDKAcquireStatusRegistration = vscode.commands.registerCommand('sample.dotnet-sdk.acquireStatus', async (version) =>
415+
const sampleSDKAcquireStatusRegistration = vscode.commands.registerCommand('sample.dotnet-sdk.acquireStatus', async (version: string | undefined) =>
406416
{
407417
if (!version)
408418
{

sample/yarn.lock

Lines changed: 42 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vscode-dotnet-runtime-extension/CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,21 @@ and this project adheres to [Semantic Versioning].
77

88
## [Unreleased]
99

10+
11+
1012
## [3.1.0] - 2026-5
1113

12-
- Adds Language Model Tools for AI agents (GitHub Copilot) to install, uninstall, list, and find .NET SDKs/Runtimes.
14+
- Adds Language Model Tools for the AI chat in VS Code. These language model tools:
15+
1. Help the agent chat window resolve scenarios where C# or related extensions fail to load.
16+
2. Help agents deterministically install and uninstall the .NET SDK at the system-level, in a way that maintains updates, is visible to the user, persists across sessions, and provides a more secure and robust development environment. Prior agents often used one-off .NET installs that may have been discarded, undiscoverable, nondeterministic, or insecure.
17+
3. Provides tools to help discover what is installed and what is available for .NET runtimes and .NET SDKs.
18+
19+
20+
The language model tools may be disabled in the extension settings or in the settings JSON like so:
21+
```
22+
"dotnetAcquisitionExtension.enableLanguageModelTools": false
23+
```
24+
- The `dotnet.availableInstalls` API now accepts an optional `fallbackToFindPathInstalls` property (default `false`). When `true` and no install is found for the resolved host, it falls back to the `dotnet.findPath` logic to locate a host independently of the PATH and retries the search. This is opt-in (and enabled by the Language Model tools) to avoid a breaking change, since `findPath` may return non system-level paths depending on the environment.
1325
- Consolidate rimraf usage — thank you @Green00101!
1426
- Dependency updates.
1527

0 commit comments

Comments
 (0)