MCP ExplorerExplorer

Go Mcp Server Example

@BearHuddlestonon 9 months ago
5 MIT
FreeCommunity
AI Systems
#example#go#golang#mcp-server
Example how to make a DIY MCP server in Go

Overview

What is Go Mcp Server Example

go-mcp-server-example is an implementation of a Model Context Protocol (MCP) server in Go, designed to provide coffee shop information through various tools and resources.

Use cases

Use cases include building a coffee shop management system, integrating with MCP Inspector for debugging, and creating interactive tools for coffee shop operations.

How to use

To use go-mcp-server-example, build the application using ‘go build -o mcpserver ./cmd/mcpserver’, then run it with either stdio transport or HTTP transport by executing ‘./mcpserver’ or ‘./mcpserver -transport http -port 8080’.

Key features

Key features include compliance with MCP 2025-03-26 specification, support for multiple transport methods (stdio and HTTP), a focus on coffee shop operations, graceful shutdown capabilities, configurable timeouts, and production readiness with structured logging and error handling.

Where to use

go-mcp-server-example can be used in the coffee shop industry, particularly for applications that require managing coffee shop operations and providing relevant information to customers.

Content

MCP Server Example (MCP Coffee Shop)

A Model Context Protocol (MCP) server implementation in Go that provides coffee shop information through tools, resources, and prompts, following Go project layout best practices.

Features

  • MCP 2025-03-26 Specification Compliant
  • Multiple Transport Support: stdio (default, compatible with MCP Inspector), http (with SSE)
  • Coffee Shop Domain: Tools, resources, and prompts for coffee shop operations
  • Graceful Shutdown & Configurable Timeouts
  • Production Ready: Structured logging, error handling, validation

Project Structure

simple-mcp-server-refactored/
├── cmd/mcpserver/           # Application entrypoint
├── pkg/                     # Public library code
│   ├── mcp/                 # Core MCP protocol types
│   ├── config/              # Configuration management
│   ├── transport/           # Transport implementations
│   └── handlers/            # Domain-specific handlers
├── internal/server/         # Server implementation
└── go.mod

Usage

# Build the application
go build -o mcpserver ./cmd/mcpserver

# Run with stdio transport (default)
./mcpserver

# Run with HTTP transport
./mcpserver -transport http -port 8080
  • stdio: Standard input/output (default, compatible with MCP Inspector)
  • http: HTTP with Server-Sent Events (SSE) support
  • Coffee Shop Domain: Tools, resources, and prompts for coffee shop operations
  • Graceful Shutdown: Proper signal handling and resource cleanup
  • Configurable Timeouts: Request, shutdown, and HTTP timeouts
  • Production Ready: Structured logging, error handling, and validation

Quick Start

Docker

You can run the MCP server using Docker:

  1. Build the Docker image:

    docker build -t mcp-server .
    
  2. Run the container:

    # For HTTP transport (exposes port 8080)
    docker run -p 8080:8080 mcp-server --transport http --port 8080
    
    # For stdio transport (useful with MCP Inspector)
    docker run -it mcp-server --transport stdio
    
  3. Using environment variables:

    docker run -p 8080:8080 -e TRANSPORT=http -e PORT=8080 mcp-server
    

Prerequisites

Installation

git clone <repository-url>
cd simple-mcp-server
go build

Basic Usage

# Start with stdio transport (default)
go run ./...

# Start with HTTP transport
go run ./... --transport http --port 8080

# Custom configuration
go run ./... --transport http --port 9000 --request-timeout 45s

Configuration

Command Line Flags

Flag Description Default Example
--transport Transport type (stdio or http) stdio --transport http
--port HTTP port (ignored for stdio) 8080 --port 9000
--request-timeout Request timeout duration 30s --request-timeout 45s

Environment Variables

The server uses Go’s built-in flag parsing. Configuration is primarily through command-line flags.

Transports

Stdio Transport

Perfect for command-line tools and MCP Inspector integration:

go run ./... --transport stdio

Use Cases:

  • MCP Inspector debugging
  • CLI integrations
  • Development and testing

HTTP Transport

RESTful HTTP API with optional Server-Sent Events:

go run ./... --transport http --port 8080

Endpoints:

  • POST /mcp - Send JSON-RPC requests
  • GET /mcp - Open SSE stream
  • GET /health - Health check

Examples:

# Regular JSON response
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"initialize","id":1}'

# SSE stream response
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":"test"}'

Implementing a New Handler

To add a new handler to the MCP server, follow these steps using the getWeather handler as an example:

  1. Create a new handler file in pkg/handlers/ (e.g., weather.go):
package handlers

import (
	"context"
	"encoding/json"

	"github.com/your-org/simple-mcp-server-refactored/pkg/mcp"
)

type WeatherHandler struct {
	// Add any dependencies here (e.g., API clients, config)
}

// WeatherRequest represents the expected request parameters
type WeatherRequest struct {
	Location string `json:"location"`
}

// WeatherResponse represents the response structure
type WeatherResponse struct {
	Location    string  `json:"location"`
	Temperature float64 `json:"temperature"`
	Condition   string  `json:"condition"`
	Humidity    int     `json:"humidity"`
	WindSpeed   float64 `json:"wind_speed"`
	Unit        string  `json:"unit"`
}

// Handle processes the weather request
func (h *WeatherHandler) Handle(ctx context.Context, request json.RawMessage) (interface{}, error) {
	var req WeatherRequest
	if err := json.Unmarshal(request, &req); err != nil {
		return nil, mcp.NewInvalidParamsError("invalid request parameters")
	}

	// TODO: Implement actual weather data retrieval
	// This is a mock implementation
	return WeatherResponse{
		Location:    req.Location,
		Temperature: 72.5,
		Condition:   "Sunny",
		Humidity:    45,
		WindSpeed:   8.2,
		Unit:        "fahrenheit",
	}, nil
}

// Register registers the handler with the MCP server
func (h *WeatherHandler) Register(router *mcp.Router) {
	router.RegisterHandler("getWeather", h.Handle)
}
  1. Register the handler in internal/server/server.go:
// In NewServer function
weatherHandler := &handlers.WeatherHandler{}
weatherHandler.Register(router)
  1. Add tests in pkg/handlers/weather_test.go:
package handlers_test

import (
	"context"
	"encoding/json"
	"testing"

	"github.com/your-org/simple-mcp-server-refactored/pkg/handlers"
	"github.com/stretchr/testify/assert"
)

func TestWeatherHandler(t *testing.T) {
	h := &handlers.WeatherHandler{}
	
	t.Run("successful request", func(t *testing.T) {
		req := map[string]interface{}{
			"location": "New York, NY",
		}
		reqBytes, _ := json.Marshal(req)

		result, err := h.Handle(context.Background(), reqBytes)
		assert.NoError(t, err)
		assert.NotNil(t, result)
		
		resp, ok := result.(handlers.WeatherResponse)
		assert.True(t, ok)
		assert.Equal(t, "New York, NY", resp.Location)
	})

	t.Run("invalid request", func(t *testing.T) {
		req := map[string]interface{}{
			"invalid": "data",
		}
		reqBytes, _ := json.Marshal(req)

		_, err := h.Handle(context.Background(), reqBytes)
		assert.Error(t, err)
	})
}
  1. Update documentation in the README.md to document the new handler.

MCP Capabilities

Tools

Interactive functions that can be called by the LLM:

Tool Description Parameters
getDrinkNames Get list of available drinks None
getDrinkInfo Get detailed drink information name: string (required)

Example:

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "id": "1",
  "params": {
    "name": "getDrinkInfo",
    "arguments": {
      "name": "Latte"
    }
  }
}

Resources

Contextual data managed by the application:

Resource URI Description
menu menu://app Complete coffee shop menu

Example:

{
  "jsonrpc": "2.0",
  "method": "resources/read",
  "id": "1",
  "params": {
    "uri": "menu://app"
  }
}

Prompts

Template-driven interactions for the LLM:

Prompt Description Parameters
drinkRecommendation Get personalized drink recommendations budget: number (optional)
preference: string (optional)
drinkDescription Get detailed drink descriptions drink_name: string (required)

Example:

{
  "jsonrpc": "2.0",
  "method": "prompts/get",
  "id": "1",
  "params": {
    "name": "drinkRecommendation",
    "arguments": {
      "budget": 6,
      "preference": "sweet"
    }
  }
}

Testing with MCP Inspector

  1. Install MCP Inspector:

    npm install -g @modelcontextprotocol/inspector
    
  2. Start the inspector:

    npx @modelcontextprotocol/inspector
    
  3. Connect to the server:

    • Transport: stdio
    • Command: go
    • Args: run ./...

Manual Testing

# Test stdio transport
echo '{"jsonrpc":"2.0","method":"initialize","id":1}' | go run ./... --transport stdio

# Test HTTP transport
go run ./... --transport http &
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"initialize","id":1}'

API Reference

JSON-RPC Methods

Method Description Parameters
initialize Initialize MCP session Client info (optional)
tools/list List available tools None
tools/call Execute a tool name, arguments
resources/list List available resources None
resources/read Read resource content uri
prompts/list List available prompts None
prompts/get Get prompt template name, arguments (optional)
ping Health check None

Error Codes

Code Meaning Description
-32700 Parse Error Invalid JSON was received
-32600 Invalid Request Invalid JSON-RPC request
-32601 Method Not Found Method does not exist
-32602 Invalid Params Invalid method parameters
-32603 Internal Error Internal JSON-RPC error

Systemd Service

[Unit]
Description=MCP Coffee Server
After=network.target

[Service]
Type=simple
User=mcp
ExecStart=/usr/local/bin/mcp-server --transport http --port 8080
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Troubleshooting

Common Issues

Connection Refused (HTTP)

# Check if server is running
curl http://localhost:8080/health

# Verify port is not in use
lsof -i :8080

Stdio Transport Not Responding

# Check JSON format
echo '{"jsonrpc":"2.0","method":"ping","id":1}' | go run ./...

Request Timeout

# Increase timeout
go run ./... --request-timeout 60s

Parse Errors

  • Ensure JSON is valid and properly formatted
  • Check that all required fields are present
  • Verify JSON-RPC 2.0 compliance

Resources

Support

For issues and questions:

License

MIT

Tools

No tools

Comments

Recommend MCP Servers

View All MCP Servers