mcpField
M
MCP Server Go

MCP Server Go

ローカル
github.com/shaneholloman開発ツール170 週間前に更新

MCP Server Go について

MCP Server Goは、MCPサーバーを構築するためのGo実装です。LLMアプリケーションとデータやツールを連携させる開発者向けで、ツール、リソース、プロンプトの高水準APIを備えています。高度な機能の一部は開発中です。

主な機能

  1. 01高水準のGoサーバーAPI
  2. 02ツールの登録
  3. 03静的・動的リソース
  4. 04再利用可能なプロンプト定義
  5. 05プロトコルと接続の管理

活用シーン

  1. 01GoでMCPサーバーを構築
  2. 02アプリケーションデータをリソースとして公開
  3. 03LLMアプリケーションに操作ツールを提供
  4. 04再利用可能な対話プロンプトを定義

MCP 対応

このライブラリはMCPサーバー側を実装し、ツール、リソース、プロンプトをMCPクライアントに公開します。コア仕様への対応を目指しており、高度な機能の一部は開発中です。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

インストール方法は未掲載です

このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。

リポジトリ

ツール

ツール一覧はまだ取得されていません

ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。

詳細

MCP Server Go

Go Report Card GoDoc

ヒント

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 のイシューまたはディスカッションでお気軽にお問い合わせください。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。