# Turn the ASP.NET Core Web API you already have into an MCP server

> Source: <https://dev.to/hovikaghajanyan/turn-the-aspnet-core-web-api-you-already-have-into-an-mcp-server-1f55>
> Published: 2026-08-14 14:59:53+00:00

· **Repo:** [https://github.com/hovik-aghajanyan/nabu.net](https://github.com/hovik-aghajanyan/nabu.net)

· **Docs:** [https://nabu.aghajanyan.me/](https://nabu.aghajanyan.me/)

· **NuGet:** [https://www.nuget.org/packages/Nabu.Mcp.AspNetCore](https://www.nuget.org/packages/Nabu.Mcp.AspNetCore)

[ Nabu.Mcp.AspNetCore](https://github.com/hovik-aghajanyan/nabu.net) publishes existing ASP.NET Core

```
[HttpGet("{id:guid}")]
[McpTool]                                   // <- that's it
public ActionResult<TodoItem> GetById(Guid id) => ...
js
app.MapGet("/customers/{id}", (int id) => ...)
   .McpTool();                              // <- same thing for Minimal APIs
js
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddNabuMcp(options =>
{
    options.ServerName = "my-api";
    options.RequireAuthorization = true;                    // protect the MCP endpoint itself
    options.ToolVisibility = McpToolVisibility.Authorized;  // advertise only what the caller may invoke
});

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.UseNabuMcp();          // serves MCP at /mcp
app.MapControllers();
app.Run();
curl -X POST http://localhost:5000/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

Tool descriptions come from your XML docs; input schemas are generated from your CLR types, data

annotations and nullability. `[Authorize]`

, policies and roles are enforced per call — the same action

that returns 403 over HTTP returns an `isError`

tool result over MCP for the same caller, and

`tools/list`

can show each caller only the tools it is actually allowed to invoke.

Direct method invocation quietly drops everything that makes an action *safe*: `[Authorize]`

is enforced

by middleware and filters, `ModelState`

is populated by model binding, rate limiting and exception

handling live outside the method. Nabu instead captures the app's `RequestDelegate`

at startup and pushes

a synthetic `HttpContext`

— carrying the caller's identity and forwarded credentials — through the full

pipeline for every tool call.

`[McpTool]`

repeatedly with different names, parameter subsets and pinned constants.`tools/list`

evaluated with your own authorization policies.`Authorization`

, `Cookie`

or proxy headers.`Nabu.Mcp.ModelContextProtocol`

serves the same tools through the official MCP C# SDK.📚 Full documentation: [https://nabu.aghajanyan.me/](https://nabu.aghajanyan.me/)
