%% > Published `=dateformat(this.created, "MMM dd, yyyy")` %% > Published Jun 06, 2025 # Having Fun Building a Simple TODO .NET MCP Server I was recently playing around building MCP Server and decided to take my basic .NET Blazor in-memory TODO list app and supercharge it by turning it into a .NET MCP (Model Context Protocol) server. The goal? To make it smart enough to talk to AI tools like Claude Desktop or GitHub Copilot, so I can manage my tasks using natural language prompts. In this blog I explained exactly how I did it. ## Starting Point: A Simple Blazor TODO App The original app was a straightforward Blazor Server application that allowed me to: - Add and remove tasks - Mark tasks as complete or incomplete - View the list of tasks It was all in-memory, no database involved, and hosted via Docker for easy setup. ## Enhancing the App with MCP To enable AI assistants to interact with the app, I needed to set up an MCP server. Here's how I integrated it: ### 1. Creating MCP Builder To add MCP functionality, I created a separate MCP web application within my existing Blazor app: ```cs var mcpBuilder = WebApplication.CreateBuilder(); mcpBuilder.WebHost.ConfigureKestrel(options => options.ListenAnyIP(5051)); mcpBuilder.Services.AddSingleton(todoService); var mcpApp = mcpBuilder.Build(); ``` This snippet sets up a new application on port `5051` specifically to handle MCP requests. ### 2. Adding MCP Endpoints I defined endpoints to handle specific actions (tools): - **Add a TODO item:** ```cs mcpApp.MapPost("/mcp/add", (TodoItem item) => { todoService.Add(item); return Results.Ok(todoService.GetAll()); }); ``` - **Remove a TODO item:** ```cs mcpApp.MapPost("/mcp/remove", (TodoItem item) => { todoService.Remove(item.Title); return Results.Ok(todoService.GetAll()); }); ``` - **Mark a TODO item as done:** ```cs mcpApp.MapPost("/mcp/markdone", (TodoItem item) => { todoService.MarkAsDone(item.Title, item.IsDone); return Results.Ok(todoService.GetAll()); }); ``` - **List all TODO items:** ```cs mcpApp.MapGet("/mcp/todos", () => { var todos = todoService.GetAll(); return Results.Ok(new { success = true, todos, count = todos.Count }); }); ``` ### 3. Keep-Alive Endpoint I also added a keep-alive endpoint to ensure persistent connections: ```cs mcpApp.MapGet("/mcp/", async (HttpContext context) => { context.Response.Headers["Content-Type"] = "text/event-stream"; await context.Response.Body.FlushAsync(); while (!context.RequestAborted.IsCancellationRequested) { await context.Response.WriteAsync(": keep-alive\n\n"); await context.Response.Body.FlushAsync(); await Task.Delay(10000, context.RequestAborted); } }); ``` ### 4. Central MCP Endpoint To support flexible MCP commands, I created a central JSON-RPC style endpoint: ```cs mcpApp.MapPost("/mcp", async (HttpContext context) => { // JSON-RPC processing logic for handling dynamic tool calls (add, remove, markdone, get) // See repository for complete implementation }); ``` This endpoint dynamically handles requests and provides capabilities to initialize the server and list available tools. ### 5. Running the MCP Server To run the MCP server alongside the main app, I launched it in a separate task: ```cs _ = Task.Run(async () => await mcpApp.RunAsync()); ``` ### 6. Integrating AI Tools I then configured VS Code to interact with my MCP server by adding a `mcp.json` file: ```json { "servers": { "my-mcp-server-635d5e26": { "url": "http://localhost:5051/mcp" } } } ``` ## Running the App with Docker The app is Dockerized for easy setup. To run it locally: 1. Clone the repository: ``` git clone https://github.com/pakbaz/TodoList.git cd TodoList ``` 2. Build and run the Docker container: ``` docker build -t todolist-app . docker run -p 8080:80 -p 5051:5051 todolist-app ``` The Blazor web interface will be available at `http://localhost:8080`, and the MCP server will listen at `http://localhost:5051/mcp`. ## Using AI to Manage the TODO List With the MCP server in place, I can now use natural language prompts to manage my tasks. For example: > "Fetch the latest 15-inch MacBook Air from apple.com and add the name and model number to the TODO list with a 'Buy' prefix." An AI assistant can process this prompt by: 1. Fetching the latest MacBook Air information from Apple's website. 2. Constructing an MCP command: ```json { "method": "add", "params": { "item": "Buy MacBook Air 15-inch M4 (Model Mac15,13)" } } ``` 3. Sending the command to the MCP server at `http://localhost:5051/mcp`. The server processes the command and updates the TODO list accordingly. ## Conclusion By integrating an MCP server into my Blazor TODO app, I've enabled seamless interaction with AI tools, allowing for dynamic task management through natural language. It's a simple yet powerful enhancement that bridges traditional applications with modern AI capabilities. Feel free to explore the project on [GitHub](https://github.com/pakbaz/TodoList) and try it out yourself!