tk3.biz
ブログ一覧に戻る Back to Blog

C#でMCPサーバーを自作してClaude Codeのツールに追加してみた I Built My Own MCP Server in C# and Added It to Claude Code as a Tool

はじめに

Claude Code などのAIコーディングアシスタントは、MCP(Model Context Protocol) というプロトコルを通じてカスタムツールを追加できます。

「自作ツールを繋げる」と聞くと難しそうですが、公式のC# SDKを使うと驚くほどシンプルに実装できます。今回は天気取得ツールを例に、ゼロからMCPサーバーを作ってClaude Codeに接続するまでを試してみました。

MCPとは?

MCP(Model Context Protocol)はAnthropicが2024年に公開したオープンプロトコルです。AIと外部ツール・データソースが標準インターフェースで通信できるようにする仕組みです。

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

MCPサーバーを自作することで「社内APIを叩くツール」「プロジェクト固有の操作」などをAIに追加できます。

用意するもの

  • .NET 9 SDK
  • Claude Code(設定ファイルを編集できる状態)

プロジェクト作成

コンソールアプリとして作成します。

dotnet new console -n WeatherMcp
cd WeatherMcp

NuGetパッケージを追加します。

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

ModelContextProtocolとは?
Microsoftが管理するC#公式MCP SDK。Toolの定義を属性ベースで書けるため実装がシンプルです。

実装

Program.cs

Program.cs をまるごと以下に置き換えます。

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

プロジェクトに WeatherTools.cs を新規作成します。

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()}";
    }
}

ポイント:

属性役割
[McpServerToolType]このクラスにToolが含まれることを宣言
[McpServerTool]このメソッドをToolとして公開
[Description]AIへの説明文。AIがToolの使い方を理解するために重要

天気データは wttr.in を使います。APIキー不要で使える便利なサービスです。フォーマット文字列の意味:

記号内容
%C天候の説明(Sunny、Cloudy など)
%t気温
%h湿度

単体動作確認

Claude Codeに繋ぐ前に単体で確認します。

dotnet run

起動したら標準入力に以下をペーストしてEnterを押します。

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

GetWeather ツールの情報が返ってきたら成功です。Ctrl+C で終了します。

Claude Codeに登録する

Claude Codeの設定ファイルに追記します。

  • プロジェクト単位: .claude/settings.json
  • グローバル: ~/.claude/settings.json
{
  "mcpServers": {
    "weather": {
      "command": "dotnet",
      "args": ["run", "--project", "C:/path/to/WeatherMcp"]
    }
  }
}

C:/path/to/WeatherMcp は実際のパスに変えてください。

起動を速くするには
dotnet run は毎回ビルドが走るため起動が遅めです。dotnet publish でexeを生成して直接指定するのがおすすめです。

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": []
    }
  }
}

実際に使ってみる

設定後にClaude Codeを再起動すると weather サーバーが接続されます。そのまま話しかけると:

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

Claude Codeが GetWeather を2回呼び出し、wttr.inから取得した結果をまとめて返してくれます。

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

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

ツール呼び出しの様子が見えるのが面白いところです。

まとめ

C#でMCPサーバーを作る手順を振り返ります:

  1. ModelContextProtocol NuGetパッケージを追加
  2. [McpServerToolType] / [McpServerTool] でToolを定義
  3. AddMcpServer().WithStdioServerTransport().WithTools<T>() でサーバー起動
  4. settings.json に登録してClaude Codeから呼び出す

全体的に実装量は少なく、属性を付けるだけでToolとして認識されるのが快適でした。天気APIの代わりに社内REST APIやSQLクエリを呼ぶToolに差し替えるだけで、実務でも十分使えそうです。自分専用のAIツールキットを育てていく感覚で、今後も試していきたいと思います。

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

dev-orchestra で役割ごとに決まった指示を渡してみた Giving dev-orchestra Standing Instructions per Role

dev-orchestra 1.2.1 で入った instructions を試しました。implementer やレビュアーへの決まった指示をリポジトリに書いておくと、毎回のプロンプトに入ります。どう表示され、どこに入り、指示を変える変更がどう扱われるかを、実際の出力で確かめます。 I tried instructions, added in dev-orchestra 1.2.1. Standing instructions for the implementer or reviewers written in the repository go into every prompt. I check, with real output, how they are shown, where they go, and how a change to the instructions is treated.

[Released] dev-orchestra: 作業単位の並列実行と役割ごとの指示を追加 v1.1.0 - v1.2.1 [Released] dev-orchestra: Parallel Work Units and Per-Role Instructions v1.1.0 - v1.2.1

dev-orchestra の v1.1.0 から v1.2.1 までの変更をまとめました。計画を作業単位に分けて並べて走らせる機能、役割ごとに決まった指示を渡す機能、設計の前の質問、進み具合の報告の設定が入りました。Windows で出力を取り込んでいる人は、文字コードの変更に注意してください。 A roundup of dev-orchestra's changes from v1.1.0 to v1.2.1: running a plan as work units side by side, standing instructions per role, questions before the design, and settings for progress reports. If you capture its output on Windows, note the encoding change.

dev-orchestra の作業単位で、計画を分けて並べて実装してみた Splitting a Plan into dev-orchestra Work Units and Implementing Them Side by Side

dev-orchestra 1.2.0 で入った作業単位を試しました。計画に ## Units を書き、2 つの作業単位を別々の git worktree で並べて Claude に実装させ、作業ツリーへマージし、最後の統合の作業単位をその場で走らせるまでを、実際のコマンドと出力で追います。 I tried the work units added in dev-orchestra 1.2.0. I wrote a ## Units section in a plan, had Claude implement two units side by side in separate git worktrees, merged them into the working tree, and ran the final integration unit in place, with the actual commands and output.