Skip to content

MCP Inspector integration #625

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

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,252 changes: 1,252 additions & 0 deletions CommunityToolkit.Aspire.sln

Large diffs are not rendered by default.

10 changes: 4 additions & 6 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<PackageVersion Include="Aspire.Hosting" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.Dapr" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.Azure.AppContainers" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.Azure.AppContainers" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.Azure.Redis" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.NodeJS" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.PostgreSQL" Version="$(AspireVersion)" />
Expand All @@ -16,6 +16,8 @@
<PackageVersion Include="Aspire.Hosting.Redis" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.MongoDB" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="$(AspireVersion)" />
<PackageVersion Include="ModelContextProtocol" Version="0.1.0-preview.6" />
<PackageVersion Include="ModelContextProtocol.AspNetCore" Version="0.1.0-preview.6" />
</ItemGroup>
<ItemGroup Label="Core Packages">
<!-- AspNetCore packages -->
Expand Down Expand Up @@ -53,11 +55,9 @@
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="$(OpenTelemetryVersion)" />
<PackageVersion Include="OpenTelemetry.Exporter.InMemory" Version="$(OpenTelemetryVersion)" />
</ItemGroup>

<ItemGroup Label="Build Dependencies">
<PackageVersion Include="Microsoft.DotNet.GenAPI.Task" Version="9.0.103-servicing.25065.25" />
</ItemGroup>

<ItemGroup Label="Integration Packages">
<PackageVersion Include="Azure.Provisioning.AppContainers" Version="1.0.0" />
<PackageVersion Include="JsonSchema.Net" Version="7.3.3" />
Expand All @@ -82,7 +82,6 @@
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="7.3.1" />
</ItemGroup>

<ItemGroup Label="Testing">
<!-- Testing packages -->
<PackageVersion Include="Aspire.Hosting.Testing" Version="$(AspireVersion)" />
Expand All @@ -98,8 +97,7 @@
<PackageVersion Include="Testcontainers" Version="$(TestContainersVersion)" />
<PackageVersion Include="Testcontainers.MsSql" Version="$(TestContainersVersion)" />
</ItemGroup>

<ItemGroup Label=".NET 9 Overrides" Condition="'$(TargetFramework)' == 'net9.0'">
<PackageVersion Update="Microsoft.Extensions.Logging.Abstractions" Version="9.0.3" />
</ItemGroup>
</Project>
</Project>
4 changes: 4 additions & 0 deletions docs/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ Once a release of .NET Aspire with that API is available, the API in the .NET As
## CTASPIRE002

Support for loading extensions into SQLite requires either a NuGet package or folder path to the library to be provided, and as a result there is some custom logic to load the extension based on the path or NuGet package. This logic will require some experimenting to figure out edge cases, so the feature for extension loading will be kept as experimental until it is proven to be stable.

## CTASPIRE003

The underlying type used here may change to a different resource type in the future. Avoid taking a direct dependency on the Aspire type, instead rely on the CommunityToolkit resource type returned or the `Resource` type from Aspire.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<Sdk Name="Aspire.AppHost.Sdk" Version="$(AspireAppHostSdkVersion)" />

<PropertyGroup>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>985811f2-fd0c-480a-885b-bc6cc0574b62</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../../../src/CommunityToolkit.Aspire.Hosting.McpInspector/CommunityToolkit.Aspire.Hosting.McpInspector.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="../CommunityToolkit.Aspire.Hosting.McpInspector.McpServer/CommunityToolkit.Aspire.Hosting.McpInspector.McpServer.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
var builder = DistributedApplication.CreateBuilder(args);

var server = builder.AddProject<Projects.CommunityToolkit_Aspire_Hosting_McpInspector_McpServer>("mcp-server");

builder.AddMcpInspector("mcp-inspector")
.WithMcpServer(server)
;

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17118;http://localhost:15207",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21173",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22290"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15207",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19133",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20023"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<PackageReference Include="ModelContextProtocol" />
<PackageReference Include="ModelContextProtocol.AspNetCore" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using ModelContextProtocol.Server;
using System.ComponentModel;

var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddMcpServer()
.WithTools<McpServerTools>();

var app = builder.Build();

app.MapMcp();

app.Run();

[McpServerToolType]
class McpServerTools
{
[McpServerTool, Description("An echo tool")]
public static string Echo(string message) => $"Echo: {message}";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5230",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7295;http://localhost:5230",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>An Aspire to run the MCP Inspector against a MCP server.</Description>
<AdditionalPackageTags>ai mcp debugging hosting</AdditionalPackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Diagnostics.CodeAnalysis;

namespace Aspire.Hosting.ApplicationModel;

/// <summary>
/// Resource for the MCP Inspector server.
/// </summary>
/// <param name="name">The name of the resource.</param>
/// <remarks>
/// This resource will run as a Node.js process using the npx command.
///
/// In future, it is likely to become a container resource, once <seealso href="https://github.com/modelcontextprotocol/inspector/issues/237"/> is resolved.
/// </remarks>
[Experimental("CTASPIRE003")]
public class McpInspectorResource(string name) : ExecutableResource(name, "npx", "");
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Aspire.Hosting.ApplicationModel;
#pragma warning disable CTASPIRE003

namespace Aspire.Hosting;

/// <summary>
/// Provides extension methods for adding the MCP Inspector to an <see cref="IDistributedApplicationBuilder"/>.
/// </summary>
public static class McpInspectorResourceBuilderExtensions
{
/// <summary>
/// Adds a MCP Inspector container resource to the <see cref="IDistributedApplicationBuilder"/>.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/> to which the MCP Inspector resource will be added.</param>
/// <param name="name">The name of the MCP Inspector container resource.</param>
public static IResourceBuilder<McpInspectorResource> AddMcpInspector(this IDistributedApplicationBuilder builder, [ResourceName] string name)
{
var resource = builder.AddResource(new McpInspectorResource(name))
.WithArgs(["-y", "@modelcontextprotocol/inspector"])
.ExcludeFromManifest()
.WithHttpEndpoint(isProxied: false, port: Random.Shared.Next(3000, 4000), env: "CLIENT_PORT", name: "client")
.WithHttpEndpoint(isProxied: false, port: Random.Shared.Next(4000, 5000), env: "SERVER_PORT", name: "server-proxy");

return resource
.WithEnvironment(ctx =>
{
ctx.EnvironmentVariables["MCP_PROXY_FULL_ADDRESS"] = resource.GetEndpoint("server-proxy");
});
}

/// <summary>
/// Configures the MCP Inspector resource to use a specified MCP server resource that uses SSE as the transport type.
/// </summary>
/// <typeparam name="TResource">The type of the MCP server resource.</typeparam>
/// <param name="builder">The <see cref="IResourceBuilder{T}"/> used to configure the MCP Inspector resource.</param>
/// <param name="mcpServer">The <see cref="IResourceBuilder{T}"/> for the MCP server resource.</param>
/// <param name="route">The route that the SSE connection will use.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{McpInspectorResource}"/> for further configuration.</returns>
public static IResourceBuilder<McpInspectorResource> WithMcpServer<TResource>(this IResourceBuilder<McpInspectorResource> builder, IResourceBuilder<TResource> mcpServer, string route = "/sse")
where TResource : IResourceWithEndpoints
{
return builder.WithArgs(ctx =>
{
var httpEndpoint = mcpServer.Resource.GetEndpoint("http");

var url = ReferenceExpression.Create($"{httpEndpoint}{route}");
ctx.Args.Add(url);
});
}
}
Loading