An AI app is only as useful as the tools it can reach. The Model Context Protocol (MCP) gives those tools a standard shape. A server lists what it can do, and any MCP-aware client, such as an agent, VS Code, or the MCP Inspector, can discover and call it. The official C# SDK is now on 1.x, so .NET developers can build servers with the ASP.NET Core pieces they already know.
In this article we build a small inventory server with two tools and run it locally. It takes about ten minutes.
What you need
- The .NET 8 SDK or later.
- Node.js, only if you want to test with the MCP Inspector.
Step 1: Create the project
dotnet new web -n InventoryMcp
cd InventoryMcp
dotnet add package ModelContextProtocol.AspNetCore
The ModelContextProtocol.AspNetCore package is the one for HTTP-based servers. It brings in the core SDK as a dependency.
Step 2: Wire up the server
Replace the contents of Program.cs with this:
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddMcpServer()
.WithHttpTransport()
.WithToolsFromAssembly();
var app = builder.Build();
app.MapMcp("/mcp");
app.Run();
AddMcpServer registers the server, WithHttpTransport makes it reachable over HTTP, and WithToolsFromAssembly scans your project for tools. MapMcp exposes everything at /mcp.
Step 3: Add two tools
Create a file named InventoryTools.cs:
using System.ComponentModel;
using ModelContextProtocol.Server;
[McpServerToolType]
public static class InventoryTools
{
// Demo data. In a real server this would call your ERP or a database.
private static readonly StockInfo[] Data =
[
new("PLANT-1020", "MAT-9920", 450, 500),
new("PLANT-1020", "MAT-1104", 80, 120),
new("PLANT-3040", "MAT-9920", 1200, 300),
];
[McpServerTool, Description("Get stock on hand and reorder level for one material at one plant.")]
public static StockInfo? GetStock(
[Description("Plant ID, for example PLANT-1020")] string plantId,
[Description("Material number, for example MAT-9920")] string materialNumber)
=> Data.FirstOrDefault(s => s.PlantId == plantId && s.MaterialNumber == materialNumber);
[McpServerTool, Description("List the materials at a plant that are below their reorder level.")]
public static StockInfo[] ListLowStock(
[Description("Plant ID, for example PLANT-1020")] string plantId)
=> Data.Where(s => s.PlantId == plantId && s.OnHand < s.ReorderLevel).ToArray();
}
public record StockInfo(string PlantId, string MaterialNumber, int OnHand, int ReorderLevel);
Two attributes do the work. [McpServerToolType] marks the class, and [McpServerTool] marks each method that becomes a tool. The SDK builds the input schema from the method signature, so you do not write any JSON schema by hand.
Step 4: Run it and try it
Start the server on a fixed port so the URL is easy to remember:
dotnet run --urls http://localhost:5000
In a second terminal, start the MCP Inspector:
npx @modelcontextprotocol/inspector
In the Inspector, choose the Streamable HTTP transport, enter http://localhost:5000/mcp, and connect. Open the Tools tab and list the tools. You should see GetStock and ListLowStock with their descriptions. Call ListLowStock with PLANT-1020 and you get both materials back, since each one is below its reorder level.
Why the descriptions matter
The model never sees your C# code. It sees the tool name, the description, and the parameter descriptions. If those are vague, the model will pick the wrong tool or pass the wrong values. Put an example value in each parameter description, as the code above does, and the calls get noticeably more accurate.
Before you use it for real
- Keep each tool to one job and return small results. Large responses use up the model's context.
- Treat every input as untrusted. The values come from a model, so validate them like you would any user input.
- Add authentication before the endpoint leaves your machine. The mapped endpoint works with the usual ASP.NET Core authentication and authorization, for example by calling
RequireAuthorizationon it. - Return only what the caller should see. A tool result goes straight back into the model's context.
In the next article we connect an AI agent written in C# to this server, so the agent can answer stock questions on its own.
Resources
- MCP C# SDK documentation: csharp.sdk.modelcontextprotocol.io
- ModelContextProtocol.AspNetCore on NuGet: nuget.org/packages/ModelContextProtocol.AspNetCore
- Model Context Protocol: modelcontextprotocol.io
Join the conversation! Your thoughts help the community grow.