-
Notifications
You must be signed in to change notification settings - Fork 746
Add list_integrations and get_integration_docs MCP tools to CLI #13231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add list_integrations and get_integration_docs MCP tools to CLI #13231
Conversation
|
@copilot Implement the PR feedback |
|
@copilot Why does the schema from the ListIntegrationsTool and GetAspireDocsTool have no properties? For the ListIntegrationsTool we should respond with both names (long and short) and the description should describe how to add integrations to the apphost using the aspire cli. |
Fixed in 2c864f1 - The input schemas now include |
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 13231Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 13231" |
|
@copilot remove the GetAspireDocsTool from the CLI MCP server. instead I want you to introduce a new annotation called AgentContentAnnotation into the app model (put it in the Introduce an API that looks like this to the app model: var myresource = builder.AddPostgres("pg")
.WithAgentContent(async (context) => { });The idea is that each resource can have a callback which is invoked to get text which can be returned to the agent. Introduce a new MCP tool called The context instance will be a new type called AgentContentContext which exposes a model for appending text which is ultimately rendered to the client. |
Implemented in eeaf179:
|
9ad1588 to
27515a1
Compare
|
@copilot we have decided to split some of the functionality out of this PR. Make the following changes so we can clean this up and merge it:
Once those changes are made introduce a new tool called The response for the |
Implemented in cc34ed5:
|
Co-authored-by: davidfowl <[email protected]>
Co-authored-by: davidfowl <[email protected]>
Co-authored-by: davidfowl <[email protected]>
…ttpClient timeout Co-authored-by: davidfowl <[email protected]>
Co-authored-by: davidfowl <[email protected]>
…, return JSON Co-authored-by: davidfowl <[email protected]>
Co-authored-by: davidfowl <[email protected]>
…integrations Co-authored-by: davidfowl <[email protected]>
…ent MCP tool Co-authored-by: mitchdenny <[email protected]>
Co-authored-by: mitchdenny <[email protected]>
…ocsTool Co-authored-by: mitchdenny <[email protected]>
cc34ed5 to
244698c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds two new MCP tools to the Aspire CLI that operate independently without requiring a running AppHost. These tools enhance the CLI's capability to provide integration information and documentation to users.
Key Changes:
- Adds
list_integrationstool that retrieves and formats available Aspire hosting integrations from NuGet package channels - Adds
get_integration_docstool that returns NuGet documentation URLs for specific integration packages - Extends the backchannel monitor interface with
SelectedConnectionproperty andGetConnectionsForWorkingDirectorymethod to support future AppHost selection features
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/Aspire.Cli/Mcp/ListIntegrationsTool.cs |
Implements tool for listing integrations with semantic versioning, deduplication, and friendly name extraction |
src/Aspire.Cli/Mcp/GetIntegrationDocsTool.cs |
Implements tool for retrieving NuGet documentation URLs with input validation |
src/Aspire.Cli/JsonSourceGenerationContext.cs |
Adds AOT-compatible JSON serialization support for Integration and ListIntegrationsResponse types |
src/Aspire.Cli/Commands/McpStartCommand.cs |
Registers new tools and updates tool routing logic to handle non-AppHost tools |
src/Aspire.Cli/Commands/McpCommand.cs |
Injects IPackagingService dependency for MCP command initialization |
src/Aspire.Cli/Backchannel/IAuxiliaryBackchannelMonitor.cs |
Extends interface with SelectedConnection property and GetConnectionsForWorkingDirectory method |
src/Aspire.Cli/Backchannel/AuxiliaryBackchannelMonitor.cs |
Implements new interface members with AppHost selection and scoping logic |
tests/Aspire.Cli.Tests/TestServices/TestAuxiliaryBackchannelMonitor.cs |
Mirrors production implementation for test scenarios |
tests/Aspire.Cli.Tests/Mcp/MockPackagingService.cs |
Provides test doubles for packaging service and NuGet cache |
tests/Aspire.Cli.Tests/Mcp/ListIntegrationsToolTests.cs |
Comprehensive test suite covering various scenarios for ListIntegrationsTool |
| internal sealed class GetIntegrationDocsTool : CliMcpTool | ||
| { | ||
| public override string Name => "get_integration_docs"; | ||
|
|
||
| public override string Description => "Gets documentation for a specific Aspire hosting integration package. Use this tool to get detailed information about how to use an integration within the AppHost."; | ||
|
|
||
| public override JsonElement GetInputSchema() | ||
| { | ||
| return JsonDocument.Parse(""" | ||
| { | ||
| "type": "object", | ||
| "properties": { | ||
| "packageId": { | ||
| "type": "string", | ||
| "description": "The NuGet package ID of the integration (e.g., 'Aspire.Hosting.Redis')." | ||
| }, | ||
| "packageVersion": { | ||
| "type": "string", | ||
| "description": "The version of the package (e.g., '9.0.0')." | ||
| } | ||
| }, | ||
| "required": ["packageId", "packageVersion"], | ||
| "additionalProperties": false, | ||
| "description": "Gets documentation for a specific Aspire hosting integration. Requires the package ID and version." | ||
| } | ||
| """).RootElement; | ||
| } | ||
|
|
||
| public override ValueTask<CallToolResult> CallToolAsync(ModelContextProtocol.Client.McpClient mcpClient, IReadOnlyDictionary<string, JsonElement>? arguments, CancellationToken cancellationToken) | ||
| { | ||
| // This tool does not use the MCP client as it operates locally | ||
| _ = mcpClient; | ||
| _ = cancellationToken; | ||
|
|
||
| if (arguments == null) | ||
| { | ||
| return ValueTask.FromResult(new CallToolResult | ||
| { | ||
| IsError = true, | ||
| Content = [new TextContentBlock { Text = "Arguments are required." }] | ||
| }); | ||
| } | ||
|
|
||
| if (!arguments.TryGetValue("packageId", out var packageIdElement)) | ||
| { | ||
| return ValueTask.FromResult(new CallToolResult | ||
| { | ||
| IsError = true, | ||
| Content = [new TextContentBlock { Text = "The 'packageId' parameter is required." }] | ||
| }); | ||
| } | ||
|
|
||
| var packageId = packageIdElement.GetString(); | ||
| if (string.IsNullOrEmpty(packageId)) | ||
| { | ||
| return ValueTask.FromResult(new CallToolResult | ||
| { | ||
| IsError = true, | ||
| Content = [new TextContentBlock { Text = "The 'packageId' parameter cannot be empty." }] | ||
| }); | ||
| } | ||
|
|
||
| if (!arguments.TryGetValue("packageVersion", out var packageVersionElement)) | ||
| { | ||
| return ValueTask.FromResult(new CallToolResult | ||
| { | ||
| IsError = true, | ||
| Content = [new TextContentBlock { Text = "The 'packageVersion' parameter is required." }] | ||
| }); | ||
| } | ||
|
|
||
| var packageVersion = packageVersionElement.GetString(); | ||
| if (string.IsNullOrEmpty(packageVersion)) | ||
| { | ||
| return ValueTask.FromResult(new CallToolResult | ||
| { | ||
| IsError = true, | ||
| Content = [new TextContentBlock { Text = "The 'packageVersion' parameter cannot be empty." }] | ||
| }); | ||
| } | ||
|
|
||
| var content = $""" | ||
| Instructions for the {packageId} integration can be downloaded from: | ||
| https://www.nuget.org/packages/{packageId}/{packageVersion} | ||
| Review this documentation for instructions on how to use this package within the apphost. Refer to linked documentation for additional information. | ||
| """; | ||
|
|
||
| return ValueTask.FromResult(new CallToolResult | ||
| { | ||
| Content = [new TextContentBlock { Text = content }] | ||
| }); | ||
| } | ||
| } |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing test coverage for GetIntegrationDocsTool. While ListIntegrationsTool has comprehensive tests, the GetIntegrationDocsTool lacks any test coverage.
Consider adding tests similar to ListIntegrationsToolTests.cs that verify:
- Correct tool name and description
- Valid input schema
- Error handling when arguments are null or missing
- Error handling when packageId or packageVersion are empty
- Successful response with valid parameters
- Correct URL formatting in the response
| public AppHostConnection? SelectedConnection | ||
| { | ||
| get | ||
| { | ||
| var connections = _connections.Values.ToList(); | ||
|
|
||
| if (connections.Count == 0) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| // Check if a specific AppHost was selected | ||
| if (!string.IsNullOrEmpty(SelectedAppHostPath)) | ||
| { | ||
| var selectedConnection = connections.FirstOrDefault(c => | ||
| c.AppHostInfo?.AppHostPath != null && | ||
| string.Equals(Path.GetFullPath(c.AppHostInfo.AppHostPath), Path.GetFullPath(SelectedAppHostPath), StringComparison.OrdinalIgnoreCase)); | ||
|
|
||
| if (selectedConnection != null) | ||
| { | ||
| return selectedConnection; | ||
| } | ||
|
|
||
| // Clear the selection since the AppHost is no longer available | ||
| SelectedAppHostPath = null; | ||
| } | ||
|
|
||
| // Look for in-scope connections | ||
| var inScopeConnections = connections.Where(c => c.IsInScope).ToList(); | ||
|
|
||
| if (inScopeConnections.Count == 1) | ||
| { | ||
| return inScopeConnections[0]; | ||
| } | ||
|
|
||
| // Fall back to the first available connection | ||
| return connections.FirstOrDefault(); | ||
| } | ||
| } | ||
|
|
||
| public IReadOnlyList<AppHostConnection> GetConnectionsForWorkingDirectory(DirectoryInfo workingDirectory) | ||
| { | ||
| return _connections.Values | ||
| .Where(c => IsAppHostInScopeOfDirectory(c.AppHostInfo?.AppHostPath, workingDirectory.FullName)) | ||
| .ToList(); | ||
| } | ||
|
|
||
| private static bool IsAppHostInScopeOfDirectory(string? appHostPath, string workingDirectory) | ||
| { | ||
| if (string.IsNullOrEmpty(appHostPath)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| // Normalize the paths for comparison | ||
| var normalizedWorkingDirectory = Path.GetFullPath(workingDirectory); | ||
| var normalizedAppHostPath = Path.GetFullPath(appHostPath); | ||
|
|
||
| // Check if the AppHost path is within the working directory | ||
| var relativePath = Path.GetRelativePath(normalizedWorkingDirectory, normalizedAppHostPath); | ||
| return !relativePath.StartsWith("..", StringComparison.Ordinal) && !Path.IsPathRooted(relativePath); | ||
| } |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code duplication detected between TestAuxiliaryBackchannelMonitor and AuxiliaryBackchannelMonitor. The SelectedConnection property (lines 16-54) and IsAppHostInScopeOfDirectory method (lines 63-77) are duplicated from the production implementation.
This duplication could lead to maintenance issues if the selection logic needs to be updated. Consider extracting this logic into a shared helper class or extension method that both implementations can use, ensuring the test implementation stays in sync with the production code.
Description
Adds two new MCP tools to the CLI that operate independently without requiring a running AppHost:
MCP Tools
list_integrations- Lists available Aspire hosting integrations (NuGet packages) from configured package channels, returns structured JSON withIntegrationschema containing short name, full package ID, and version. Description explains how to add integrations usingaspire add <integration-name>and references theget_integration_docstool for more information.get_integration_docs- Gets documentation URL for a specific integration package. TakespackageIdandpackageVersionas required parameters and returns content with the NuGet package URL for documentation.Changes
ListIntegrationsTool.cs- UsesIPackagingServiceto fetch packages, extracts friendly names, uses semantic versioning for correct ordering, returns structured JSON. Updated description to referenceget_integration_docstool.GetIntegrationDocsTool.cs- New tool that returns NuGet package documentation URLs for integrationsMcpStartCommand.cs- Registers new toolsMcpCommand.cs- InjectsIPackagingServicedependencyJsonSourceGenerationContext.cs- AddedIntegrationandListIntegrationsResponsetypes for AOT-compatible JSON serializationChecklist
<remarks />and<code />elements on your triple slash comments?doc-ideatemplatebreaking-changetemplatediagnostictemplateOriginal prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.