{"id":30871785,"url":"https://github.com/BearHuddleston/go-mcp-server-example","last_synced_at":"2025-09-07T22:29:28.335Z","repository":{"id":297136751,"uuid":"995767471","full_name":"BearHuddleston/go-mcp-server-example","owner":"BearHuddleston","description":"Example how to make a DIY MCP server in Go","archived":false,"fork":false,"pushed_at":"2025-06-04T01:48:41.000Z","size":29,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-07T06:43:25.838Z","etag":null,"topics":["example","go","golang","mcp-server"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BearHuddleston.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-04T01:32:35.000Z","updated_at":"2025-07-03T09:24:31.000Z","dependencies_parsed_at":"2025-06-04T08:52:44.544Z","dependency_job_id":"4047571c-2103-4c21-91d4-710e223e87eb","html_url":"https://github.com/BearHuddleston/go-mcp-server-example","commit_stats":null,"previous_names":["bearhuddleston/go-mcp-server-example"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/BearHuddleston/go-mcp-server-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BearHuddleston%2Fgo-mcp-server-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BearHuddleston%2Fgo-mcp-server-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BearHuddleston%2Fgo-mcp-server-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BearHuddleston%2Fgo-mcp-server-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BearHuddleston","download_url":"https://codeload.github.com/BearHuddleston/go-mcp-server-example/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BearHuddleston%2Fgo-mcp-server-example/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274106566,"owners_count":25223436,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["example","go","golang","mcp-server"],"created_at":"2025-09-07T22:05:29.928Z","updated_at":"2025-09-07T22:29:28.319Z","avatar_url":"https://github.com/BearHuddleston.png","language":"Go","funding_links":[],"categories":["⚙️ DevOps"],"sub_categories":[],"readme":"# MCP Server Example (MCP Coffee Shop)\n\nA [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server implementation in Go that provides coffee shop information through tools, resources, and prompts, following Go project layout best practices.\n\n## Features\n\n- **MCP 2025-03-26 Specification Compliant**\n- **Multiple Transport Support**: `stdio` (default, compatible with MCP Inspector), `http` (with SSE)\n- **Coffee Shop Domain**: Tools, resources, and prompts for coffee shop operations\n- **Graceful Shutdown \u0026 Configurable Timeouts**\n- **Production Ready**: Structured logging, error handling, validation\n\n## Project Structure\n\n```\nsimple-mcp-server-refactored/\n├── cmd/mcpserver/           # Application entrypoint\n├── pkg/                     # Public library code\n│   ├── mcp/                 # Core MCP protocol types\n│   ├── config/              # Configuration management\n│   ├── transport/           # Transport implementations\n│   └── handlers/            # Domain-specific handlers\n├── internal/server/         # Server implementation\n└── go.mod\n```\n\n## Usage\n\n```bash\n# Build the application\ngo build -o mcpserver ./cmd/mcpserver\n\n# Run with stdio transport (default)\n./mcpserver\n\n# Run with HTTP transport\n./mcpserver -transport http -port 8080\n```\n\n  - `stdio`: Standard input/output (default, compatible with MCP Inspector)\n  - `http`: HTTP with Server-Sent Events (SSE) support\n- **Coffee Shop Domain**: Tools, resources, and prompts for coffee shop operations\n- **Graceful Shutdown**: Proper signal handling and resource cleanup\n- **Configurable Timeouts**: Request, shutdown, and HTTP timeouts\n- **Production Ready**: Structured logging, error handling, and validation\n\n## Quick Start\n\n### Docker\n\nYou can run the MCP server using Docker:\n\n1. **Build the Docker image**:\n   ```bash\n   docker build -t mcp-server .\n   ```\n\n2. **Run the container**:\n   ```bash\n   # For HTTP transport (exposes port 8080)\n   docker run -p 8080:8080 mcp-server --transport http --port 8080\n   \n   # For stdio transport (useful with MCP Inspector)\n   docker run -it mcp-server --transport stdio\n   ```\n\n3. **Using environment variables**:\n   ```bash\n   docker run -p 8080:8080 -e TRANSPORT=http -e PORT=8080 mcp-server\n   ```\n\n### Prerequisites\n\n- Go 1.24+ installed\n- For testing: [MCP Inspector](https://github.com/modelcontextprotocol/inspector)\n\n### Installation\n\n```bash\ngit clone \u003crepository-url\u003e\ncd simple-mcp-server\ngo build\n```\n\n### Basic Usage\n\n```bash\n# Start with stdio transport (default)\ngo run ./...\n\n# Start with HTTP transport\ngo run ./... --transport http --port 8080\n\n# Custom configuration\ngo run ./... --transport http --port 9000 --request-timeout 45s\n```\n\n## Configuration\n\n### Command Line Flags\n\n| Flag | Description | Default | Example |\n|------|-------------|---------|---------|\n| `--transport` | Transport type (`stdio` or `http`) | `stdio` | `--transport http` |\n| `--port` | HTTP port (ignored for stdio) | `8080` | `--port 9000` |\n| `--request-timeout` | Request timeout duration | `30s` | `--request-timeout 45s` |\n\n### Environment Variables\n\nThe server uses Go's built-in flag parsing. Configuration is primarily through command-line flags.\n\n## Transports\n\n### Stdio Transport\n\nPerfect for command-line tools and MCP Inspector integration:\n\n```bash\ngo run ./... --transport stdio\n```\n\n**Use Cases:**\n- MCP Inspector debugging\n- CLI integrations\n- Development and testing\n\n### HTTP Transport\n\nRESTful HTTP API with optional Server-Sent Events:\n\n```bash\ngo run ./... --transport http --port 8080\n```\n\n**Endpoints:**\n- `POST /mcp` - Send JSON-RPC requests\n- `GET /mcp` - Open SSE stream\n- `GET /health` - Health check\n\n**Examples:**\n\n```bash\n# Regular JSON response\ncurl -X POST http://localhost:8080/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"method\":\"initialize\",\"id\":1}'\n\n# SSE stream response\ncurl -X POST http://localhost:8080/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Accept: text/event-stream\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"method\":\"tools/list\",\"id\":\"test\"}'\n```\n\n## Implementing a New Handler\n\nTo add a new handler to the MCP server, follow these steps using the `getWeather` handler as an example:\n\n1. **Create a new handler file** in `pkg/handlers/` (e.g., `weather.go`):\n\n```go\npackage handlers\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\n\t\"github.com/your-org/simple-mcp-server-refactored/pkg/mcp\"\n)\n\ntype WeatherHandler struct {\n\t// Add any dependencies here (e.g., API clients, config)\n}\n\n// WeatherRequest represents the expected request parameters\ntype WeatherRequest struct {\n\tLocation string `json:\"location\"`\n}\n\n// WeatherResponse represents the response structure\ntype WeatherResponse struct {\n\tLocation    string  `json:\"location\"`\n\tTemperature float64 `json:\"temperature\"`\n\tCondition   string  `json:\"condition\"`\n\tHumidity    int     `json:\"humidity\"`\n\tWindSpeed   float64 `json:\"wind_speed\"`\n\tUnit        string  `json:\"unit\"`\n}\n\n// Handle processes the weather request\nfunc (h *WeatherHandler) Handle(ctx context.Context, request json.RawMessage) (interface{}, error) {\n\tvar req WeatherRequest\n\tif err := json.Unmarshal(request, \u0026req); err != nil {\n\t\treturn nil, mcp.NewInvalidParamsError(\"invalid request parameters\")\n\t}\n\n\t// TODO: Implement actual weather data retrieval\n\t// This is a mock implementation\n\treturn WeatherResponse{\n\t\tLocation:    req.Location,\n\t\tTemperature: 72.5,\n\t\tCondition:   \"Sunny\",\n\t\tHumidity:    45,\n\t\tWindSpeed:   8.2,\n\t\tUnit:        \"fahrenheit\",\n\t}, nil\n}\n\n// Register registers the handler with the MCP server\nfunc (h *WeatherHandler) Register(router *mcp.Router) {\n\trouter.RegisterHandler(\"getWeather\", h.Handle)\n}\n```\n\n2. **Register the handler** in `internal/server/server.go`:\n\n```go\n// In NewServer function\nweatherHandler := \u0026handlers.WeatherHandler{}\nweatherHandler.Register(router)\n```\n\n3. **Add tests** in `pkg/handlers/weather_test.go`:\n\n```go\npackage handlers_test\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/your-org/simple-mcp-server-refactored/pkg/handlers\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestWeatherHandler(t *testing.T) {\n\th := \u0026handlers.WeatherHandler{}\n\t\n\tt.Run(\"successful request\", func(t *testing.T) {\n\t\treq := map[string]interface{}{\n\t\t\t\"location\": \"New York, NY\",\n\t\t}\n\t\treqBytes, _ := json.Marshal(req)\n\n\t\tresult, err := h.Handle(context.Background(), reqBytes)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, result)\n\t\t\n\t\tresp, ok := result.(handlers.WeatherResponse)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, \"New York, NY\", resp.Location)\n\t})\n\n\tt.Run(\"invalid request\", func(t *testing.T) {\n\t\treq := map[string]interface{}{\n\t\t\t\"invalid\": \"data\",\n\t\t}\n\t\treqBytes, _ := json.Marshal(req)\n\n\t\t_, err := h.Handle(context.Background(), reqBytes)\n\t\tassert.Error(t, err)\n\t})\n}\n```\n\n4. **Update documentation** in the README.md to document the new handler.\n\n## MCP Capabilities\n\n### Tools\n\nInteractive functions that can be called by the LLM:\n\n| Tool | Description | Parameters |\n|------|-------------|------------|\n| `getDrinkNames` | Get list of available drinks | None |\n| `getDrinkInfo` | Get detailed drink information | `name`: string (required) |\n\n**Example:**\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"tools/call\",\n  \"id\": \"1\",\n  \"params\": {\n    \"name\": \"getDrinkInfo\",\n    \"arguments\": {\"name\": \"Latte\"}\n  }\n}\n```\n\n### Resources\n\nContextual data managed by the application:\n\n| Resource | URI | Description |\n|----------|-----|-------------|\n| `menu` | `menu://app` | Complete coffee shop menu |\n\n**Example:**\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"resources/read\",\n  \"id\": \"1\",\n  \"params\": {\"uri\": \"menu://app\"}\n}\n```\n\n### Prompts\n\nTemplate-driven interactions for the LLM:\n\n| Prompt | Description | Parameters |\n|--------|-------------|------------|\n| `drinkRecommendation` | Get personalized drink recommendations | `budget`: number (optional)\u003cbr\u003e`preference`: string (optional) |\n| `drinkDescription` | Get detailed drink descriptions | `drink_name`: string (required) |\n\n**Example:**\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"prompts/get\",\n  \"id\": \"1\",\n  \"params\": {\n    \"name\": \"drinkRecommendation\",\n    \"arguments\": {\"budget\": 6, \"preference\": \"sweet\"}\n  }\n}\n```\n\n## Testing with MCP Inspector\n\n1. **Install MCP Inspector:**\n   ```bash\n   npm install -g @modelcontextprotocol/inspector\n   ```\n\n2. **Start the inspector:**\n   ```bash\n   npx @modelcontextprotocol/inspector\n   ```\n\n3. **Connect to the server:**\n   - **Transport**: `stdio`\n   - **Command**: `go`\n   - **Args**: `run ./...`\n\n\n## Manual Testing\n```bash\n# Test stdio transport\necho '{\"jsonrpc\":\"2.0\",\"method\":\"initialize\",\"id\":1}' | go run ./... --transport stdio\n\n# Test HTTP transport\ngo run ./... --transport http \u0026\ncurl -X POST http://localhost:8080/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"method\":\"initialize\",\"id\":1}'\n```\n\n## API Reference\n\n### JSON-RPC Methods\n\n| Method | Description | Parameters |\n|--------|-------------|------------|\n| `initialize` | Initialize MCP session | Client info (optional) |\n| `tools/list` | List available tools | None |\n| `tools/call` | Execute a tool | `name`, `arguments` |\n| `resources/list` | List available resources | None |\n| `resources/read` | Read resource content | `uri` |\n| `prompts/list` | List available prompts | None |\n| `prompts/get` | Get prompt template | `name`, `arguments` (optional) |\n| `ping` | Health check | None |\n\n### Error Codes\n\n| Code | Meaning | Description |\n|------|---------|-------------|\n| `-32700` | Parse Error | Invalid JSON was received |\n| `-32600` | Invalid Request | Invalid JSON-RPC request |\n| `-32601` | Method Not Found | Method does not exist |\n| `-32602` | Invalid Params | Invalid method parameters |\n| `-32603` | Internal Error | Internal JSON-RPC error |\n\n### Systemd Service\n\n```ini\n[Unit]\nDescription=MCP Coffee Server\nAfter=network.target\n\n[Service]\nType=simple\nUser=mcp\nExecStart=/usr/local/bin/mcp-server --transport http --port 8080\nRestart=always\nRestartSec=10\n\n[Install]\nWantedBy=multi-user.target\n```\n\n## Troubleshooting\n\n### Common Issues\n\n**Connection Refused (HTTP)**\n```bash\n# Check if server is running\ncurl http://localhost:8080/health\n\n# Verify port is not in use\nlsof -i :8080\n```\n\n**Stdio Transport Not Responding**\n```bash\n# Check JSON format\necho '{\"jsonrpc\":\"2.0\",\"method\":\"ping\",\"id\":1}' | go run ./...\n```\n\n**Request Timeout**\n```bash\n# Increase timeout\ngo run ./... --request-timeout 60s\n```\n\n**Parse Errors**\n- Ensure JSON is valid and properly formatted\n- Check that all required fields are present\n- Verify JSON-RPC 2.0 compliance\n\n## Resources\n\n- [Model Context Protocol Specification](https://modelcontextprotocol.io/specification/2025-03-26)\n- [MCP Inspector](https://github.com/modelcontextprotocol/inspector)\n- [Go Documentation](https://golang.org/doc/)\n- [Jack Herrington's YouTube video on DIY MCP Server](https://www.youtube.com/watch?v=nTMSyldeVSw)\n\n## Support\n\nFor issues and questions:\n- Create an issue in the repository\n- Check the [MCP documentation](https://modelcontextprotocol.io/)\n- Review the [troubleshooting section](#troubleshooting)\n\n## License\n\nMIT","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBearHuddleston%2Fgo-mcp-server-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FBearHuddleston%2Fgo-mcp-server-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBearHuddleston%2Fgo-mcp-server-example/lists"}