In my last post, Connecting Open WebUI to MCP Servers, we connected our local AI to existing MCP servers and saw the power of the protocol. But the real competitive advantage lies in building your own MCP servers — custom tools that wire your AI directly to your systems, your data, your workflows.
This is the third in a four-part series. We’re going to build the same MCP server in four different languages: Go, JavaScript, C#, and Python. Each post covers its language in isolation — you only need to read the one matching your stack.
The tool we’re building? A Google Reviews scraper. Your AI agent asks “What are our latest Google reviews?” or “Show me reviews with ratings below 3 stars” — and the MCP server fetches and returns structured data. One server. Every AI client. Forever reusable.
In the Go version, we compiled to a single binary. In the JavaScript version, we ran on Node.js. Here in C#, we’re leveraging the full power of ASP.NET Core with dependency injection, hosted service lifecycles, and the official Microsoft-maintained SDK.
What Is an MCP Server?
MCP (Model Context Protocol) is an open specification that defines how AI clients communicate with external tools and data sources. Think of it as a universal USB-C port for AI. One standard. Any tool. Any client.
The protocol exposes three primitives:
- Tools — actions the AI can invoke (scrape reviews, query a database, create a file)
- Resources — readable data sources (a live dashboard, an API response, a document)
- Prompts — reusable message templates for common workflows
The official MCP SDK is available in six languages, all Tier 1 for feature completeness and protocol support: TypeScript, Python, C#, and Go (maintained in collaboration with Google), plus Java and Rust at Tier 2. The SDK handles the JSON-RPC plumbing. You focus on the business logic.
For the full SDK reference, see the official MCP SDK documentation.
Setting Up the C# SDK
The official C# SDK is published as three NuGet packages and is maintained in collaboration with Microsoft. The package selection depends on your hosting needs:
- ModelContextProtocol.Core – Minimum dependencies. Use if you only need the client or low-level server APIs.
- ModelContextProtocol – The main package with hosting and dependency injection. Use this for most projects. References
ModelContextProtocol.Core. - ModelContextProtocol.AspNetCore – HTTP-based MCP servers in ASP.NET Core. References
ModelContextProtocol.
Create a new project and install the packages:
dotnet new web -o mcp-google-reviews
cd mcp-google-reviews
dotnet add package ModelContextProtocol.AspNetCore
What this command is doing:
dotnet new web– Creates a new minimal API project withProgram.csas the entry point. This is the fastest way to start an ASP.NET Core application.dotnet add package ModelContextProtocol.AspNetCore– Installs the full MCP C# SDK with ASP.NET Core hosting. This pulls in both the core SDK and the HTTP transport middleware.
The Complete Google Reviews MCP Server in C#
Here is the full server. It exposes a single tool — fetch_reviews — that takes a Google Maps place ID and returns the latest reviews as structured JSON.
Replace the contents of Program.cs with:
using ModelContextProtocol.Server;
using System.ComponentModel;
var builder = WebApplication.CreateBuilder(args);
// Register MCP server with dependency injection
builder.Services.AddMcpServer()
.WithHttpTransport(options =>
{
// Stateless mode is recommended for simple API-style servers.
// This means no session tracking, which is fine for our use case.
options.Stateless = true;
})
.WithToolsFromAssembly();
var app = builder.Build();
// Map the MCP endpoint
app.MapMcp();
// Configure the application to listen on port 3003
app.Run("http://localhost:3003");
[McpServerToolType]
public static class GoogleReviewsTool
{
///
/// Fetch Google reviews for a business using its Place ID.
///
[McpServerTool, Description(
"Fetch Google reviews for a business using its Place ID. Returns structured review data including ratings, text, and author names.")]
public static string FetchReviews(
[Description("The Google Maps place ID of the business")] string placeId,
[Description("Maximum number of reviews to return, defaults to 10")] int limit = 10)
{
// In a real implementation, you would:
// 1. Call the Google Places API with placeId
// 2. Parse the response into review objects
// 3. Return structured JSON
var reviews = new[]
{
new { AuthorName = "Alice Johnson", Rating = 5, Text = "Excellent service! The team went above and beyond.", TimeAgo = "2 days ago" },
new { AuthorName = "Bob Smith", Rating = 4, Text = "Great experience overall, minor wait time.", TimeAgo = "1 week ago" },
new { AuthorName = "Carol Davis", Rating = 1, Text = "Disappointing. Did not meet expectations.", TimeAgo = "3 weeks ago" },
};
var result = new
{
placeId,
reviews = reviews.Take(limit),
count = reviews.Length
};
return System.Text.Json.JsonSerializer.Serialize(result, new System.Text.Json.JsonSerializerOptions
{
WriteIndented = true
});
}
}
What this code is doing:
builder.Services.AddMcpServer()– Registers the MCP server in ASP.NET Core’s dependency injection container. This makes the MCP pipeline available throughout your application lifecycle..WithHttpTransport(options)– Configures the server to use Streamable HTTP transport. TheStateless = trueoption means the server does not track sessions — each request is self-contained. This is recommended for simple API-style servers like ours that don’t need server-to-client push notifications..WithToolsFromAssembly()– Discovers all tool classes in the current assembly at compile time. Every static class marked with[McpServerToolType]is automatically scanned, and every method with[McpServerTool]becomes an MCP tool. No manual registration needed.[McpServerToolType]– Marks this class as containing MCP tools. The SDK scans for classes with this attribute during startup.[McpServerTool]– Marks theFetchReviewsmethod as an MCP tool. Combined withDescriptionattributes on both the method and parameters, the SDK auto-generates the tool’s schema that AI clients use to invoke it correctly.app.MapMcp()– Maps the MCP endpoint at/mcp. All MCP protocol communication flows through this route.app.Run("http://localhost:3003")– Starts the ASP.NET Core server, listening on port 3003.
Running the Server
Build and run the server:
dotnet run
Expected output:
Now listening on: http://localhost:3003
Application started. Press Ctrl+C to shut down.
Google Reviews MCP server starting
Connecting to Open WebUI
Follow the same process from my Connecting Open WebUI to MCP Servers post, pointing the Server URL to http://localhost:3003
- Navigate to Admin Settings → External Tools in your Open WebUI admin panel
- Click + (Add Server)
- Set Type to MCP (Streamable HTTP)
- Set Server URL to
http://localhost:3003 - Set Auth to None
- Click Save
From Example to Production
The code above returns sample data. For production, inject HttpClient via ASP.NET Core’s DI container:
builder.Services.AddHttpClient<GooglePlacesClient>(client =>
{
client.BaseAddress = new Uri("https://places.googleapis.com");
client.DefaultRequestHeaders.Add("X-Goog-Api-Key", Environment.GetEnvironmentVariable("GOOGLE_API_KEY"));
});
Then inject it into your tool:
public static class GoogleReviewsTool
{
private static HttpClient _httpClient;
public static void Configure(HttpClient httpClient)
{
_httpClient = httpClient;
}
[McpServerTool, Description("...")]
public static async Task<string> FetchReviews(string placeId, int limit = 10)
{
var response = await _httpClient.GetAsync($"/v1/places/{placeId}:reviews");
var data = await response.Content.ReadAsStringAsync();
return data;
}
}
The MCP structure stays identical. ASP.NET Core handles everything else: HTTP lifecycle, connection pooling, graceful shutdown, structured logging, health checks, and more.
What’s Next
We built this in C#. Here is how all four languages compare:
- Go version – Compiled to a single binary. Best for performance-critical, minimal-footprint deployments.
- JavaScript version – Runs on Node.js or Bun. Great for web teams already working in JavaScript.
- Python version – Built with the
FastMCPAPI using decorators. The quickest to write and prototype. - This C# version – Full ASP.NET Core integration with dependency injection. Ideal for enterprise stacks and teams already invested in .NET.
For the full C# SDK documentation, see the MCP C# SDK documentation.
Key Takeaway
- Type safety: C#’s strongly-typed method signatures and
System.ComponentModel.Descriptionattributes mean the MCP SDK generates perfectly typed JSON Schema at compile time. No runtime surprises, no schema drift. - Enterprise integration: ASP.NET Core gives you structured logging, health checks, graceful shutdown, and middleware pipelines — all the things your production services already depend on, now available to your MCP server.
- Strategic: Your AI agent has direct, typed access to your company’s review data. No middleware, no vendor lock-in. Just a C# service that returns data your LLM can act on.

Leave a Reply