MCP Server Go について
MCP Server Goは、MCPサーバーを構築するためのGo実装です。LLMアプリケーションとデータやツールを連携させる開発者向けで、ツール、リソース、プロンプトの高水準APIを備えています。高度な機能の一部は開発中です。
主な機能
- 01高水準のGoサーバーAPI
- 02ツールの登録
- 03静的・動的リソース
- 04再利用可能なプロンプト定義
- 05プロトコルと接続の管理
活用シーン
- 01GoでMCPサーバーを構築
- 02アプリケーションデータをリソースとして公開
- 03LLMアプリケーションに操作ツールを提供
- 04再利用可能な対話プロンプトを定義
MCP 対応
このライブラリはMCPサーバー側を実装し、ツール、リソース、プロンプトをMCPクライアントに公開します。コア仕様への対応を目指しており、高度な機能の一部は開発中です。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
MCP Server Go
ヒント
Go による Model Context Protocol(MCP)の実装で、LLM アプリケーションと外部のデータソースやツールをシームレスに統合できます。
package main
import (
"context"
"fmt"
"github.com/shaneholloman/mcp-server-go/mcp"
"github.com/shaneholloman/mcp-server-go/server"
)
func main() {
// Create MCP server
s := server.NewMCPServer(
"Demo",
"1.0.0",
)
// Add tool
tool := mcp.NewTool("hello_world",
mcp.WithDescription("Say hello to someone"),
mcp.WithString("name",
mcp.Required(),
mcp.Description("Name of the person to greet"),
),
)
// Add tool handler
s.AddTool(tool, helloHandler)
// Start the stdio server
if err := server.ServeStdio(s); err != nil {
fmt.Printf("Server error: %v\n", err)
}
}
func helloHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
name, ok := request.Params.Arguments["name"].(string)
if !ok {
return mcp.NewToolResultError("name must be a string"), nil
}
return mcp.NewToolResultText(fmt.Sprintf("Hello, %s!", name)), nil
}
これだけです!
MCP Go が複雑なプロトコルの詳細とサーバー管理をすべて処理するため、優れたツールの開発に専念できます。高水準で使いやすいことを目指しています。
主な機能
- 高速:高水準のインターフェースにより、コード量を減らし、開発を高速化できます
- シンプル:最小限の定型コードで MCP サーバーを構築できます
- 完全*:MCP Go は、MCP のコア仕様を完全に実装することを目指しています
重要
MCP Go は、MCP 仕様自体と同様、現在も活発に開発されています。コア機能は動作しますが、一部の高度な機能はまだ開発中です。
目次
インストール
go get github.com/shaneholloman/mcp-server-go
クイックスタート
計算ツールといくつかのデータを公開する、シンプルな MCP サーバーを作成してみましょう。
package main
import (
"context"
"fmt"
"github.com/shaneholloman/mcp-server-go/mcp"
"github.com/shaneholloman/mcp-server-go/server"
)
func main() {
// Create a new MCP server
s := server.NewMCPServer(
"Calculator Demo",
"1.0.0",
server.WithResourceCapabilities(true, true),
server.WithLogging(),
)
// Add a calculator tool
calculatorTool := mcp.NewTool("calculate",
mcp.WithDescription("Perform basic arithmetic operations"),
mcp.WithString("operation",
mcp.Required(),
mcp.Description("The operation to perform (add, subtract, multiply, divide)"),
mcp.Enum("add", "subtract", "multiply", "divide"),
),
mcp.WithNumber("x",
mcp.Required(),
mcp.Description("First number"),
),
mcp.WithNumber("y",
mcp.Required(),
mcp.Description("Second number"),
),
)
// Add the calculator handler
s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
op := request.Params.Arguments["operation"].(string)
x := request.Params.Arguments["x"].(float64)
y := request.Params.Arguments["y"].(float64)
var result float64
switch op {
case "add":
result = x + y
case "subtract":
result = x - y
case "multiply":
result = x * y
case "divide":
if y == 0 {
return mcp.NewToolResultError("Cannot divide by zero"), nil
}
result = x / y
}
return mcp.NewToolResultText(fmt.Sprintf("%.2f", result)), nil
})
// Start the server
if err := server.ServeStdio(s); err != nil {
fmt.Printf("Server error: %v\n", err)
}
}
MCP とは?
Model Context Protocol(MCP)を使うと、LLM アプリケーションにデータや機能を安全かつ標準化された方法で公開するサーバーを構築できます。LLM とのやり取りに特化した Web API のようなものだと考えてください。MCP サーバーでは、次のことができます。
- リソースを通じてデータを公開する(GET エンドポイントのようなもので、LLM のコンテキストに情報を読み込むために使用します)
- ツールを通じて機能を提供する(POST エンドポイントのようなもので、コードを実行したり、それ以外の副作用を発生させたりするために使用します)
- プロンプトを通じて対話パターンを定義する(LLM とのやり取りに再利用できるテンプレートです)
- その他にもさまざまなことができます!
コアコンセプト
サーバー
サーバーの例を表示
サーバーは MCP プロトコルとの中心的なインターフェースです。接続管理、プロトコルへの準拠、メッセージのルーティングを処理します。
// Create a basic server
s := server.NewMCPServer(
"My Server", // Server name
"1.0.0", // Version
)
// Start the server using stdio
if err := server.ServeStdio(s); err != nil {
log.Fatalf("Server error: %v", err)
}
リソース
リソースの例を表示
リソースは、LLM にデータを公開するためのものです。ファイル、API の応答、データベースクエリ、システム情報など、さまざまなものを扱えます。リソースには次の種類があります。- 静的(固定 URI)
- 動的(URI テンプレートを使用)
静的リソースの簡単な例を紹介します。
// Static resource example - exposing a README file
resource := mcp.NewResource(
"docs://readme",
"Project README",
mcp.WithResourceDescription("The project's README file"),
mcp.WithMIMEType("text/markdown"),
mcp.WithAnnotations([]mcp.Role{mcp.RoleAssistant}, 0.8),
)
// Add resource with its handler
s.AddResource(resource, func(ctx context.Context, request mcp.ReadResourceRequest) ([]interface{}, error) {
content, err := os.ReadFile("README.md")
if err != nil {
return nil, err
}
return []interface{}{
mcp.TextResourceContents{
ResourceContents: mcp.ResourceContents{
URI: "docs://readme",
MIMEType: "text/markdown",
},
Text: string(content),
},
}, nil
})
テンプレートを使った動的リソースの例を紹介します。
// Dynamic resource example - user profiles by ID
template := mcp.NewResourceTemplate(
"users://{id}/profile",
"User Profile",
mcp.WithTemplateDescription("Returns user profile information"),
mcp.WithTemplateMIMEType("application/json"),
mcp.WithTemplateAnnotations([]mcp.Role{mcp.RoleAssistant, mcp.RoleUser}, 0.5),
)
// Add template with its handler
s.AddResourceTemplate(template, func(ctx context.Context, request mcp.ReadResourceRequest) ([]interface{}, error) {
userID := request.Params.URI // Extract ID from the full URI
profile, err := getUserProfile(userID) // Your DB/API call here
if err != nil {
return nil, err
}
return []interface{}{
mcp.TextResourceContents{
ResourceContents: mcp.ResourceContents{
URI: fmt.Sprintf("users://%s/profile", userID),
MIMEType: "application/json",
},
Text: profile,
},
}, nil
})
これらの例はシンプルですが、コアコンセプトを示しています。複数のコンテンツの提供、アノテーションの使用、データベースや外部 API との統合など、リソースをさらに高度なものにすることもできます。
ツール
ツールの例を表示
ツールを使うと、LLM がサーバーを通じてアクションを実行できます。リソースとは異なり、ツールは計算を実行し、副作用を発生させることを想定しています。REST API の POST エンドポイントに似ています。
簡単な計算の例:
calculatorTool := mcp.NewTool("calculate",
mcp.WithDescription("Perform basic arithmetic calculations"),
mcp.WithString("operation",
mcp.Required(),
mcp.Description("The arithmetic operation to perform"),
mcp.Enum("add", "subtract", "multiply", "divide"),
),
mcp.WithNumber("x",
mcp.Required(),
mcp.Description("First number"),
),
mcp.WithNumber("y",
mcp.Required(),
mcp.Description("Second number"),
),
)
s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
op := request.Params.Arguments["operation"].(string)
x := request.Params.Arguments["x"].(float64)
y := request.Params.Arguments["y"].(float64)
var result float64
switch op {
case "add":
result = x + y
case "subtract":
result = x - y
case "multiply":
result = x * y
case "divide":
if y == 0 {
return mcp.NewToolResultError("Division by zero is not allowed"), nil
}
result = x / y
}
return mcp.FormatNumberResult(result), nil
})
HTTP リクエストの例:
httpTool := mcp.NewTool("http_request",
mcp.WithDescription("Make HTTP requests to external APIs"),
mcp.WithString("method",
mcp.Required(),
mcp.Description("HTTP method to use"),
mcp.Enum("GET", "POST", "PUT", "DELETE"),
),
mcp.WithString("url",
mcp.Required(),
mcp.Description("URL to send the request to"),
mcp.Pattern("^https?://.*"),
),
mcp.WithString("body",
mcp.Description("Request body (for POST/PUT)"),
),
)
s.AddTool(httpTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
method := request.Params.Arguments["method"].(string)
url := request.Params.Arguments["url"].(string)
body := ""
if b, ok := request.Params.Arguments["body"].(string); ok {
body = b
}
// Create and send request
var req *http.Request
var err error
if body != "" {
req, err = http.NewRequest(method, url, strings.NewReader(body))
} else {
req, err = http.NewRequest(method, url, nil)
}
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("Failed to create request: %v", err)), nil
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("Request failed: %v", err)), nil
}
defer resp.Body.Close()
// Return response
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("Failed to read response: %v", err)), nil
}
return mcp.NewToolResultText(fmt.Sprintf("Status: %d\nBody: %s", resp.StatusCode, string(respBody))), nil
})
ツールは、あらゆる種類の計算や副作用に利用できます。
- データベースクエリ
- ファイル操作
- 外部 API 呼び出し
- 計算
- システム操作
各ツールには、次の要件があります。
- 明確な説明がある
- 入力を検証する
- エラーを適切に処理する
- 構造化された応答を返す
- 適切な結果型を使用する
プロンプトの例を表示
プロンプトは、LLM がサーバーと効果的にやり取りするための再利用可能なテンプレートです。サーバーに組み込まれた「ベストプラクティス」のようなものです。以下に例を示します。
// Simple greeting prompt
s.AddPrompt(mcp.NewPrompt("greeting",
mcp.WithPromptDescription("A friendly greeting prompt"),
mcp.WithArgument("name",
mcp.ArgumentDescription("Name of the person to greet"),
),
), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
name := request.Params.Arguments["name"].(string)
if name == "" {
name = "friend"
}
return mcp.NewGetPromptResult(
"A friendly greeting",
[]mcp.PromptMessage{
mcp.NewPromptMessage(
mcp.RoleAssistant,
mcp.NewTextContent(fmt.Sprintf("Hello, %s! How can I help you today?", name)),
),
},
), nil
})
// Code review prompt with embedded resource
s.AddPrompt(mcp.NewPrompt("code_review",
mcp.WithPromptDescription("Code review assistance"),
mcp.WithArgument("pr_number",
mcp.ArgumentDescription("Pull request number to review"),
mcp.RequiredArgument(),
),
), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
prNumber := request.Params.Arguments["pr_number"].(string)
if prNumber == "" {
return nil, fmt.Errorf("pr_number is required")
}
return mcp.NewGetPromptResult(
"Code review assistance",
[]mcp.PromptMessage{
mcp.NewPromptMessage(
mcp.RoleSystem,
mcp.NewTextContent("You are a helpful code reviewer. Review the changes and provide constructive feedback."),
),
mcp.NewPromptMessage(
mcp.RoleAssistant,
mcp.NewEmbeddedResource(mcp.ResourceContents{
URI: fmt.Sprintf("git://pulls/%s/diff", prNumber),
MIMEType: "text/x-diff",
}),
),
},
), nil
})
// Database query builder prompt
s.AddPrompt(mcp.NewPrompt("query_builder",
mcp.WithPromptDescription("SQL query builder assistance"),
mcp.WithArgument("table",
mcp.ArgumentDescription("Name of the table to query"),
mcp.RequiredArgument(),
),
), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
tableName := request.Params.Arguments["table"].(string)
if tableName == "" {
return nil, fmt.Errorf("table name is required")
}
return mcp.NewGetPromptResult(
"SQL query builder assistance",
[]mcp.PromptMessage{
mcp.NewPromptMessage(
mcp.RoleSystem,
mcp.NewTextContent("You are a SQL expert. Help construct efficient and safe queries."),
),
mcp.NewPromptMessage(
mcp.RoleAssistant,
mcp.NewEmbeddedResource(mcp.ResourceContents{
URI: fmt.Sprintf("db://schema/%s", tableName),
MIMEType: "application/json",
}),
),
},
), nil
})
プロンプトには、次の内容を含めることができます。
- システム指示
- 必須の引数
- 埋め込みリソース
- 複数のメッセージ
- さまざまなコンテンツタイプ(テキスト、画像など)
- カスタム URI スキーム
例
例については、examples/ ディレクトリを参照してください。
コントリビューション
開発者ガイドを開く
前提条件
Go バージョン >= 1.23
開発用インストール
このリポジトリをフォークしてから、クローンします。
git clone https://github.com/shaneholloman/mcp-server-go.git
cd mcp-server-go
テスト
新しい機能を追加した場合は、必ずテストしてください。テストはシンプルで独立したものにし、複雑なパターンを固定化するのではなく、変更を想定するようにしてください。
ルートディレクトリからテストを実行します。
go test -v './...'
プルリクエストの作成
リポジトリをフォークして、新しいブランチを作成します。
git checkout -b my-branch
変更を加えて、コミットします。
git add . && git commit -m "My changes"
変更をフォークしたリポジトリにプッシュします。
git push origin my-branch
ご不明な点があれば、GitHub のイシューまたはディスカッションでお気軽にお問い合わせください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。