C#でMCP Serverを作る
MCP とは
と、大上段に書いてみましたが、例によって例のごとく、MCP(ModelContextProtocol)については本人の認識がまだ薄いため、解説はほかのサイトで!ということでお願いします。
うっすらとした認識でいうと、 AIモデルから使用されるユーティリティ関数群 というところです。
AIが「知らない」話題に関して、ユーティリティ関数とやり取りして情報を得、次の動作につなげていく機能のカケラ、でしょうか。
MCPサーバーの種類
MCPサーバーには以下の種類があります。
- 標準入出力型
- Webサーバー型
今回は両方とも作り方を説明します。
サンプルは こちら 。
サーバー用共通部分
まずは、サーバー用の共通部分を作ります。
こちらは上記の ユーティリティ関数 になります。
作成
$ mkdir McpServerCommon ; cd McpServerCommon
$ dotnet new classlib
$ dotnet add package ModelContextProtocol --prerelease
コードの修正
できた Class1.cs
を BookTool.cs
に変更し、内容を以下にします。
using ModelContextProtocol.Server;
using System.ComponentModel;
namespace McpServerCommon;
[McpServerToolType]
public class BookTool
{
[McpServerTool, Description("注目の漫画の情報を取得します")]
public static BookData GetFeaturedBook()
{
return new BookData
{
ISBN = "9784046818782",
Title = "魔術師クノンは見えている",
Volume = 1,
};
}
}
public class BookData
{
[Description("ISBNコード")]
public string ISBN { get; set; } = string.Empty;
[Description("タイトル")]
public string Title { get; set; } = string.Empty;
[Description("巻数")]
public int Volume { get; set; } = 1;
}
標準入出力型のMCPサーバーアプリケーション
基本的には、 .NET を使用して最小限の MCP サーバーを作成して接続する に書かれていることそのままです。
作成
$ mkdir McpServerStdio ; cd McpServerStdio
$ dotnet new console
$ dotnet add package ModelContextProtocol --prerelease
$ dotnet add package Microsoft.Extensions.Hosting
$ dotnet add reference ../McpServerCommon
コードの修正
Program.cs
を以下の内容に変更します。
using McpServerCommon;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using System.ComponentModel;
// Create a generic host builder for
// dependency injection, logging, and configuration.
var builder = Host.CreateApplicationBuilder(args);
// Configure logging for better integration with MCP clients.
builder.Logging.AddConsole(consoleLogOptions =>
{
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
// Register the MCP server and configure it to use stdio transport.
// Scan the assembly for tool definitions.
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly(typeof(BookTool).Assembly);
// Build and run the host. This starts the MCP server.
await builder.Build().RunAsync();
上記のページほとんどそのままです。
試してみる
Visual Studio Code の GitHub Copilot Chat を使って動作を確認します。
McpServerStdio ディレクトリに移動し、下記ディレクトリとファイルを作成したのち、Visual Studio Codeを起動します。
$ mkdir .vscode
$ touch .vscode/mcp.json
$ code .
.vscode/mcp.json
を以下の内容にします。
{
"inputs": [],
"servers": {
"McpServerStdio": {
"type": "stdio",
"command": "dotnet",
"args": [
"run"
]
}
}
}
Ctrl + Alt + i を押し、Copilot Chat を起動して 注目の漫画の情報を
と入力します。
上記 共通部分 で作った関数が読み込まれて実行されていることがわかります。
Webサーバー型MCPサーバーアプリケーション
こちらは ASP.NET Core extensions for the MCP C# SDK に書かれていることそのままです。
作成
$ mkdir McpServerSse ; cd McpServerSse
$ dotnet new web
$ dotnet add package ModelContextProtocol.AspNetCore --prerelease
$ dotnet add reference ../McpServerCommon
コードの修正
Program.cs
を以下の内容に変更します。
using McpServerCommon;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithToolsFromAssembly(typeof(BookTool).Assembly);
var app = builder.Build();
app.MapMcp();
app.Run("http://localhost:3001");
上記のページほとんどそのままです。
試してみる
標準入出力型と同じようにVSCodeで動作確認です。
$ mkdir .vscode
$ touch .vscode/mcp.json
$ code .
$ dotnet run
.vscode/mcp.json
を以下の内容にします。
{
"inputs": [],
"servers": {
"McpServerSse": {
"type": "sse",
"url": "http://localhost:3001/"
}
}
}
Ctrl + Alt + i を押し、Copilot Chat を起動して 注目の漫画の情報
と入力します。
Webサーバー型MCPサーバーアプリケーション with DI
せっかくC#でプログラムしているので、Webサーバー型のものに少し手を入れてDIしてみましょう。
ここでは MySql.EntityFrameworkCore
を使ってDBからデータを取得できるようにしてみます。
using McpServerSseEF;
using Microsoft.EntityFrameworkCore;
using ModelContextProtocol.Server;
using MySql.Data.MySqlClient;
using System.ComponentModel;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddDbContext<BookContext>(options =>
options.UseMySQL(ShadowContent.ConnectionString));
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithToolsFromAssembly();
var app = builder.Build();
app.MapMcp();
app.Run("http://localhost:3001");
[McpServerToolType]
public class BookTool
{
[McpServerTool, Description("ISBNコードから漫画情報を取得")]
public static BookData GetBookDataFromIsbn(
BookContext db,
[Description("ISBNコード")] string isbn)
{
return db
.Database
.SqlQueryRaw<BookData>(ShadowContent.SQL_GetBookDataFromCode, new[] {
new MySqlParameter("isbn", isbn)
})
.FirstOrDefault() ?? new BookData
{
ISBN = isbn,
Title = "Unknown",
Volume = 0
};
}
}
見てもらえば一目瞭然なのですが、 builder.Services.AddDbContext<>()
で普通にDI登録しています。
そして、 GetBookDataFromIsbn(BookContext db,
という風にMCPの関数の引数でDI取得をしています。
試してみる
上記のWebサーバー型のものと同じように試してみると。
Continueを押して続けてみると、
データが取得できました!
Webサーバー型に関してその他
通常のWebサーバーにMCPサーバーを混ぜる
何やら、 .MapMcp()
をすると、ルートが取られるようで。
app.MapMcp();
app.MapGet("/", () => "MCP Server is running!");
こういうコードにすると、
となってしまいます。
ルートを外してパスを構築しましょう
app.MapMcp();
app.MapGet("/home", () => "MCP Server is running!");
まとめ
AIに関しては迷走感があるC#ですが、MCPに関しては対応が早いですね。
これだけの短いコードで構築できるのは楽です。
Discussion