mcp

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2025 License: MIT Imports: 12 Imported by: 4

README

⚡ go-mcp

A type‑safe, intuitive Go SDK for MCP server development

🤔 What is go‑mcp?✨ Features🏁 Quick Start🔍 Examples✅ Supported Features🤝 Contributing


🤔 What is go‑mcp?

go‑mcp is a Go SDK for building MCP (Model Context Protocol) servers with ease and confidence. It provides a type‑safe, intuitive interface that makes server development a breeze.


✨ Features

  • 🔒 Type‑Safe – Code generation ensures your tools and prompt parameters are statically typed, so errors are caught at compile time instead of at runtime.
  • 🧩 Simple & Intuitive API – A natural, idiomatic Go interface that lets you build servers quickly without a steep learning curve.
  • 🔌 Developer‑Friendly – Designed with API ergonomics in mind, making it approachable.

🏁 Quick Start

Creating an MCP server with go‑mcp is straightforward!

Directory structure

Below is an example directory structure for a temperature‑conversion MCP server:

.
├── cmd
│   ├── mcpgen
│   │   └── main.go
│   └── temperature
│       └── main.go
├── mcp.gen.go
└── temperature.go
1. Define the MCP server

First, create cmd/mcpgen/main.go for code generation. Running this file will automatically generate the necessary code.

package main

import (
    "log"
    "os"
    "path/filepath"

    "github.com/ktr0731/go-mcp/codegen"
)

func main() {
    // Create output directory
    outDir := "."
    if err := os.MkdirAll(outDir, 0o755); err != nil {
        log.Fatalf("failed to create output directory: %v", err)
    }

    // Create output file
    f, err := os.Create(filepath.Join(outDir, "mcp.gen.go"))
    if err != nil {
        log.Fatalf("failed to create file: %v", err)
    }
    defer f.Close()

    // Server definition
    def := &codegen.ServerDefinition{
        Capabilities: codegen.ServerCapabilities{
            Tools:   &codegen.ToolCapability{},
            Logging: &codegen.LoggingCapability{},
        },
        Implementation: codegen.Implementation{
            Name:    "Temperature MCP Server",
            Version: "1.0.0",
        },
        // Tool definitions (declared with Go structs)
        Tools: []codegen.Tool{
            {
                Name:        "convert_temperature",
                Description: "Convert temperature between Celsius and Fahrenheit",
                InputSchema: struct {
                    Temperature float64 `json:"temperature" jsonschema:"description=Temperature value to convert"`
                    FromUnit    string  `json:"from_unit"  jsonschema:"description=Source temperature unit,enum=celsius,enum=fahrenheit"`
                    ToUnit      string  `json:"to_unit"    jsonschema:"description=Target temperature unit,enum=celsius,enum=fahrenheit"`
                }{},
            },
        },
    }

    // Generate code
    if err := codegen.Generate(f, def, "temperature"); err != nil {
        log.Fatalf("failed to generate code: %v", err)
    }
}

Generate the code:

go run ./cmd/mcpgen
2. Implement the MCP server

Next, implement the server logic in cmd/temperature/main.go:

package main

import (
    "context"
    "fmt"
    "log"
    "math"

    mcp "github.com/ktr0731/go-mcp"
    "golang.org/x/exp/jsonrpc2"
)

type toolHandler struct{}

func (h *toolHandler) HandleToolConvertTemperature(ctx context.Context, req *ToolConvertTemperatureRequest) (*mcp.CallToolResult, error) {
    temperature := req.Temperature
    fromUnit := req.FromUnit
    toUnit := req.ToUnit

    var result float64
    switch {
    case fromUnit == ConvertTemperatureFromUnitTypeCelsius && toUnit == ConvertTemperatureToUnitTypeFahrenheit:
        // °C → °F: (C × 9/5) + 32
        result = (temperature*9/5 + 32)
    case fromUnit == ConvertTemperatureFromUnitTypeFahrenheit && toUnit == ConvertTemperatureToUnitTypeCelsius:
        // °F → °C: (F − 32) × 5/9
        result = (temperature - 32) * 5 / 9
    case fromUnit == toUnit:
        result = temperature
    default:
        return nil, fmt.Errorf("unsupported conversion: %s to %s", fromUnit, toUnit)
    }

    // Round to two decimal places
    result = math.Round(result*100) / 100

    resultText := fmt.Sprintf("%.2f %s = %.2f %s", temperature, fromUnit, result, toUnit)

    return &mcp.CallToolResult{
        Content: []mcp.CallToolContent{
            mcp.TextContent{Text: resultText},
        },
    }, nil
}

func main() {
    handler := NewHandler(&toolHandler{})

    ctx, listener, binder := mcp.NewStdioTransport(context.Background(), handler, nil)
    srv, err := jsonrpc2.Serve(ctx, listener, binder)
    if err != nil {
        log.Fatalf("failed to serve: %v", err)
    }

    srv.Wait()
}

Run the server:

go run ./cmd/temperature

🔍 Examples

See complete examples in the examples directory and the API documentation.


✅ Supported Features

  • Ping
  • Tools
  • Prompts
  • Prompts, Tools, Resources, Resource Templates
  • Resource subscription
  • Resource update notification
  • Logging
  • Completion
  • Cancellation

🚧 Under Development

  • Batching (JSON‑RPC 2.0)
  • Streamable HTTP transport
  • Progress notification

🚫 Not Planned

  • Dynamic prompt and tool changes

    Go is not well‑suited for dynamic tool additions. Adding tools dynamically requires constructing tool definitions, JSON Schema, and handlers at runtime. While generated code remains type‑safe, dynamically added components do not, forcing heavy use of any and type assertions and harming interface consistency. We delegate these use cases to SDKs in languages better suited for dynamic changes, such as TypeScript.

    Most currently implemented MCP servers use static definitions only, and dynamic changes do not seem to be a primary use case yet.


🤝 Contributing

Contributions are welcome! Feel free to submit a pull request.


📄 License

This project is licensed under the MIT License – see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Logger

func Logger(ctx context.Context, name string) *slog.Logger

Logger creates a new logger with the given name. Note that this logger is for communication with the client, not for internal logging. The logged messages are sent as notifications to the client.

See https://modelcontextprotocol.io/specification/2025-03-26/server/utilities/logging#logging

func NextCursor

func NextCursor(ctx context.Context) (string, bool)

NextCursor returns the next cursor from the context. If there is no next cursor or the API doesn't support pagination, it returns false.

func SetLogWriterToContext

func SetLogWriterToContext(ctx context.Context, w io.Writer) context.Context

SetLogWriterToContext sets the log writer to the context. This function is intended to be called by functions that creates a new transport.

Types

type Annotations

type Annotations struct {
	// Audience describes who the intended customer of this object or data is.
	// It can include multiple entries to indicate content useful for multiple audiences (e.g., ["user", "assistant"]).
	Audience []Role `json:"audience,omitzero"`
	// Priority describes how important this data is for operating the server.
	// A value of 1 means "most important," and indicates that the data is
	// effectively required, while 0 means "least important," and indicates that
	// the data is entirely optional.
	Priority *float64 `json:"priority,omitzero"` // 0: optional, 1: required
}

Annotations represents optional annotations for the client. Annotations are used by the client to inform how objects are used or displayed.

type AudioContent

type AudioContent struct {
	// Data is the audio data.
	Data io.Reader
	// MimeType is the MIME type of the audio. Different providers may support different audio types.
	MimeType string

	// Annotations are optional annotations for the client.
	Annotations *Annotations
}

AudioContent represents audio data.

func (AudioContent) MarshalJSON

func (a AudioContent) MarshalJSON() ([]byte, error)

type BlobResourceContent

type BlobResourceContent struct {
	// URI is the URI of this resource.
	URI string
	// MimeType is the MIME type of this resource, if known.
	MimeType string
	// Blob is the binary data of the item.
	Blob io.Reader
}

BlobResourceContent represents binary resource content.

func (BlobResourceContent) MarshalJSON

func (b BlobResourceContent) MarshalJSON() ([]byte, error)

type CallToolContent

type CallToolContent interface {
	// contains filtered or unexported methods
}

CallToolContent is the interface for content that can be returned by a tool call. TextContent and EmbeddedResource are the only valid types.

type CallToolResult

type CallToolResult struct {
	// Content is the content of the tool call.
	// TextContent and EmbeddedResource are the only valid types.
	Content []CallToolContent `json:"content"`
	// IsError indicates whether the tool call ended in an error.
	// If not set, this is assumed to be false (the call was successful).
	IsError bool `json:"isError,omitzero"`
}

CallToolResult represents the server's response to a tool call. Any errors that originate from the tool SHOULD be reported inside the result object, with IsError set to true, NOT as an MCP protocol-level error response. Otherwise, the LLM would not be able to see that an error occurred and self-correct.

type CompleteRequestParams

type CompleteRequestParams struct {
	// Ref is a reference to a prompt or resource
	Ref Reference `json:"ref"`
	// Argument contains the argument's information
	Argument CompletionArgument `json:"argument"`
}

CompleteRequestParams is a request from the client to the server, to ask for completion options.

type CompleteResult

type CompleteResult struct {
	// Values is an array of completion values. Must not exceed 100 items.
	Values []string `json:"values"`
	// Total is the total number of completion options available. This can exceed the number of values actually sent in the response.
	Total int `json:"total,omitzero"`
	// HasMore indicates whether there are additional completion options beyond those provided in the current response,
	// even if the exact total is unknown.
	HasMore bool `json:"hasMore,omitzero"`
}

CompleteResult represents the completion options for argument autocompletion.

type CompletionArgument

type CompletionArgument struct {
	// Name is the name of the argument
	Name string `json:"name"`
	// Value is the value of the argument to use for completion matching.
	Value string `json:"value"`
}

CompletionArgument represents an argument for completion.

type CompletionReferenceType

type CompletionReferenceType string

CompletionReferenceType represents the type of a completion reference.

const (
	// CompletionReferenceTypePrompt identifies a prompt.
	CompletionReferenceTypePrompt CompletionReferenceType = "ref/prompt"
	// CompletionReferenceTypeResource is a reference to a resource or resource template definition.
	CompletionReferenceTypeResource CompletionReferenceType = "ref/resource"
)

type EmbeddedResource

type EmbeddedResource struct {
	// Resource is the resource content to embed.
	Resource ResourceContent `json:"resource"`

	// Annotations are optional annotations for the client.
	Annotations *Annotations `json:"annotations,omitzero"`
}

EmbeddedResource represents the contents of a resource, embedded into a prompt or tool call result. EmbeddedResource is rendered by the client in a way that best serves the benefit of the LLM and/or the user.

type GetPromptResult

type GetPromptResult struct {
	// Description is an optional description for the prompt.
	Description string `json:"description,omitzero"`
	// Arguments is a list of arguments to use for templating the prompt.
	Messages []PromptMessage `json:"messages"`
}

GetPromptResult represents the server's response to a prompts/get request from the client.

type Handler

type Handler struct {
	Capabilities   protocol.ServerCapabilities
	Implementation protocol.Implementation

	Prompts       []protocol.Prompt
	PromptHandler serverHandler[protocol.GetPromptRequestParams]

	Tools       []protocol.Tool
	ToolHandler serverHandler[protocol.CallToolRequestParams]

	ResourceHandler   ServerResourceHandler
	ResourceTemplates []ResourceTemplate

	CompletionHandler ServerCompletionHandler
	// contains filtered or unexported fields
}

Handler is the main handler for MCP server implementation. Note that exported fields are exported for accessing by generated code. Do not access/modify them directly.

func (*Handler) Handle

func (h *Handler) Handle(ctx context.Context, req *jsonrpc2.Request) (any, error)

Handle handles an incoming request.

func (*Handler) IsSubscribed

func (h *Handler) IsSubscribed(uri string) bool

IsSubscribed checks if the given resource is subscribed.

type ImageContent

type ImageContent struct {
	// Data is the image data.
	Data io.Reader
	// MimeType is the MIME type of the image. Different providers may support different image types.
	MimeType string

	// Annotations are optional annotations for the client.
	Annotations *Annotations
}

ImageContent represents image data.

func (ImageContent) MarshalJSON

func (i ImageContent) MarshalJSON() ([]byte, error)

type ListResourcesResult

type ListResourcesResult struct {
	// NextCursor is an opaque token representing the current pagination position.
	// If provided, the server should return results starting after this cursor.
	NextCursor string `json:"nextCursor,omitzero"`
	// Resources is a list of resources the server offers.
	Resources []Resource `json:"resources"`
}

ListResourcesResult represents the response for resources list. ListResourcesResult is a PaginatedResult that contains a list of resources the server offers.

type PromptMessage

type PromptMessage struct {
	// Role represents the role of the message sender/recipient.
	Role Role `json:"role"`
	// Content represents the content of the message.
	// TextContent, ImageContent, AudioContent, or EmbeddedResource.
	Content PromptMessageContent `json:"content"`
}

PromptMessage describes a message returned as part of a prompt. PromptMessage is similar to SamplingMessage, but also supports the embedding of resources from the MCP server.

type PromptMessageContent

type PromptMessageContent interface {
	// contains filtered or unexported methods
}

PromptMessageContent is the interface for content that can be included in a prompt message. TextContent, ImageContent, AudioContent, or EmbeddedResource.

type ReadResourceRequest

type ReadResourceRequest struct {
	// URI is the URI of the resource to read. The URI can use any protocol; it is up to the server how to interpret it.
	URI string `json:"uri"`
}

ReadResourceRequest represents a request to read a specific resource. ReadResourceRequest is sent from the client to the server, to read a specific resource URI.

type ReadResourceResult

type ReadResourceResult struct {
	// Contents is a list of contents of the resource.
	Contents []ResourceContent `json:"contents"`
}

ReadResourceResult represents the response for a resource read operation. ReadResourceResult is the server's response to a resources/read request from the client.

type Reference

type Reference struct {
	Type CompletionReferenceType `json:"type"`
	// Name is the name of the prompt or URI of the resource
	Name string `json:"name"`
}

Reference represents a reference to a completion item.

type Resource

type Resource struct {
	// URI is the URI of this resource.
	URI string `json:"uri"` // URI (e.g. file://...)
	// Name is a human-readable name for this resource.
	// This can be used by clients to populate UI elements.
	Name string `json:"name"`
	// Description is a description of what this resource represents.
	// This can be used by clients to improve the LLM's understanding of available resources.
	// It can be thought of like a "hint" to the model.
	Description string `json:"description,omitzero"`
	// MimeType is the MIME type of this resource, if known.
	MimeType string `json:"mimeType,omitzero"`
	// Size is the size of the raw resource content, if known.
	// This can be used by Hosts to display file sizes and estimate context window usage.
	Size int64 `json:"size,omitzero"`

	// Annotations are optional annotations for the client.
	Annotations *Annotations `json:"annotations,omitzero"`
}

Resource represents a resource handled by the server. Resource is a known resource that the server is capable of reading.

type ResourceContent

type ResourceContent interface {
	// contains filtered or unexported methods
}

ResourceContent is the interface for contents of a specific resource or sub-resource.

type ResourceTemplate

type ResourceTemplate struct {
	// URITemplate is a URI template (according to RFC 6570) that can be used to construct resource URIs.
	URITemplate string `json:"uriTemplate"`
	// Name is a human-readable name for the type of resource this template refers to.
	// This can be used by clients to populate UI elements.
	Name string `json:"name"`
	// Description is a description of what this template is for.
	// This can be used by clients to improve the LLM's understanding of available resources.
	// It can be thought of like a "hint" to the model.
	Description string `json:"description,omitzero"`
	// MimeType is the MIME type for all resources that match this template. This should only be included
	// if all resources matching this template have the same type.
	MimeType string `json:"mimeType,omitzero"`

	// Annotations are optional annotations for the client.
	Annotations *Annotations `json:"annotations,omitzero"`
}

ResourceTemplate represents a resource template definition. ResourceTemplate is a template description for resources available on the server.

type Role

type Role string

Role represents the sender or recipient of messages and data in a conversation.

const (
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
)

type ServerCompletionHandler

type ServerCompletionHandler interface {
	// HandleComplete handles a completion (completion/complete) request.
	HandleComplete(ctx context.Context, req *CompleteRequestParams) (*CompleteResult, error)
}

ServerCompletionHandler is the interface for a server that can handle completion requests.

type ServerResourceHandler

type ServerResourceHandler interface {
	// HandleResourcesList handles a resources/list request.
	HandleResourcesList(ctx context.Context) (*ListResourcesResult, error)
	// HandleResourcesRead handles a resources/read request.
	HandleResourcesRead(ctx context.Context, req *ReadResourceRequest) (*ReadResourceResult, error)
}

ServerResourceHandler is the interface for a server that can handle resource-related requests.

type StdioTransportOptions

type StdioTransportOptions struct {
	// MaxConns is the maximum number of connections that can be handled by the transport.
	// If this is not set, 5 connections are allowed.
	MaxConns int
	// Preempter is the preempter for the transport.
	// If this is not set, no preemption is done.
	Preempter jsonrpc2.Preempter
}

type TextContent

type TextContent struct {
	// Text is the text content of the message.
	Text string `json:"text"`

	// Annotations are optional annotations for the client.
	Annotations *Annotations `json:"annotations,omitzero"`
}

TextContent represents text data.

func (TextContent) MarshalJSON

func (t TextContent) MarshalJSON() ([]byte, error)

type TextResourceContent

type TextResourceContent struct {
	// URI is the URI of this resource.
	URI string
	// MimeType is the MIME type of this resource, if known.
	MimeType string
	// Text is the text of the item. This must only be set if the item can actually be represented as text (not binary data).
	Text string
}

TextResourceContent represents textual resource content.

func (TextResourceContent) MarshalJSON

func (t TextResourceContent) MarshalJSON() ([]byte, error)

Directories

Path Synopsis
examples
weather
Code generated by mcp-codegen.
Code generated by mcp-codegen.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL