A running solution where you can add server middleware to ASP.NET Core minimal APIs
1. Install MCP NuGet packages
Install the MCP packages from NuGet. Use the latest stable versions where possible. Example package links:
2. Add the MCP server to your host
Register the MCP server and transports during host building. WithToolsFromAssembly()
scans your assembly for [McpServerToolType]
classes and auto-registers tools.
builder.Services
.AddMcpServer()
.WithHttpTransport()
.WithToolsFromAssembly();
var app = builder.Build();
app.MapEndpoints(); // Your own extension method, defined later
app.MapMcp(pattern: "api/mcp"); // Expose MCP over HTTP
await app.RunAsync();
3. Define MCP tools
Mark the types that contain tools with the appropriate attribute McpServerToolType
and annotate tool methods McpServerTool
. Provide clear Description
text to improve discovery and documentation.
Note: attribute names and exact signatures depend on the MCP C# SDK you're using.
[McpServerToolType]
public static class Endpoint
{
public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder app)
{
app.MapGet("api/users", Handler)
.WithSummary("Get list of users")
.Produces<PagedResponse<GetUserResponse>>(StatusCodes.Status200OK)
.WithOpenApi();
return app;
}
[McpServerTool(Name = "get_paged_list_users"), Description("Get cursor-based paged list of users")]
private static async Task<PagedResponse<GetUserResponse>> Handler(ApplicationDbContext dbContext, [AsParameters] GetUsersRequest request, IValidator<GetUsersRequest> validator, CancellationToken token)
{
await validator.ValidateAndThrowAsync(request, token);
var users = await dbContext.Users
.Select(user => Map(user))
.ToPagedAsync(request, token);
return users;
}
}
4. Add authorization
The Model Context Protocol provides authorization capabilities. In our API, we are using OAuth 2.1, and we will reuse it. Just add RequireAuthorization
to the MCP endpoint.
// Add JWT authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "jwt_authority";
options.Audience = "jwt_audiences";
});
builder.Services.AddAuthorization(c => c.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
...
app.MapMcp(pattern: "api/mcp").RequireAuthorization();
...
5. Test locally
- Use the Model Context Protocol inspector app: https://modelcontextprotocol.io/legacy/tools/inspector
- Use your VS Code with Copilot: https://code.visualstudio.com/docs/copilot/customization/mcp-servers
- Any other tool that supports MCP
Conclusions
There’s a straightforward way to add MCP server support to an existing minimal API. We can reuse the same endpoint handlers and authorization logic, and dependency injection works as before. With this setup, the server can now expose both a REST API and MCP. The key point is to provide clear descriptions of tools and parameters to improve discovery and usability for LLMs.
Additional references
- Model Context Protocol docs: https://modelcontextprotocol.io/docs/getting-started/intro
- Getting-started blog post: https://devblogs.microsoft.com/dotnet/build-a-model-context-protocol-mcp-server-in-csharp/
- GitHub C# SDK: https://github.com/modelcontextprotocol/csharp-sdk/blob/main/README.md
Top comments (0)