ローカルLLM(Ollama)で、AIチャットクライアント(C#)を作り、MCPサーバーを動かす

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

以前、github modelやAzure OpenAIを使ってAIチャットクライアントを作成し、そこでMCPサーバーを使うということをした。

github modelsを使ってAIチャットクライアントを作成

qiita.com

Azure OpenAIを使って、AIチャットクライアント(C#)を作る

qiita.com

今回は、クラウドのAIモデルサービスではなく、ローカルのPC上でLLMが動くようにしてAIチャットクライアントを動かせるらしい、と聞いたので、それをやってみる。

前提

  • 2025/09/06実施
  • ローカルLLMとして、Ollama v0.11.10 を使用

今回作成したコード

github.com

やったこと

やったことを順番にメモする。

Ollamaのインストール

Ollamaをダウンロードする。

https://ollama.com/download/windows

ダウンロードしたファイルを実行

インストール始まる

インストール完了すると、こういうクライアントが立ち上がった。 Ollama用のクライアントなのか?

スタートメニューをみると、こういうアプリがインストールされていた。

参考サイトには、手でダウンロードする手順が案内されているが、今はこのクライアントのここで選んだモデルで、最初になにかチャットしようと入力すると、ダウンロードしてくれる様子。

ただ参考サイトと違う手順をするのが不安なので、サイト通りにコマンドからダウンロードする形でやってみる。

モデル(gemma2:2b)のインストール

下の、モデルのDLサイトに行き、

https://ollama.com/search

参考ページと同じ、gemma2を検索する。
👇のようなのが出てくるので、gemma2:2bを押す

👇のようなのが出てくるので、ここに表示されているコマンドをコピーして、コマンドプロンプトに入力する。

そうすると、👇のように、ダウンロードが始まる。

ダウンロードが終わるとこうなった。

「こんにちは!」と入れてみると、応答が返ってきた。 これで、gemma2:2bがインストールされた。

※このコンソールは、コマンドプロンプトで、さっきの

ollama run gemma2:2b

を実行すれば立ち上がるっぽい。
また、上でOllamaを入れたときにインストールされたクライアントアプリは、これの代わりをしてくれるっぽい。

自作AIチャットクライアントと連携する

参考ページによると、
gemma2:2bをLLMとしてつかうには、エンドポイントとして

localhost:11434

を使い、モデル名として

gemma2:2b

を使えばよいっぽい。やってみる。

前回、github modelsを使って自作AIチャットクライアントでMCPサーバーを使う実験をした。

qiita.com

その時のコードから、ChatClient周りだけを少し改造し、👇のようにした。

using Microsoft.Extensions.AI;
using ModelContextProtocol.Client;
using OpenAI;
using System.ClientModel;
using System.Diagnostics;
using System.Net;
using System.Windows;

namespace AIChatJikken;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        PromptBox.Text = "休日のパパはなにをしていますか?";
        Key.Text = "ここにgithub modelsのキーを入れてください";
    }

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        SendButton.IsEnabled = false;
        var prompt = PromptBox.Text;

        if (prompt is null)
            return;

        ResponseBlock.Text = await GetCompletionAsync(prompt, Key.Text);
        SendButton.IsEnabled = true;
    }

    public async Task<string> GetCompletionAsync(string prompt, string key)
    {
        // MCPサーバー起動時のパラメータの設定
        var clientTransport = new StdioClientTransport(new()
        {
            // MCPサーバーのexeは、@"C:\Program Files\MyMcpServer\MyMcpServer.exe"に置くことにする。引数は無し。
            Command = @"C:\Program Files\MyMcpServer\MyMcpServer.exe",
            Arguments = [],
            Name = "My Mcp Server",
        });

        // MCPクライアントを作成(ここで、MCPサーバーが起動する)
        var mcpClient = await McpClientFactory.CreateAsync(clientTransport!);

        // ツールの名前を列挙
        var mcpTools = await mcpClient.ListToolsAsync();
        foreach (var tool in mcpTools)
        {
            Debug.WriteLine($"MCPサーバーのツール名:{tool.Name}");
        }

        //-------------------------------

        var chatOption = new ChatOptions
        {
            ToolMode = ChatToolMode.Auto,
            Tools = [.. mcpTools]
        };

        // エンドポイントを指定
        // LLMのモデルを指定
        var aiClient = new OllamaChatClient(new Uri("http://localhost:11434/"), "gemma2:2b");

        var chatClient = aiClient.AsBuilder()
                                    .UseFunctionInvocation()
                                    .Build();

        var chatmsg = new ChatMessage(ChatRole.User, prompt);

        // チャットを送信
        var res = await chatClient.GetResponseAsync([chatmsg], chatOption);

        //-------------------------

        // MCPクライアントを終了(ここで、MCPサーバーが終了する)
        await mcpClient.DisposeAsync();

        return res.Text;
    }
}

これを動かすと、例外が起きた。

どうやら、gemma2:2bだと、MCPサーバーのツールをサポートしてないらしい。

今回は、MCPサーバーの実験をしたくてローカルLLMを探している、という都合があるので、 gemma2ではない、別のモデルでMCPサーバーのツールをサポートしてるモデルがあるかを探してみる。

→さらっと検索したところ、llama3.2だとサポートしているっぽい。それをダウンロードしてみる。

モデル(llama3.2)のインストール

gemma2を入れたときと同じやり方で、llama3.2をインストールする。

llama3.2をLLMとしてつかうには、モデル名として

llama3.2

を使えばよいっぽい。

→やってみた。エラーは出なくなり、MCPサーバーも使われているっぽい。(MCPサーバーのツール側にbreakをはって、そこを通っていることを確認した)

が、自作MCPを使ってくれているならこういう回答がくるだろうという、思った回答が来ない。

using ModelContextProtocol.Server;
using System.ComponentModel;

namespace MyMcpServer;

[McpServerToolType]
internal static class HowToSpendHoliday
{
    [McpServerTool, Description("Get how to spend holiday. 休日の過ごし方を取得する。")]
    internal static string GetHowToSpendHoliday(
        [Description("休日の過ごし方を取得したい家族の呼称")] string target) => target switch
        {
            "パパ" => "ごろごろしています。",
            "ママ" => "ショッピングしています。",
            "息子" => "走り回っています。",
            "娘" => "歌を歌っています。",
            _ => "どうしてるんでしょう?",
        };
}

MCPサーバーのツールのコードがこれなので、「パパは休日に何をしてますか?」と聞くと、「ごろごろしてます」という回答が欲しいのだが、全然思った内容が来ない。

こんなのが来る。

github modelsや、AzureOpenAI経由でgpt4などを使っていた時は、うまく回答してくれていた)

なぜかを調べたところ、MCPのツールが、日本語をうまく受けることができていないっぽい。 breakを張ったときの、引数の値が変なことになっていた。

inputは👇(休日のパパはなにをしていますか?)なので、明らかに変。


こまったので、
試しに、少しMCP側を改造して、inputも同じ内容で英語にして聞いてみると、うまく答えてくれた。

英語にしたMCP

using ModelContextProtocol.Server;
using System.ComponentModel;

namespace MyMcpServer;

[McpServerToolType]
internal static class HowToSpendHoliday
{
    [McpServerTool, Description("Get how to spend holiday. 休日の過ごし方を取得する。")]
    internal static string GetHowToSpendHoliday(
        [Description("A name for a family member who wants to learn how to spend their holidays. 休日の過ごし方を取得したい家族の呼称")] string target) => target switch
        {
            "father" => "Swimming in the pool.",
            "mother" => "Shopping.",
            "son" => "Runnning.",
            "daughter" => "Singing songs.",
            _ => "I don't know",
        };
} 

breakで止めたときの引数

入力と出力

現時点では、llama3.2でMCPを使った際には、うまく日本語を認識してくれないのかもしれない。

試した結果

今回の目論見だった、ローカルLLMで自作MCPサーバーを動かすことはできた。

github modelsだったり、AzureOpenAI経由でLLMを使ったときより、Ollama環境だと、チャットの回答がすごくわかりにくかったり、言葉に違和感があったりした。

日本語だからだったり、LLMモデルの種類によるものだったりするかもしれず、別のモデルをいろいろ試すとよいものもあったりするかもしれないが、今回初めて試したときの印象はあまり良くなかった。

やはり、github modelsやAzureOpenAIなどの最新のモデルに比べると、古めのモデルになるから性能が低めなのかもしれない。

1,2個しかモデルを試していないので、他のもっと新しいモデルも試してみようと思う。

参考

ローカルLLMのすゝめ。Windows環境でのOllama(オラマ)を使った生成AI利用方法について
ほぼこのサイトの通りにさせて頂いた。ありがとうございます。

https://smooz.cloud/news/column/locak-llm-ollama/

Microsoft.Extensions.AIを利用してOllama(Phi-4)を試してみる
OllamaでChatClientをC#でつくるときのコードを参考にさせて頂いた。ありがとうございます。

https://devlog.mescius.jp/microsoft-extensions-ai-ollama-phi-4/

Chat with a local AI model using .NET
公式に、ollamaでローカルLLMとやり取りするやり方が書いてあった。

https://learn.microsoft.com/en-us/dotnet/ai/quickstarts/chat-local-model