機械学習
記事内に商品プロモーションを含む場合があります

Go言語でMCPサーバーを実装し、LMStudioから使ってみた

Aru

LMStudioもMCP(Model Context Protocol)に対応したので、Go言語で独自のMCPサーバーを作ってみました。作成したのはローン計算の計算ができる「金融電卓」です。この記事では、mcp-goを使ったMCPサーバーの実装例と、それをLMStudioから使う方法について解説します。

はじめに

MCPとは?

Model Context Protocol(MCP)はClaudeの開発元であるAnthropicにより提案された、大規模言語モデル(LLM)が外部のコンテキスト(情報)にアクセスする方法を標準化するためのオープンなプロトコルです。MCPはLLMと多様なデータソースやツールとの連携を標準化するとっても便利なプロトコルです。

これを使っていろんなサービスを連携させることができ、実際にたくさんのMPCサーバーが提供されています。この記事では、「使うのではなく、MCPサーバーをGo言語で作りたい」という方に向けた記事になります。

Go言語の対応状況

公式のドキュメントを見ると、Python、Node、Java、Kotlin、C#でMCPサーバーを作るサンプルはありますが、残念ながらGo言語については書かれていません。

とりあえず、検索すると以下のライブラリがGithubにアップされていました。

https://github.com/mark3labs/mcp-go

他のGo向けのmcpのパッケージがありましたが、スター(★)が多かったのでこれを選びました。

今回使うライブラリ

今回使うライブラリはmcp-goというモデル コンテキスト プロトコル (MCP) の Go 実装です。ドキュメントはまだ整備されていない感じですがサンプルやexamplesのフォルダを眺めながらコードを作成していきました。

ちなみに、2025/03/21に公開されていたZennの記事のサンプルコードはエラーによりビルドできなかったので、ライブラリは活発に書き換えられている感じかもしれません。

Zennの記事:
  「GoのModel Context Protocol (MCP)の開発フレームワークmcp-goを使ってみる

もしかしたら、ここで作ったプログラムもライブラリの変更により動作しなくなるかも。とりあえず、バージョン指定の入ったgo.modを含めたコードを以下に置いておきます。

https://github.com/aruaru0/finance_calc_go

記事作成後も機能追加やコード修正を行なっているので、この記事とコードが異なる可能性があります。

MCPサーバーを作ってみる

作成するMCPサーバーの機能

とりあえず、金融電卓を作ってみます。今回は、ファイナンシャル・プランニング使う6つの係数を使って計算する機能を実装します。

  • 終価係数
    現金X円が、年利r%でN年複利運用した場合にいくらになるかを計算する係数
  • 現価係数
    N年後にX円を準備したいとき、年利r%で複利運用した場合に元本はいくら必要かを計算する係数
  • 年金終価係数
    年利r%の複利運用で毎年X円積み立てるとN年後にいくらになるかを計算する係数
  • 年金現価係数
    N年間、毎年X円を受け取りたい時に、元本はいくらあれば良いかを計算する係数。なお、運用利率はr%とする
  • 資本回収係数
    X万円を、運用利益r%で運用しながらN年間にわたって取り崩す場合、毎年いくら受け取れるかを計算する係数。X万円のローンを金利r%でN年間で返済する場合に、毎年いくら返済すれば良いかという計算にも使えます
  • 減債基金係数
    年利r%で運用してN年後にX万円ためるには、毎年いくら積み立てれば良いかを計算する係数

今回はこの2つだけ実装します。係数についてはこちらの記事を参考にしてください。

コード

以下、コードです。

mcp-goのexamples等をみながら試行錯誤で作成しました。

実装のポイントは以下のようになると思います。

LLMにツールを知らせる部分
  • Descriptionで何のツールかを記述する(今回は英語で書いています)
  • 各パラメータについても、必須かどうかと、パラメータの説明を記述する
LLMから受けっとたパラメータを解析する部分
  • financeHandlerでパラメータを受け取って、処理を行う
  • LLMへの返答は、少し無駄があってもLLM側が解析してくれるので問題なさそう
  • 係数の計算は、デバッグしやすくするため別に関数定義
package main

import (
	"context"
	"fmt"
	"math"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

// Define constants for financial calculation types
const (
	FutureValueFactor           = "Future Value Factor"
	PresentValueFactor          = "Present Value Factor"
	FutureValueOfAnnuityFactor  = "Future Value of Annuity Factor"
	PresentValueOfAnnuityFactor = "Present Value of Annuity Factor"
	SinkingFundFactor           = "Sinking Fund Factor"
	CapitalRecoveryFactor       = "Capital Recovery Factor"
)

// Define a slice of available financial calculation operations
var financialOperations = []string{
	FutureValueFactor,
	PresentValueFactor,
	FutureValueOfAnnuityFactor,
	PresentValueOfAnnuityFactor,
	SinkingFundFactor,
	CapitalRecoveryFactor,
}

// main is the entry point for the Finance Calculator MCP server.
//
// The Finance Calculator performs the following financial calculations:
// 1. Future Value Factor: Calculates the future value of a present sum after a period of compound interest.
// 2. Present Value Factor: Calculates the present value of a future sum.
// 3. Future Value of Annuity Factor: Calculates the future value of a series of equal payments (annuity).
// 4. Present Value of Annuity Factor: Calculates the present value of a series of equal payments (annuity).
// 5. Sinking Fund Factor: Calculates the annual deposit required to reach a specific future sum.
// 6. Capital Recovery Factor: Calculates the payment required to recover an initial investment.
//
// The server is started with standard input/output.
func main() {
	// Create a new MCP server
	s := server.NewMCPServer(
		"Finance Calculator",
		"1.0.0",
		server.WithResourceCapabilities(true, true), // Options used for Resource features
		server.WithLogging(),
	)

	// Define the interface for the financial calculator tool
	calculatorTool := mcp.NewTool("financial_calculator",
		mcp.WithDescription("Performs financial calculations."),
		mcp.WithString("operation",
			mcp.Required(),
			mcp.Description(`The financial calculation to perform. Select one of the following:
- Future Value Factor: Calculates the future value of a present sum after a period of compound interest.
- Present Value Factor: Calculates the present value of a future sum.
- Future Value of Annuity Factor: Calculates the future value of a series of equal payments (annuity).
- Present Value of Annuity Factor: Calculates the present value of a series of equal payments (annuity).
- Sinking Fund Factor: Calculates the annual deposit required to reach a specific future sum.
- Capital Recovery Factor: Calculates the payment required to recover an initial investment.`),
			mcp.Enum(financialOperations...),
		),
		mcp.WithNumber("r",
			mcp.Required(),
			mcp.Description("interest rate(0.0 ~ 1.0)"),
		),
		mcp.WithNumber("n",
			mcp.Required(),
			mcp.Description("number of periods(years)"),
		),
		mcp.WithNumber("amount",
			mcp.Required(),
			mcp.Description("amount"),
		),
	)

	// Add a tool handler
	s.AddTool(calculatorTool, financeHandler)

	// Start the server with standard I/O
	if err := server.ServeStdio(s); err != nil {
		fmt.Printf("Server error: %v\n", err)
	}
}

// calculateFinancialRate calculates various financial rates based on the given operation.
// Parameters:
//   - op: The type of financial calculation to perform. Supported operations include:
//     "Future Value Factor", "Present Value Factor", "Future Value of Annuity Factor",
//     "Present Value of Annuity Factor", "Sinking Fund Factor", and "Capital Recovery Factor".
//   - r: The interest rate expressed as a decimal (e.g., 0.05 for 5%).
//   - n: The number of periods (e.g., years) over which the calculation is performed.
//
// Returns:
// - The calculated rate as a float64 based on the specified operation.
// - An error if the provided operation is unknown.
func calculateFinancialRate(op string, r, n float64) (float64, error) {
	var rate float64
	// Branch calculation based on operation type
	switch op {
	case FutureValueFactor:
		rate = math.Pow(1+r, n)
	case PresentValueFactor:
		rate = math.Pow(1+r, -n)
	case FutureValueOfAnnuityFactor:
		rate = (math.Pow(1+r, n) - 1) / r
	case PresentValueOfAnnuityFactor:
		rate = (1 - math.Pow(1+r, -n)) / r
	case SinkingFundFactor:
		rate = r / (math.Pow(1+r, n) - 1)
	case CapitalRecoveryFactor:
		rate = (r * math.Pow(1+r, n)) / (math.Pow(1+r, n) - 1)
	default:
		return 0, fmt.Errorf("unknown operation: %s", op)
	}
	return rate, nil
}

// financeHandler is the handler for the financial tool.
// It takes four parameters:
// - operation: The type of financial calculation to perform.
// - r: The interest rate expressed as a decimal (e.g., 0.05 for 5%).
// - n: The number of periods (e.g., years) over which the calculation is performed.
// - amount: The amount on which the calculation is based.
// It returns the calculated financial rate and the result as an integer.
func financeHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	// Get operation from arguments
	op, ok := request.GetArguments()["operation"].(string)
	if !ok {
		return nil, fmt.Errorf("missing operation")
	}

	// Get interest rate from arguments
	r, ok := request.GetArguments()["r"].(float64)
	if !ok {
		return nil, fmt.Errorf("missing r")
	}

	// If the interest rate is greater than 1, divide by 10
	if r > 1 {
		r /= 10.0
	}

	// Get number of periods from arguments
	n, ok := request.GetArguments()["n"].(float64)
	if !ok {
		return nil, fmt.Errorf("missing n")
	}

	// Get amount from arguments
	amount, ok := request.GetArguments()["amount"].(float64)
	if !ok {
		return nil, fmt.Errorf("missing amount")
	}

	// Calculate financial rate
	rate, err := calculateFinancialRate(op, r, n)
	if err != nil {
		return nil, err
	}

	// Calculate result
	result := amount * rate

	// Format and return the calculation result
	return mcp.NewToolResultText(fmt.Sprintf("rate = %f n = %f amount = %f result rate = %f result is %d", r, n, amount, rate, int(result))), nil
}

上記のプログラムをビルドします。以下のコマンドを行うことでビルドできると思います。

go mod init
go mod tidy
go build

LMStuidoに登録して使ってみる

登録方法

LMStudioを立ち上げて、左側のタブを開いてProgramを選択し、InstallをクリックしてEdit mcp.jsonでjsonファイルを開きます。

mcp.jsonが開くので、ここに以下を追加します。フォルダは、作成したGo作成した実行プログラムへのパスをフルパスで指定します。

{
  "mcpServers": {
    "finance calc": {
      "command": "/フォルダ/作成した実行プログラム名",
      "args": []
    }
  }
}

保存すると、右のタブに登録されますので、ONにします。

これで利用準備が整いました。

いざ、実行

ツールに対応している(ツールマークのあるLLM)をロードして、ツールが実行されるか試してみます。

今回は、qwen3-30b-a3b-mlxを使ってみました(実行環境はMacです)。

モデル名の横にある工具のアイコン(青いアイコン)がツール対応を示しています。

質問No.1

とりあえず、以下のような質問をします。

/no_think

年率3%で20年後に2000万円を受け取りたい場合、いくらずつ積み立てれば良いか?

/no_thinkは、推論モードをOFFにするQwen3の指示です。

すると、ツールを使用するかどうか尋ねてきますので、許可します。

ちゃんとツール(Sinking Fund Factor)を使って回答していることがわかります。

LMStudioを一旦終了させないと、Goのソースコードを書き換えても反映させる、デバッグに少し苦労しました。修正するときはLMStudioも終了した方が良いです。

途中からgemini climcpサーバーを登録して、デバッグしました。個人的にはコードのデバッグはvscodeのターミナルから実行できるコマンドラインツールの方が楽でした。

質問No.2

続けて、次のように質問します。

1000万借りて金利4%で10年で返済する場合、毎年いくら返せば良い?

今度は、ツールのCapital Recovery Factorを呼び出して回答してきました。

高度な質問例

では、もう少し難しめの質問をしてみます。

/no_think
5年後に定価が400万円の車を購入しようと考えています。5年間金利1%で一定額を積み立てて購入するのと、金利2.9%の自動車ローンで一定額を支払って購入するのでは総支払い額はいくら違う?

このような質問に対して適切にツールを使ってくれると嬉しいです。回答は以下のようになりました。

Screenshot

出力結果を見ると、積み立ての場合はSinking Fund Factorを、ローンの場合はCapital Recovery Factorをそれぞれ使っていることがわかります。このように、必要な計算がある場合に自動で呼び出してくれて便利です。

プロンプトにより呼び出さなかったり、間違った係数を使ったりしていました。Qwen3-30B-A3Bでも、2回目に実行したときは間違った係数を使っていました。ミスは、特に小さいモデルで多かったです。MCPを使う場合は大きいモデルがよいと思います。

あと、Descriptionも工夫すべきですね。

まとめ

MCPサーバーをGo言語で作成する方法について解説しました。Goでツールを作る人は少ないかと思いますが、参考になれば幸いです。

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT ME
ある/Aru
ある/Aru
IT&機械学習エンジニア/ファイナンシャルプランナー(CFP®)
専門分野は並列処理・画像処理・機械学習・ディープラーニング。プログラミング言語はC, C++, Go, Pythonを中心として色々利用。現在は、Kaggle, 競プロなどをしながら悠々自適に活動中
記事URLをコピーしました