Skip to content

Conversation

JohnMcPMS
Copy link
Member

@JohnMcPMS JohnMcPMS commented Jul 22, 2025

Discussion on further MCP work: #5609

Change

This change adds an MCP server that provides two tools:

  • Find packages
    • Searches for packages based on a single input value, returning information about each one found.
  • Install package
    • Installs a package given a single input value, which is expected to be an identifier, name or moniker (same rules as winget CLI)

The package response looks like:

{
  "identifier":"Microsoft.VisualStudioCode",
  "name":"Microsoft Visual Studio Code",
  "catalog":"winget",
  "isInstalled":true,
  "installedVersion":"1.102.1",
  "installedLocation":"%LOCALAPPDATA%\\Programs\\Microsoft VS Code\\",  <- Is actually real path, not tokenized
  "isUpdateAvailable":false
}

Also includes:

  • A group policy that determines whether the MCP server is allowed to operate
  • An mcp command that helps with manually configuring an MCP client
  • A change to the default COM caller behavior that makes it only use the file name
    • Also changes to not use the package family name if it is the same as the current process (so we can better differentiate our own callers)
  • A Version property on the PackageManager COM object that returns the version string as 1.2.3 or 1.2.3-preview.
    • Start preferentially using this in the PowerShell module to get the version rather than running the CLI

Validation

I have ensured that the various portions of this change function within the context of the dev package.

Microsoft Reviewers: Open in CodeFlow

florelis
florelis previously approved these changes Jul 25, 2025
<data name="ConfigurationEnableMessage" xml:space="preserve">
<value>Enable configuration components. Requires store access.</value>
<data name="ExtendedFeaturesEnableMessage" xml:space="preserve">
<value>Enable extended features. Requires store access.</value>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit concerned about there being confusion between "experimental" and "extended" features, but I can't think of a better naming.

@@ -119,4 +119,7 @@ namespace AppInstaller::Filesystem
// Gets the PathDetails used for the given path.
// This is exposed primarily to allow for testing, GetPathTo should be preferred.
PathDetails GetPathDetailsFor(PathName path, bool forDisplay = false);

// Gets the path to the executable for the given process id.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are HANDLEs just the process ID? 🤯
(Or is the comment wrong?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is wrong because I wrote it with process id at first and then changed it when I realized what I actually had to pass in. Might hold on changing it in case there aren't any other substantial issues.

}

// First attempt a more exact match
var findResult = FindForIdentifier(packageCatalog, identifier, expandedFields: false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The search is using "FindForQuery", so it may return different results. I'm pretty sure people don't like that in the CLI, but I don't know how this ends up being called by the hosts to know if that would be an issue here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The search tool does:

  1. ID equals OR Name equals OR Moniker equals (what the CLI uses for "targeted" commands)
  2. ID contains OR Name contains OR Moniker equals (a looser version to provide some flexibility to the agent)

only using option 2 if nothing is found with option 1.

The install tool does:

  1. Id equals
  2. Id equals OR Name equals OR Moniker equals

similarly falling back to 2 only if nothing is found with 1.

The expectation is that the agent will always use the search tool to gather information, then use the result from that to inform the identifier field to use in the install tool.


public string? InstalledLocation { get; set; }

public bool? IsUpdateAvailable { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't include the available version?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COM doesn't provide it easily.

Comment on lines +14 to +22
public string? Message { get; set; }

public bool? RebootRequired { get; set; }

public int? ErrorCode { get; set; }

public uint? InstallerErrorCode { get; set; }

public FindPackageResult? InstalledPackageInformation { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does MCP allow us to say what any of these mean?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, as far as I know, there is no ability to provide output schemas, despite the MCP documentation suggesting that you should have them.

{
public string? Message { get; set; }

public bool? RebootRequired { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have information about this in the manifest, right? Could we report it ahead of time using the progress message? I think it would be nice to not get that information at the very end.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I can get it in the search results, then I will add it there so that the agent can better reason over that fact.

@florelis
Copy link
Member

Is this not going to be behind an experimental feature?

@florelis
Copy link
Member

Also, I'd really appreciate it if you could update doc/ReleaseNotes.md with this feature

@JohnMcPMS
Copy link
Member Author

Is this not going to be behind an experimental feature?

I don't see it as needed given that the user needs to opt-in to using it by manually configuring their client. The implementation of that block would either require reading the config in the MCP server or hacking in a check based on the caller info.

@denelon for opinion.

@@ -176,6 +176,16 @@
<decimal value="0" />
</disabledValue>
</policy>
<policy name="EnableWindowsPackageManagerMcpServer" class="Machine" displayName="$(string.EnableWindowsPackageManagerMcpServer)" explainText="$(string.EnableWindowsPackageManagerMcpServerExplanation)" key="Software\Policies\Microsoft\Windows\AppInstaller" valueName="EnableWindowsPackageManagerMcpServer">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case we have not done it, we'll need to talk to policy team about updating the policy template later.

<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.Msix.Utils" Version="2.1.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageVersion Include="Microsoft.PowerShell.SDK" Version="7.4.6" />
<PackageVersion Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.1.6" />
<PackageVersion Include="Microsoft.Windows.SDK.Contracts" Version="10.0.26100.1742" />
<PackageVersion Include="ModelContextProtocol" Version="0.2.0-preview.3" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: do we want to add a todo to update to stable version later?

@@ -3,6 +3,7 @@
#include "pch.h"
#include "ConfigureExportCommand.h"
#include "Workflows/ConfigurationFlow.h"
#include "Workflows/MSStoreInstallerHandler.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I'm wondering, why did we not put this command under Commands folder ...

if (SUCCEEDED(wil::QueryFullProcessImageNameW(processHandle.get(), 0, imageName)) &&
(imageName.get() != nullptr))
std::filesystem::path executablePath = AppInstaller::Filesystem::GetExecutablePathForProcess(processHandle.get());
if (executablePath.has_filename())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the executable path does not have file name, should we return the full path instead of empty?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so; that sounds like an error and logging would be appropriate.

yao-msft
yao-msft previously approved these changes Jul 25, 2025
using Microsoft.Management.Deployment;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using System.ComponentModel;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I guess Stylecop is not turned on for this project? It should complain that System. should be on the top.

.WithStdioServerTransport()
.WithTools<WingetPackageTools>();

builder.Build().Run();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this handle shutdown events automagically by the framework?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I doubt it, but I had thought of that. Maybe my change to improve our quiesce story should include an event to make it easier for clients to act appropriately without needing to re-implement the entire "window to listen for shutdown messages".

@JohnMcPMS JohnMcPMS dismissed stale reviews from yao-msft and florelis via 413431c July 26, 2025 00:12
@JohnMcPMS JohnMcPMS merged commit eaab1bf into microsoft:master Jul 26, 2025
9 checks passed
@JohnMcPMS JohnMcPMS deleted the mcp-poc branch July 26, 2025 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants