Sponsored by Deepsite.site

MCP Server Example (MCP Coffee Shop)

Created By
BearHuddleston6 months ago
Example how to make a DIY MCP server in Go
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

FlagDescriptionDefaultExample
--transportTransport type (stdio or http)stdio--transport http
--portHTTP port (ignored for stdio)8080--port 9000
--request-timeoutRequest timeout duration30s--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:

ToolDescriptionParameters
getDrinkNamesGet list of available drinksNone
getDrinkInfoGet detailed drink informationname: string (required)

Example:

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

Resources

Contextual data managed by the application:

ResourceURIDescription
menumenu://appComplete coffee shop menu

Example:

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

Prompts

Template-driven interactions for the LLM:

PromptDescriptionParameters
drinkRecommendationGet personalized drink recommendationsbudget: number (optional)
preference: string (optional)
drinkDescriptionGet detailed drink descriptionsdrink_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

MethodDescriptionParameters
initializeInitialize MCP sessionClient info (optional)
tools/listList available toolsNone
tools/callExecute a toolname, arguments
resources/listList available resourcesNone
resources/readRead resource contenturi
prompts/listList available promptsNone
prompts/getGet prompt templatename, arguments (optional)
pingHealth checkNone

Error Codes

CodeMeaningDescription
-32700Parse ErrorInvalid JSON was received
-32600Invalid RequestInvalid JSON-RPC request
-32601Method Not FoundMethod does not exist
-32602Invalid ParamsInvalid method parameters
-32603Internal ErrorInternal 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

Recommend Servers
TraeBuild with Free GPT-4.1 & Claude 3.7. Fully MCP-Ready.
Visual Studio Code - Open Source ("Code - OSS")Visual Studio Code
BlenderBlenderMCP connects Blender to Claude AI through the Model Context Protocol (MCP), allowing Claude to directly interact with and control Blender. This integration enables prompt assisted 3D modeling, scene creation, and manipulation.
MCP AdvisorMCP Advisor & Installation - Use the right MCP server for your needs
WindsurfThe new purpose-built IDE to harness magic
CursorThe AI Code Editor
Context7Context7 MCP Server -- Up-to-date code documentation for LLMs and AI code editors
Jina AI MCP ToolsA Model Context Protocol (MCP) server that integrates with Jina AI Search Foundation APIs.
AiimagemultistyleA Model Context Protocol (MCP) server for image generation and manipulation using fal.ai's Stable Diffusion model.
Serper MCP ServerA Serper MCP Server
Zhipu Web SearchZhipu Web Search MCP Server is a search engine specifically designed for large models. It integrates four search engines, allowing users to flexibly compare and switch between them. Building upon the web crawling and ranking capabilities of traditional search engines, it enhances intent recognition capabilities, returning results more suitable for large model processing (such as webpage titles, URLs, summaries, site names, site icons, etc.). This helps AI applications achieve "dynamic knowledge acquisition" and "precise scenario adaptation" capabilities.
EdgeOne Pages MCPAn MCP service designed for deploying HTML content to EdgeOne Pages and obtaining an accessible public URL.
MiniMax MCPOfficial MiniMax Model Context Protocol (MCP) server that enables interaction with powerful Text to Speech, image generation and video generation APIs.
TimeA Model Context Protocol server that provides time and timezone conversion capabilities. This server enables LLMs to get current time information and perform timezone conversions using IANA timezone names, with automatic system timezone detection.
Playwright McpPlaywright MCP server
Tavily Mcp
Amap Maps高德地图官方 MCP Server
ChatWiseThe second fastest AI chatbot™
DeepChatYour AI Partner on Desktop
Howtocook Mcp基于Anduin2017 / HowToCook (程序员在家做饭指南)的mcp server,帮你推荐菜谱、规划膳食,解决“今天吃什么“的世纪难题; Based on Anduin2017/HowToCook (Programmer's Guide to Cooking at Home), MCP Server helps you recommend recipes, plan meals, and solve the century old problem of "what to eat today"
Baidu Map百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。