csharp-sdk/samples/AspNetCoreMcpServer/Program.cs
pardhu c6a97d94d6
Add HttpServerSessionMode for hybrid stateful/stateless HTTP serving (#1796)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jeff Handley <jeffhandley@users.noreply.github.com>
2026-08-12 23:36:36 -07:00

73 lines
2.7 KiB
C#

using Azure.Monitor.OpenTelemetry.AspNetCore;
using ModelContextProtocol.AspNetCore;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using AspNetCoreMcpServer.Tools;
using AspNetCoreMcpServer.Resources;
using System.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
var allowedOrigins = builder.Configuration.GetSection("Mcp:AllowedOrigins").Get<string[]>() ?? ["http://localhost:5173"];
// Only enable CORS if you intentionally want browser-based cross-origin access to this server.
// Keep the allowlist narrowly scoped to known origins. Broad CORS settings weaken security.
builder.Services.AddCors(options =>
{
options.AddPolicy("McpBrowserClient", policy =>
{
policy.WithOrigins(allowedOrigins)
.WithMethods("GET", "POST", "DELETE")
// Browsers can send Accept without extra CORS configuration. These are the MCP-specific
// and non-safelisted headers the browser-based client needs for stateful Streamable HTTP.
.WithHeaders("Content-Type", "MCP-Protocol-Version", "Mcp-Session-Id")
.WithExposedHeaders("Mcp-Session-Id");
});
});
// Note: This sample uses SampleLlmTool which calls server.AsSamplingChatClient() to send
// a server-to-client sampling request. This requires stateful (session-based) mode. Set
// SessionMode = HttpServerSessionMode.Stateful since sessions are required for sampling.
// See https://csharp.sdk.modelcontextprotocol.io/concepts/sessions/sessions.html for details.
builder.Services.AddMcpServer()
.WithHttpTransport(o => o.SessionMode = HttpServerSessionMode.Stateful)
.WithTools<EchoTool>()
.WithTools<SampleLlmTool>()
.WithTools<WeatherTools>()
.WithResources<SimpleResourceType>();
var telemetry = builder.Services.AddOpenTelemetry()
.WithTracing(b => b.AddSource("*")
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation())
.WithMetrics(b => b.AddMeter("*")
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation())
.WithLogging();
string? applicationInsightsConnectionString =
builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"];
if (string.IsNullOrWhiteSpace(applicationInsightsConnectionString))
{
telemetry.UseOtlpExporter();
}
else
{
telemetry.UseAzureMonitor(options =>
options.ConnectionString = applicationInsightsConnectionString);
}
// Configure HttpClientFactory for weather.gov API
builder.Services.AddHttpClient("WeatherApi", client =>
{
client.BaseAddress = new Uri("https://api.weather.gov");
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("weather-tool", "1.0"));
});
var app = builder.Build();
app.UseCors();
app.MapMcp().RequireCors("McpBrowserClient");
app.Run();