<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hovik Aghajanyan</title>
    <description>The latest articles on DEV Community by Hovik Aghajanyan (@hovikaghajanyan).</description>
    <link>https://dev.to/hovikaghajanyan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4075666%2Fe1b1ee54-3a77-4824-93a5-e61c90125243.jpg</url>
      <title>DEV Community: Hovik Aghajanyan</title>
      <link>https://dev.to/hovikaghajanyan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hovikaghajanyan"/>
    <language>en</language>
    <item>
      <title>Turn the ASP.NET Core Web API you already have into an MCP server

https://nabu.aghajanyan.me/</title>
      <dc:creator>Hovik Aghajanyan</dc:creator>
      <pubDate>Fri, 14 Aug 2026 15:03:13 +0000</pubDate>
      <link>https://dev.to/hovikaghajanyan/turn-the-aspnet-core-web-api-you-already-have-into-an-mcp-serverhttpsnabuaghajanyanme-26di</link>
      <guid>https://dev.to/hovikaghajanyan/turn-the-aspnet-core-web-api-you-already-have-into-an-mcp-serverhttpsnabuaghajanyanme-26di</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://nabu.aghajanyan.me/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhovik-aghajanyan.github.io%2Fnabu.net%2Fassets%2Fog-image.png" height="400" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://nabu.aghajanyan.me/" rel="noopener noreferrer" class="c-link"&gt;
            Nabu.NET — Turn your ASP.NET Core Web API into an MCP Server
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            One attribute turns existing ASP.NET Core controllers and Minimal APIs into Model Context Protocol tools. Authentication, authorization, validation and middleware keep working.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnabu.aghajanyan.me%2Fassets%2Flogo.svg" width="64" height="64"&gt;
          nabu.aghajanyan.me
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Turn the ASP.NET Core Web API you already have into an MCP server</title>
      <dc:creator>Hovik Aghajanyan</dc:creator>
      <pubDate>Fri, 14 Aug 2026 14:59:53 +0000</pubDate>
      <link>https://dev.to/hovikaghajanyan/turn-the-aspnet-core-web-api-you-already-have-into-an-mcp-server-1f55</link>
      <guid>https://dev.to/hovikaghajanyan/turn-the-aspnet-core-web-api-you-already-have-into-an-mcp-server-1f55</guid>
      <description>&lt;h1&gt;
  
  
  Nabu.NET — turn your ASP.NET Core Web API into an MCP server with one attribute
&lt;/h1&gt;

&lt;p&gt;· &lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/hovik-aghajanyan/nabu.net" rel="noopener noreferrer"&gt;https://github.com/hovik-aghajanyan/nabu.net&lt;/a&gt;&lt;br&gt;&lt;br&gt;
· &lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://nabu.aghajanyan.me/" rel="noopener noreferrer"&gt;https://nabu.aghajanyan.me/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
· &lt;strong&gt;NuGet:&lt;/strong&gt; &lt;a href="https://www.nuget.org/packages/Nabu.Mcp.AspNetCore" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/Nabu.Mcp.AspNetCore&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/hovik-aghajanyan/nabu.net" rel="noopener noreferrer"&gt;&lt;code&gt;Nabu.Mcp.AspNetCore&lt;/code&gt;&lt;/a&gt; publishes existing ASP.NET Core&lt;br&gt;
controller actions and Minimal API route handlers as &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt;&lt;br&gt;
tools — without rewriting the API. Every tool call is replayed as a real HTTP request through &lt;strong&gt;your&lt;br&gt;
application's own pipeline&lt;/strong&gt;, so authentication, authorization, validation, filters and middleware keep&lt;br&gt;
working exactly as they do over HTTP.&lt;/p&gt;

&lt;h2&gt;
  
  
  The entire integration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id:guid}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;McpTool&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;                                   &lt;span class="c1"&gt;// &amp;lt;- that's it&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TodoItem&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/customers/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;McpTool&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;                              &lt;span class="c1"&gt;// &amp;lt;- same thing for Minimal APIs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddNabuMcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-api"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequireAuthorization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                    &lt;span class="c1"&gt;// protect the MCP endpoint itself&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolVisibility&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;McpToolVisibility&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authorized&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// advertise only what the caller may invoke&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseNabuMcp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;          &lt;span class="c1"&gt;// serves MCP at /mcp&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Talk to it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5000/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"tools/list"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tool descriptions come from your XML docs; input schemas are generated from your CLR types, data&lt;br&gt;
annotations and nullability. &lt;code&gt;[Authorize]&lt;/code&gt;, policies and roles are enforced per call — the same action&lt;br&gt;
that returns 403 over HTTP returns an &lt;code&gt;isError&lt;/code&gt; tool result over MCP for the same caller, and&lt;br&gt;
&lt;code&gt;tools/list&lt;/code&gt; can show each caller only the tools it is actually allowed to invoke.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just reflect over controllers?
&lt;/h2&gt;

&lt;p&gt;Direct method invocation quietly drops everything that makes an action &lt;em&gt;safe&lt;/em&gt;: &lt;code&gt;[Authorize]&lt;/code&gt; is enforced&lt;br&gt;
by middleware and filters, &lt;code&gt;ModelState&lt;/code&gt; is populated by model binding, rate limiting and exception&lt;br&gt;
handling live outside the method. Nabu instead captures the app's &lt;code&gt;RequestDelegate&lt;/code&gt; at startup and pushes&lt;br&gt;
a synthetic &lt;code&gt;HttpContext&lt;/code&gt; — carrying the caller's identity and forwarded credentials — through the full&lt;br&gt;
pipeline for every tool call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Highlights
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One action, several tools&lt;/strong&gt; — apply &lt;code&gt;[McpTool]&lt;/code&gt; repeatedly with different names, parameter subsets and pinned constants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-caller tool visibility&lt;/strong&gt; — &lt;code&gt;tools/list&lt;/code&gt; evaluated with your own authorization policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protected headers&lt;/strong&gt; — a model-supplied argument can never override &lt;code&gt;Authorization&lt;/code&gt;, &lt;code&gt;Cookie&lt;/code&gt; or proxy headers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Official SDK adapter&lt;/strong&gt; — &lt;code&gt;Nabu.Mcp.ModelContextProtocol&lt;/code&gt; serves the same tools through the official MCP C# SDK.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broad targets&lt;/strong&gt; — netstandard2.0 (ASP.NET Core 2.1+), net8.0, net10.0. MIT licensed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📚 Full documentation: &lt;a href="https://nabu.aghajanyan.me/" rel="noopener noreferrer"&gt;https://nabu.aghajanyan.me/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aspnetcore</category>
      <category>mcp</category>
      <category>dotnet</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
