tk3.biz
Back to Blog

I Built My Own MCP Server in C# and Added It to Claude Code as a Tool

Introduction

AI coding assistants such as Claude Code let you add custom tools through a protocol called MCP (Model Context Protocol).

“Hooking up your own tools” sounds hard, but with the official C# SDK it’s surprisingly simple. This time I used a weather tool as an example and tried building an MCP server from scratch and connecting it to Claude Code.

What Is MCP?

MCP (Model Context Protocol) is an open protocol Anthropic released in 2024. It lets AI talk to external tools and data sources through a standard interface.

Claude Code ←→ MCPプロトコル ←→ 自作MCPサーバー ←→ 外部API・DBなど

By writing your own MCP server, you can give the AI things like “a tool that calls an internal API” or “project-specific operations.”

What You Need

  • .NET 9 SDK
  • Claude Code (with access to edit its settings file)

Creating the Project

Create it as a console app.

dotnet new console -n WeatherMcp
cd WeatherMcp

Add the NuGet packages.

dotnet add package ModelContextProtocol --prerelease
dotnet add package Microsoft.Extensions.Hosting

What is ModelContextProtocol?
The official C# MCP SDK, maintained by Microsoft. You define tools with attributes, which keeps the implementation simple.

Implementation

Program.cs

Replace the whole of Program.cs with the following.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Server;

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMcpServer()
    .WithStdioServerTransport()
    .WithTools<WeatherTools>();

await builder.Build().RunAsync();

WeatherTools.cs

Add a new WeatherTools.cs file to the project.

using ModelContextProtocol.Server;
using System.ComponentModel;

[McpServerToolType]
public class WeatherTools
{
    private static readonly HttpClient _http = new();

    [McpServerTool]
    [Description("指定した都市の現在の天気(天候・気温・湿度)を取得します")]
    public static async Task<string> GetWeather(
        [Description("都市名(英語)例: Tokyo, Osaka, New York")] string city)
    {
        var url = $"https://wttr.in/{Uri.EscapeDataString(city)}?format=%C+%t+%h";
        var result = await _http.GetStringAsync(url);
        return $"{city}の天気: {result.Trim()}";
    }
}

Key points:

AttributeRole
[McpServerToolType]Declares that this class contains tools
[McpServerTool]Exposes this method as a tool
[Description]The description for the AI. Important for the AI to understand how to use the tool

The weather data comes from wttr.in, a handy service that needs no API key. What the format string means:

SymbolContent
%CWeather description (Sunny, Cloudy, etc.)
%tTemperature
%hHumidity

Testing It on Its Own

Before connecting it to Claude Code, check that it works by itself.

dotnet run

Once it starts, paste the following into standard input and press Enter.

{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }

If you get back information about the GetWeather tool, it works. Press Ctrl+C to exit.

Registering It with Claude Code

Add it to a Claude Code settings file.

  • Per project: .claude/settings.json
  • Global: ~/.claude/settings.json
{
  "mcpServers": {
    "weather": {
      "command": "dotnet",
      "args": ["run", "--project", "C:/path/to/WeatherMcp"]
    }
  }
}

Replace C:/path/to/WeatherMcp with the actual path.

Making startup faster
dotnet run builds every time, so it’s slow to start. I recommend generating an exe with dotnet publish and pointing to it directly.

dotnet publish -c Release -r win-x64 --self-contained
{
  "mcpServers": {
    "weather": {
      "command": "C:/path/to/WeatherMcp/bin/Release/net9.0/win-x64/publish/WeatherMcp.exe",
      "args": []
    }
  }
}

Trying It Out

Restart Claude Code after configuring it, and the weather server connects. Then just ask:

> 東京と大阪の今日の天気を比較して

(That asks it to compare today’s weather in Tokyo and Osaka.) Claude Code calls GetWeather twice and sums up the results it got from wttr.in.

[Tool: GetWeather(city="Tokyo")]    → Overcast +18°C 72%
[Tool: GetWeather(city="Osaka")]    → Partly cloudy +20°C 65%

東京は曇り・18℃・湿度72%、大阪は晴れ時々曇り・20℃・湿度65%です。
大阪の方が2℃高く、湿度は低めです。

The answer says Tokyo is overcast at 18°C with 72% humidity, Osaka is partly cloudy at 20°C with 65% humidity, and Osaka is 2°C warmer and less humid. The fun part is that you can see the tool calls happening.

Summary

Looking back at the steps for building an MCP server in C#:

  1. Add the ModelContextProtocol NuGet package
  2. Define tools with [McpServerToolType] / [McpServerTool]
  3. Start the server with AddMcpServer().WithStdioServerTransport().WithTools<T>()
  4. Register it in settings.json and call it from Claude Code

Overall there’s very little code, and it was pleasant that just adding attributes is enough for something to be recognized as a tool. Swap the weather API for a tool that calls an internal REST API or runs SQL queries, and it looks perfectly usable for real work. It feels like growing my own personal AI toolkit, and I want to keep experimenting with it.

Related Posts