CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/golang-mcp-golang

An unofficial implementation of the Model Context Protocol in Go

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

mcp-golang

mcp-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.

Package Information

  • Package Name: mcp-golang
  • Package Type: golang
  • Language: Go
  • Module Path: github.com/metoro-io/mcp-golang
  • Installation: go get github.com/metoro-io/mcp-golang
  • Minimum Go Version: 1.21

Core Imports

import (
    mcp "github.com/metoro-io/mcp-golang"
    "github.com/metoro-io/mcp-golang/transport/stdio"
    "github.com/metoro-io/mcp-golang/transport/http"
)

Basic Usage

Creating an MCP Server

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)
    }
}

Creating an MCP Client

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)
    }
}

Architecture

mcp-golang uses a modular architecture with three main layers:

  1. Protocol Layer: The core Client and Server types implement the MCP protocol, handling tool/prompt/resource registration and execution
  2. Content Layer: Rich content types support text, images, and embedded resources with annotations
  3. Transport Layer: Pluggable transports (stdio, HTTP, Gin) handle message delivery

Transport Options

  • Stdio: Full bidirectional support for all MCP features including notifications
  • HTTP: Stateless request-response for simple scenarios (no notifications)
  • Gin: HTTP transport with Gin framework integration (stateless, no notifications)

Capabilities

MCP Client

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) *Client

Client API Documentation

MCP Server

Build MCP servers that expose tools, prompts, and resources to clients.

type Server struct { /* ... */ }

func NewServer(transport transport.Transport, options ...ServerOptions) *Server

Server API Documentation

Content Types and Responses

Rich 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) *Content

Content Types Documentation

Transport Layer

Abstract 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))
}

Transport Layer Documentation

Stdio Transport

Standard input/output transport for full bidirectional MCP communication.

type StdioServerTransport struct { /* ... */ }

func NewStdioServerTransport() *StdioServerTransport
func NewStdioServerTransportWithIO(in io.Reader, out io.Writer) *StdioServerTransport

Stdio Transport Documentation

HTTP Transports

HTTP-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() *GinTransport

HTTP Transports Documentation

Key Features

  • Type Safety: Define tool arguments as native Go structs with automatic JSON schema generation and validation
  • Minimal Boilerplate: Automatic endpoint generation for tools, prompts, and resources
  • Flexible Transports: Choose between stdio (full features), HTTP (stateless), or Gin (framework integration)
  • Change Notifications: Support for notifying clients about changes to tools, prompts, and resources (stdio only)
  • Pagination: Built-in pagination support for listing tools, prompts, and resources
  • Bidirectional Communication: Full support for both server and client implementations through stdio transport

Common Use Cases

Building an MCP Server for Claude Desktop

server := 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": {}
    }
  }
}

Building an HTTP-based MCP Server

// 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")

Connecting to an MCP Server

// 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())

docs

client.md

content-types.md

index.md

server.md

transport-http.md

transport-stdio.md

transport.md

tile.json