<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Frank Alvarez Blog]]></title><description><![CDATA[Blog de Frank Alvarez]]></description><link>https://blog.frankalvarez.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 22:01:48 GMT</lastBuildDate><atom:link href="https://blog.frankalvarez.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Crea tu primer Servidor MCP (remoto) con .NET Web API]]></title><description><![CDATA[Un Model Context Protocol (MCP) es un protocolo que permite a los desarrolladores crear herramientas para interactuar con asistentes de IA y de esa forma extender sus capacidades.
Crear un servidor MCP no es tan complicado, pero es fundamental entend...]]></description><link>https://blog.frankalvarez.dev/crea-tu-primer-servidor-mcp-remoto-con-net-web-api</link><guid isPermaLink="true">https://blog.frankalvarez.dev/crea-tu-primer-servidor-mcp-remoto-con-net-web-api</guid><category><![CDATA[mcp]]></category><category><![CDATA[AI]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[api]]></category><category><![CDATA[Csharhp]]></category><dc:creator><![CDATA[Frank Alvarez]]></dc:creator><pubDate>Sat, 19 Jul 2025 04:13:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752898214493/7a76dd64-61c2-43f0-a8d0-9aff82832c24.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Un <a target="_blank" href="https://modelcontextprotocol.io/"><strong>Model Context Protocol (MCP)</strong></a> es un protocolo que permite a los desarrolladores crear herramientas para interactuar con <strong>asistentes de IA</strong> y de esa forma extender sus capacidades.</p>
<p>Crear un servidor <a target="_blank" href="https://modelcontextprotocol.io/"><strong>MCP</strong></a> no es tan complicado, pero es fundamental entender su concepto y funcionamiento antes de continuar. Así, te resultará más sencillo comprender todos los pasos que seguiremos a continuación para alcanzar ese primer objetivo con claridad y precisión.</p>
<h2 id="heading-configuracion-inicial-del-proyecto">Configuración inicial del proyecto</h2>
<p>Primero, debes de crear un nuevo proyecto Web API y agregar las dependencias necesarias. En mi caso, lo haré usando la terminal con <code>dotnet</code> CLI, pero también puedes hacerlo desde <a target="_blank" href="https://visualstudio.microsoft.com/">Visual Studio</a>.</p>
<blockquote>
<p>Ten en cuenta que también puedes usar un proyecto existente.</p>
</blockquote>
<p>Enseguida te dejare los comandos para inicializar el proyecto e instalar la dependencia oficial de MCP para .NET disponible mediante la terminal:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># crea el proyecto Web API</span>
dotnet new webapi -n McpWebApi
<span class="hljs-comment"># ingresamos al directorio del proyecto e instalamos la dependencia oficial de MCP par .NET</span>
<span class="hljs-built_in">cd</span> McpWebApi
dotnet add package ModelContextProtocol.AspNetCore --prerelease
</code></pre>
<h3 id="heading-configuracion-del-servidor-mcp">Configuración del servidor MCP</h3>
<p>En este punto integraremos <code>ModelContextProtocol.AspNetCore</code>, para ello modifica el archivo principal <code>Program.cs</code>. Ahí es donde registrarás los servicios así como el <strong>mapper</strong> para obtener las herramientas o tools que crees.</p>
<p>A continuación te dejo el ejemplo de como debería quedar:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);

<span class="hljs-comment">// Agregamos los servicios necesarios para MCP</span>
builder.Services.AddMcpServer()
    .WithHttpTransport()
    .WithToolsFromAssembly();

<span class="hljs-comment">// Código existente...</span>

<span class="hljs-keyword">var</span> app = builder.Build();

<span class="hljs-comment">// Mapeamos el MCP en la aplicación</span>
app.MapMcp();

<span class="hljs-comment">// Código existente...</span>

app.Run();
</code></pre>
<h2 id="heading-crea-tu-primera-tool-herramienta-de-mcp">Crea tu primera tool (herramienta) de MCP</h2>
<p>Antes de comenzar, crea una carpeta llamada <code>Tools</code> dentro del proyecto para tener en un lugar organizado todas tus herramientas.</p>
<pre><code class="lang-bash">mkdir Tools
</code></pre>
<h3 id="heading-implementando-nuestro-tool-hello-world">Implementando nuestro tool: Hello World!</h3>
<p>Dentro de la carpeta <code>Tools</code>, crea el archivo <code>WelcomeTool.cs</code> con el siguiente contenido:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.ComponentModel;
<span class="hljs-keyword">using</span> ModelContextProtocol.Server;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">McpWebApi.Tools</span>;

[<span class="hljs-meta">McpServerToolType</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WelcomeTool</span>
{
    [<span class="hljs-meta">McpServerTool, Description(<span class="hljs-meta-string">"Returns a welcome message with the provided name."</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> <span class="hljs-title">SayWelcomeMessage</span>(<span class="hljs-params">String name</span>)</span>
    {
        <span class="hljs-keyword">return</span> <span class="hljs-string">$"Welcome to MCP, <span class="hljs-subst">{name}</span>!"</span>;
    }
}
</code></pre>
<p><strong>Puntos importantes:</strong></p>
<ul>
<li><p><code>[McpServerToolType]</code>: Marca la clase como contenedora de herramientas <strong>MCP</strong>. Ten en cuenta que este atributo servirá como guía para obtener todas las <strong>Server Tools</strong> mediante el mapper configurado con <code>app.MapMcp()</code>.</p>
</li>
<li><p><code>[McpServerTool]</code>: Identifica el método como una herramienta o tool disponible.</p>
</li>
<li><p><code>Description</code>: Proporciona contexto sobre qué hace la herramienta.</p>
</li>
</ul>
<blockquote>
<p>Como puedes observar, crear un tool es similar a crear un controlador en un proyecto de .NET. Seguramente debe de parecerte familiar.</p>
</blockquote>
<h3 id="heading-ejecutando-el-servidor">Ejecutando el servidor</h3>
<p>Con todo configurado, ejecuta el proyecto con el siguiente comando:</p>
<pre><code class="lang-bash">dotnet run
</code></pre>
<p>Luego de eso, verifica en la consola la url de tu servidor, en mi caso es <a target="_blank" href="http://localhost:5038"><code>http://localhost:5038</code></a>.</p>
<blockquote>
<p>Si usas Visual Studio, lo más probable es que la URL se abra automáticamente en tu navegador.</p>
</blockquote>
<h2 id="heading-configuracion-de-vs-code-para-usar-tu-mcp">Configuración de VS Code para usar tu MCP</h2>
<h3 id="heading-configuracion-del-servidor-mcp-1">Configuración del servidor MCP</h3>
<p>Para que <a target="_blank" href="https://code.visualstudio.com/"><strong>VS Code</strong></a> reconozca tu <strong>servidor MCP</strong>, necesitaremos crear un archivo de configuración. Para ello creamos la carpeta <code>.vscode</code> y el dentro el archivo <code>mcp.json</code> de la siguiente manera:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"servers"</span>: {
        <span class="hljs-attr">"my-first-mcp-server"</span>: {
            <span class="hljs-attr">"url"</span>: <span class="hljs-string">"http://localhost:5038"</span>,
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"http"</span>
        }
    },
    <span class="hljs-attr">"inputs"</span>: []
}
</code></pre>
<p><strong>Detalles de la configuración:</strong></p>
<ul>
<li><p><code>my-first-mcp-server</code>: Nombre identificador de tu servidor (puedes modificarlo a tu gusto).</p>
</li>
<li><p><code>url</code>: Es la dirección donde estará corriendo nuestro servidor MCP.</p>
</li>
<li><p><code>type</code>: Especifica que usaremos HTTP con <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events">SSE</a> en este caso.</p>
</li>
</ul>
<p>También puedes usar el comando <code>&gt; MCP: Add Server</code> en VS Code (como alternativa):</p>
<ol>
<li><p>Abre la paleta de comandos (Cmd/Ctrl + Shift + P)</p>
</li>
<li><p>Busca "MCP: Add Server"</p>
</li>
<li><p>Sigue las instrucciones para configurar tu servidor, será mucho más fácil posiblemente.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752896620750/ca5a5da4-3b2a-440d-816b-6da7cdcea6c5.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-prueba-tu-mcp-con-github-copilot-chat">Prueba tu MCP con GitHub Copilot Chat</h2>
<h3 id="heading-iniciando-el-servidor-mcp">Iniciando el servidor MCP</h3>
<p>Una vez que tengas el archivo <code>mcp.json</code> configurado, <strong>asegúrate de que tu proyecto .NET esté corriendo.</strong> Para hacerlo, debes de ir de nuevo al archivo JSON y te aparecerá el estado del servidor MCP así como la opción de iniciar en el caso de que no lo esté.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752896917931/bb67b978-e01b-4b22-beea-b3362a8517ae.png" alt class="image--center mx-auto" /></p>
<p>Alternativamente, puedes ir a la sección de extensiones → MCP SERVERS → busca tu servidor y haz clic en "Start Server".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752896941393/98d90417-8776-49a7-a913-3fe9e84485e5.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-configurando-github-copilot-chat">Configurando Github Copilot Chat</h3>
<h3 id="heading-probamos-la-funcionalidad-de-nuestros-tools">Probamos la funcionalidad de nuestros tools</h3>
<p>Primero envía el siguiente mensaje en el chat de Copilot:</p>
<pre><code class="lang-plaintext">Envía un mensaje de bienvenida para Frank
</code></pre>
<p>Como es la primera vez, se te pedirá permiso para ejecutar la herramienta:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752897144229/a2f6f527-4b17-4bc3-a4ee-85ae67d7de5e.png" alt /></p>
<p>Y una vez que aceptes, si todo está bien configurado, te responderá algo como:</p>
<pre><code class="lang-plaintext">Welcome to MCP, Frank!
</code></pre>
<p>Ejemplo de mi resultado:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752897207474/42d87314-19fb-42dc-9311-e843f5c4f970.png" alt class="image--center mx-auto" /></p>
<p>Y felicidades 🥳, de esta forma habrás creado tu primera tool (herramienta) de MCP.</p>
<h2 id="heading-herramientas-avanzadas-con-servicios-asincronos">Herramientas avanzadas con servicios asíncronos</h2>
<p>También debes de tener en cuenta que para otros casos, sí puedes crear herramientas que interactúen con <strong>servicios externos</strong> y de forma <strong>asíncrona</strong>. Por ejemplo, si quieres buscar canciones en Deezer, puedes crear una herramienta que use un servicio para interactuar con la <a target="_blank" href="https://developers.deezer.com/api">API de Deezer</a>.</p>
<p>Enseguida de dejaré un ejemplo que probé y si funciona a la perfección:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.ComponentModel;
<span class="hljs-keyword">using</span> McpWebApi.Extensions;
<span class="hljs-keyword">using</span> McpWebApi.Services;
<span class="hljs-keyword">using</span> ModelContextProtocol.Server;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">McpWebApi.Tools</span>;

[<span class="hljs-meta">McpServerToolType</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> class <span class="hljs-title">DeezerTool</span>(<span class="hljs-params">
    IDeezerService deezerService
</span>)</span>
{
    [<span class="hljs-meta">McpServerTool, Description(<span class="hljs-meta-string">"Search for tracks on Deezer"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">SearchDeezerTrack</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> query</span>)</span>
    {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> deezerService.SearchTrackAsync(query);
        <span class="hljs-keyword">return</span> result.ToMcpJson();
    }
}
</code></pre>
<h3 id="heading-manejo-de-tipos-de-retorno">Manejo de tipos de retorno</h3>
<p><strong>Importante</strong>: Las tools de MCP por lo menos mediante la librería que estamos usando, solo pueden retornar un <code>string</code>. Por lo tanto, si necesitas retornar un objeto o un modelo, debes de convertirlo a JSON.</p>
<p>En mi caso como puedes ver, cree una extensión para serializar objetos a JSON de forma sencilla, te dejaré el código de la extensión que usé:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Text.Json;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">McpWebApi.Extensions</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">JsonExtensions</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> JsonSerializerOptions PrettyOptions = <span class="hljs-keyword">new</span>()
    {
        WriteIndented = <span class="hljs-literal">true</span>,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        PropertyNameCaseInsensitive = <span class="hljs-literal">true</span>,
        DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
    };

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> <span class="hljs-title">ToMcpJson</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> T obj</span>)</span>
    {
        <span class="hljs-keyword">return</span> JsonSerializer.Serialize(obj, PrettyOptions);
    }
}
</code></pre>
<h2 id="heading-conclusion">Conclusión</h2>
<p>Crear un servidor MCP con .NET y Web API (remoto) no es tan complicado como parece. Con unos pocos pasos, puedes tener un servidor corriendo y listo con todas las tools que necesites.</p>
<p>Eso sí, en mi caso, usé VS Code porque quería un enfoque más orientado al desarrollo multiplataforma, no limitado a Windows, como ocurriría si usara Visual Studio.</p>
<p>Eso sería todo, puedes dejar un comentario si tienes alguna duda. Hasta luego.</p>
]]></content:encoded></item><item><title><![CDATA[Error de CORS en solicitudes verificadas]]></title><description><![CDATA[El error CORS al enviar una solicitud verificada se debe a que antes de enviar la solicitud real, se envía una solicitud HTTP con el método OPTIONS.
Esto suele ocurrir porque enviamos una cabecera personalizada en la petición, como Authorization, Con...]]></description><link>https://blog.frankalvarez.dev/error-de-cors-en-solicitudes-verificadas</link><guid isPermaLink="true">https://blog.frankalvarez.dev/error-de-cors-en-solicitudes-verificadas</guid><category><![CDATA[http]]></category><category><![CDATA[CORS]]></category><category><![CDATA[authorization]]></category><dc:creator><![CDATA[Frank Alvarez]]></dc:creator><pubDate>Fri, 29 Jul 2022 13:23:10 GMT</pubDate><content:encoded><![CDATA[<p>El error <strong>CORS</strong> al enviar una solicitud verificada se debe a que antes de enviar la solicitud real, se envía una solicitud HTTP con el método <code>OPTIONS</code>.</p>
<p>Esto suele ocurrir porque enviamos una cabecera personalizada en la petición, como <code>Authorization</code>, <code>Content-Type</code>, etc. Aunque no es la única razón por la que se puede pasar de una solicitud simple a una solicitud verificada, puedes ver más detalles aquí: https://developer.mozilla.org/es/docs/Web/HTTP/CORS#solicitudes_verificadas</p>
<h2 id="heading-solucion">Solución</h2>
<p>Para solucionar este problema habilite el método <code>OPTIONS</code> en su servidor y devuelva los <strong>permisos CORS</strong>, de esta manera la solicitud confirmará que la petición es segura y procederá a enviar la petición real.</p>
]]></content:encoded></item></channel></rss>