Skip to content
Go back

C# AI Agent - Part 3: Model Context Protocol (MCP) Server

Edit page

In Part 2, we enhanced the agent by giving it tools to interact with the HVAC system, and now we’re going to take it a step further by implementing a Model Context Protocol (MCP) server. This will allow us to expose our tools and data to any agent that supports MCP, not just our own.

[!TIP] You can find the complete source code for this part on the GitHub Branch: csharp-ai-agent-part-3-model-context-protocol.

What is MCP?

The Model Context Protocol (MCP) is a standardized way for language models to interact with external systems. Previously, only our agent was aware of our system and its capabilities, but what if other agents would like to leverage our tools and data as well? We can think of the MCP server the same way we think of APIs that we expose to the public internet. Everyone can use them and build different clients on top of them. MCP is just that: a protocol that allows LLMs to discover and use tools and data from external systems in a standardized way.

Setting up the MCP Server

To get started, we create a new console application inside the same ClimateCore solution for simplicity. We will need 3 dependencies in our csproj file:

<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.2" />
<PackageReference Include="ModelContextProtocol" Version="0.6.0-preview.1" />
<PackageReference Include="ModelContextProtocol.AspNetCore" Version="0.6.0-preview.1" />

Then the Program.cs file will look like this:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMcpServer()
    .WithHttpTransport()
    .WithToolsFromAssembly()
    .WithPromptsFromAssembly()
    .WithResourcesFromAssembly();
builder.WebHost.UseUrls("http://localhost:8082");   
builder.Services.AddHttpClient<ClimateCoreApiClient>(client =>
{
    client.BaseAddress = new Uri("http://localhost:8080");
});

var app = builder.Build();
app.MapMcp();
app.Run();

With this, we’re good to go, but before proceeding we also need to create some tools, prompts, and resources that the MCP server can expose to LLMs. This is very simple and very similar to what we did in Part 2. We will use the same API client to interact with our backend and we will expose tools, prompts, and resources using attributes.

Tools

[McpServerToolType]
public sealed class ClimateCoreMcpTools(ClimateCoreApiClient apiClient)
{
    [McpServerTool, Description("Gets a list of all available HVAC devices, including their IDs, names, and locations.")]
    public Task<List<DeviceDto>?> GetDevices(
        CancellationToken cancellationToken = default) =>
        apiClient.GetDevicesAsync();

    [McpServerTool, Description("Gets the real-time status of a specific device, including current temp and compressor state.")]
    public Task<DeviceStatusDto?> GetDeviceStatus(
        [Description("The device ID.")] int deviceId,
        CancellationToken cancellationToken = default) =>
        apiClient.GetDeviceStatusAsync(deviceId);
    // ... other methods
}

Prompts

[McpServerPromptType]
public class ClimateCoreMcpPrompts
{
    [McpServerPrompt, Description("Create a prompt to list all the room temperatures from the HVAC system.")]
    public string ListRoomTemperaturesPrompt() =>
        "List all room temperatures from the HVAC system.";
    // ... other prompts
}

Resources

[McpServerResourceType]
public class ClimateCoreMcpResources
{
    private static readonly string DocumentationPath = Path.Combine(AppContext.BaseDirectory, "Documentation");

    [McpServerResource(MimeType = "text/markdown")]
    [Description("Architecture overview, project structure, database schema, and quick start guide.")]
    public string GetReadme() => File.ReadAllText(Path.Combine(DocumentationPath, "README.md"));
    // ... other resources
}

Testing the MCP Server

Docker compose the infrastructure and then simply run the console application. The MCP server should now be running at http://localhost:8082. Before integrating it with Claude, we can test our MCP server using the MCP Inspector tool from GitHub: Model Context Protocol Inspector. Simply run the inspector, select the correct transport type (in our case it is Streamable HTTP), and point it to our MCP server URL: http://localhost:8082. You should be able to see the tools, prompts, and resources that we just created, and you should be able to test them as well.

Integrating with Claude

Now that we have our MCP server up and running, we can integrate it with Claude. To do this, just for testing, you can expose your MCP server to the internet using a tool like ngrok or localhost.run. Once you have a public URL that points to localhost:8082, you can add it to Claude’s MCP settings. I won’t add a screenshot because the UI might change over time, but it’s pretty straightforward. You just need to navigate to Settings → Connectors → Add Custom Connector. Give it a name and paste the public URL of your MCP server. Now just start a chat.

This is what I asked Claude:

Please check the Local MCP and analyze the last 7 days. Are there any anomalies?

And this is the response I got:

**CRITICAL ANOMALY: Master Bedroom (Device 3) Temperature Plunge**

Device 3 (Master Bedroom) experienced a severe temperature drop starting on January 23rd around 21:00:

- **Normal operating range:** 19-20.5°C (setpoint: 20°C)
- **Anomalous behavior:** Temperature plummeted from ~20.5°C to as low as 7.35°C by January 25th
- **Current temperature:** Only 7.71°C (more than 12°C below setpoint!)

This is a critical system failure. The compressor has been running excessively trying to compensate, but the temperature continues to drop rather than stabilize.

**Possible causes:**
- Broken heating element
- Refrigerant leak
- Stuck expansion valve in cooling mode
- Major duct failure or air leakage
- Faulty temperature sensor (though compressor behavior suggests real temperature issue)

**Other Observations:**

*Living Room (Device 1) - Normal operation*
- Setpoint: 21°C
- Operating within expected range (20-21.5°C)
- Typical compressor cycling

*Kitchen (Device 2) - Normal operation*
- Setpoint: 24°C
- Operating within expected range (23-24.5°C)
- Normal compressor cycling

**Immediate Action Required:**

The Master Bedroom system requires urgent attention. At 7.7°C, this is not only uncomfortable but potentially dangerous and could lead to:
- Frozen pipes
- Property damage
- Health risks for occupants
- Further HVAC system damage

**Recommendation:** Immediately inspect Device 3 (Bedroom-Master) for mechanical failure and consider shutting it down until repairs can be made to prevent further damage.

With this we have a very strong UI interface that allows us to interact with our HVAC system using any LLM that supports MCP. Pretty impressive! Of course, we would need to fine tune the resources and prompts to get the best results, but this is a great start.


Edit page
Share this post on:

Next Post
C# AI Agent - Part 2: Tool Calling and Cloud Models