An unofficial implementation of the Model Context Protocol in Go
npx @tessl/cli install tessl/golang-mcp-golang@0.16.0mcp-golang is a comprehensive Go implementation of the Model Context Protocol (MCP), enabling developers to build both MCP servers and clients with minimal boilerplate. It provides type-safe tool argument definitions using native Go structs with automatic JSON schema generation, multiple transport options, and a modular architecture.
github.com/metoro-io/mcp-golanggo get github.com/metoro-io/mcp-golangimport (
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/stdio"
"github.com/metoro-io/mcp-golang/transport/http"
)package main
import (
"fmt"
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/stdio"
)
// Tool arguments are Go structs with jsonschema tags
type CalculateArgs struct {
Operation string `json:"operation" jsonschema:"required,description=The operation to perform (add, subtract, multiply, divide)"`
A int `json:"a" jsonschema:"required,description=First number"`
B int `json:"b" jsonschema:"required,description=Second number"`
}
func main() {
// Create server with stdio transport
server := mcp.NewServer(stdio.NewStdioServerTransport())
// Register a tool
err := server.RegisterTool("calculate", "Perform arithmetic operations",
func(args CalculateArgs) (*mcp.ToolResponse, error) {
var result int
switch args.Operation {
case "add":
result = args.A + args.B
case "subtract":
result = args.A - args.B
case "multiply":
result = args.A * args.B
case "divide":
if args.B == 0 {
return nil, fmt.Errorf("division by zero")
}
result = args.A / args.B
default:
return nil, fmt.Errorf("unknown operation: %s", args.Operation)
}
return mcp.NewToolResponse(
mcp.NewTextContent(fmt.Sprintf("Result: %d", result)),
), nil
})
if err != nil {
panic(err)
}
// Start server
err = server.Serve()
if err != nil {
panic(err)
}
}package main
import (
"context"
"log"
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/stdio"
)
type CalculateArgs struct {
Operation string `json:"operation"`
A int `json:"a"`
B int `json:"b"`
}
func main() {
// Create client with stdio transport
transport := stdio.NewStdioServerTransport()
client := mcp.NewClient(transport)
// Initialize connection
_, err := client.Initialize(context.Background())
if err != nil {
log.Fatalf("Failed to initialize: %v", err)
}
// Call a tool
args := CalculateArgs{
Operation: "add",
A: 10,
B: 5,
}
response, err := client.CallTool(context.Background(), "calculate", args)
if err != nil {
log.Fatalf("Failed to call tool: %v", err)
}
if len(response.Content) > 0 {
log.Printf("Result: %s", response.Content[0].TextContent.Text)
}
}mcp-golang uses a modular architecture with three main layers:
Build MCP clients that connect to and interact with MCP servers.
type Client struct { /* ... */ }
func NewClient(transport transport.Transport) *Client
func NewClientWithInfo(transport transport.Transport, info ClientInfo) *ClientBuild MCP servers that expose tools, prompts, and resources to clients.
type Server struct { /* ... */ }
func NewServer(transport transport.Transport, options ...ServerOptions) *ServerRich content system supporting text, images, and embedded resources with comprehensive response types for tools, prompts, and resources.
type Content struct {
Type ContentType
TextContent *TextContent
ImageContent *ImageContent
EmbeddedResource *EmbeddedResource
Annotations *Annotations
}
func NewTextContent(content string) *Content
func NewImageContent(base64EncodedStringData string, mimeType string) *ContentAbstract transport interface with multiple implementations for different communication patterns.
type Transport interface {
Start(ctx context.Context) error
Send(ctx context.Context, message *BaseJsonRpcMessage) error
Close() error
SetCloseHandler(handler func())
SetErrorHandler(handler func(error))
SetMessageHandler(handler func(ctx context.Context, message *BaseJsonRpcMessage))
}Standard input/output transport for full bidirectional MCP communication.
type StdioServerTransport struct { /* ... */ }
func NewStdioServerTransport() *StdioServerTransport
func NewStdioServerTransportWithIO(in io.Reader, out io.Writer) *StdioServerTransportHTTP-based transports for stateless MCP communication with standard HTTP or Gin framework.
type HTTPTransport struct { /* ... */ }
type HTTPClientTransport struct { /* ... */ }
type GinTransport struct { /* ... */ }
func NewHTTPTransport(endpoint string) *HTTPTransport
func NewHTTPClientTransport(endpoint string) *HTTPClientTransport
func NewGinTransport() *GinTransportserver := mcp.NewServer(
stdio.NewStdioServerTransport(),
mcp.WithName("my-mcp-server"),
mcp.WithVersion("1.0.0"),
mcp.WithInstructions("Instructions for using this server"),
)
// Register your tools, prompts, and resources
server.RegisterTool("tool-name", "description", handlerFunc)
server.Serve()Configure Claude Desktop to use your server by adding to claude_desktop_config.json:
{
"mcpServers": {
"my-server": {
"command": "/path/to/your/server/executable",
"args": [],
"env": {}
}
}
}// Standard HTTP
transport := http.NewHTTPTransport("/mcp")
transport.WithAddr(":8080")
server := mcp.NewServer(transport)
server.RegisterTool("tool-name", "description", handlerFunc)
server.Serve()
// Or with Gin
router := gin.Default()
transport := http.NewGinTransport()
router.POST("/mcp", transport.Handler())
server := mcp.NewServer(transport)
server.RegisterTool("tool-name", "description", handlerFunc)
server.Serve()
router.Run(":8080")// Via stdio (for subprocess communication)
cmd := exec.Command("./mcp-server")
stdin, _ := cmd.StdinPipe()
stdout, _ := cmd.StdoutPipe()
cmd.Start()
defer cmd.Process.Kill()
transport := stdio.NewStdioServerTransportWithIO(stdout, stdin)
client := mcp.NewClient(transport)
client.Initialize(context.Background())
// Via HTTP
transport := http.NewHTTPClientTransport("http://localhost:8080/mcp")
client := mcp.NewClient(transport)
client.Initialize(context.Background())