tiny-go-mcp-server
This server provides a lightweight MCP implementation over stdio, offering basic arithmetic and greeting tools for testing AI client integrations (e.g., Cursor, Claude Desktop, Windsurf, Zed).
Add two integers (
add): Provide two integers (aandb) and receive their sum.Subtract two integers (
subtract): Provide two integers (aandb) and receive the difference (a minus b).Generate a personalized greeting (
greet): Provide a requirednameand an optionalgreetingphrase to receive a custom greeting message.
Tiny Go MCP Server
A lightweight Model Context Protocol (MCP) toolkit for Go. Build spec-compliant MCP servers (stdio, streamable HTTP, legacy SSE) with tools, resources, and prompts — minimal boilerplate and automatic JSON Schema from Go structs.
Built on the official modelcontextprotocol/go-sdk.
Requirements: Go 1.26+ (download).
Why Tiny?
Tiny Go MCP Server | Full frameworks | |
Goal | Thin helper on official go-sdk + tiny static binary | Full MCP feature surface |
Deps | Official go-sdk only | Varies |
Binary | ~5MB stripped, no runtime on host | Often larger stacks |
Schemas | Inferred from struct tags | Manual or builder APIs |
Use this project as a library (tinymcp package) or as a starting template (cmd/tiny-go-mcp).
When to use what
tinymcp (this repo) | go-sdk alone | ||
Best for | Thin helper on go-sdk, tiny binary | Rich helpers, large ecosystem | Full control, no extra layer |
Schema | Struct tags → auto JSON Schema | Builder APIs / helpers |
|
Transport | stdio ( | stdio, SSE, HTTP, … | All transports |
Deps | go-sdk only | Standalone module | go-sdk only |
Choose tinymcp when you want the official protocol implementation with minimal boilerplate and a small static server binary.
Philosophy
tinymcp is a thin helper on the official go-sdk — not a replacement for it.
We reduce setup and transport boilerplate (server creation, registration error handling, stdio/HTTP/SSE, TextResult, deploy examples). The protocol implementation, generics, and schema inference still come from modelcontextprotocol/go-sdk.
That means handler code uses both imports — and that is intentional:
import (
"github.com/kioie/tiny-go-mcp-server/tinymcp"
"github.com/modelcontextprotocol/go-sdk/mcp" // handler types, prompts, resources, advanced APIs
)Use tinymcp for | Use go-sdk ( |
| Handler signatures ( |
Safe registration (errors, not panics) | Tool annotations, elicitation, custom protocol features |
| Anything via |
We are not aiming for a non-leaky facade that hides the SDK. If you need full control, call RawServer() or use go-sdk directly — same underlying server, no lock-in.
tinymcp vs raw go-sdk
Same protocol implementation — tinymcp removes repetitive setup. Handler code still imports mcp for request types in both cases.
go-sdk alone (minimal stdio server):
server := mcp.NewServer(&mcp.Implementation{Name: "my-mcp", Version: "1.0.0"}, nil)
mcp.AddTool(server, &mcp.Tool{
Name: "greet",
Description: "Greet someone by name",
}, greet)
if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil {
log.Fatal(err)
}tinymcp (same tool, less boilerplate):
s := tinymcp.NewServer("my-mcp", "1.0.0")
if err := tinymcp.RegisterTool(s, "greet", "Greet someone by name", greet); err != nil {
log.Fatal(err)
}
log.Fatal(s.Start())tinymcp adds | Still on go-sdk ( |
| Handler signatures ( |
| Tool annotations via |
Safe registration errors (no panics) | Advanced session / event-store APIs |
| Full control via |
Use go-sdk alone when you want zero wrapper. Use tinymcp when you want less setup while staying on the official implementation.
Transport
Method | API | Typical clients |
stdio (default) |
| Cursor, Claude Desktop, Windsurf (local subprocess) |
Streamable HTTP |
| Remote MCP clients, gateways, browser tools |
Legacy SSE |
| Older clients on MCP 2024-11-05 SSE transport |
Start() runs stdio (stdin/stdout) — what most local AI clients expect.
For HTTP/SSE, tinymcp wraps the official go-sdk handlers with minimal options:
// Streamable HTTP on loopback (stateless demo — no GET/SSE or server→client RPC)
log.Fatal(server.StartHTTP("127.0.0.1:8080", &tinymcp.HTTPOptions{Stateless: true}))
// Or mount on your own mux (auth, TLS, path prefix)
handler, _ := tinymcp.StreamableHTTPHandler(server, nil)
http.Handle("/mcp", handler)Stateless mode (Stateless: true) is the default in examples: one POST JSON-RPC per request, no long-lived SSE GET stream, and no server-initiated messages. Omit it or use session options when you need full streamable HTTP sessions — see docs/HTTP.md.
See docs/HTTP.md and examples/http. To host for Smithery URL listing (no Docker for end users), use examples/http-deploy. For advanced session routing or event stores, use server.RawServer() with the go-sdk directly.
Related MCP server: MCP Playground Server
Quick start (library)
Step-by-step guide: docs/QUICKSTART.md. AI codegen: SYSTEM_PROMPT.md.
go get github.com/kioie/tiny-go-mcp-server/tinymcp@latestpackage main
import (
"context"
"fmt"
"log"
"github.com/kioie/tiny-go-mcp-server/tinymcp"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
type greetArgs struct {
Name string `json:"name" jsonschema:"Person to greet"`
}
func main() {
s := tinymcp.NewServer("my-mcp", "1.0.0")
if err := tinymcp.RegisterTool(s, "greet", "Greet someone by name", greet); err != nil {
log.Fatal(err)
}
log.Fatal(s.Start())
}
func greet(_ context.Context, _ *mcp.CallToolRequest, args greetArgs) (*mcp.CallToolResult, any, error) {
return tinymcp.TextResult(fmt.Sprintf("Hello, %s!", args.Name)), nil, nil
}See examples/minimal for a runnable copy-paste example.
Scaffold a new server
Requires tagged module template/ (v1.1.1+) for stdio, or template-http/ for streamable HTTP:
go install golang.org/x/tools/cmd/gonew@latest
gonew github.com/kioie/tiny-go-mcp-server/template@latest example.com/my-mcp my-mcp
cd my-mcp && go run .
# HTTP deploy (Smithery / Fly / Render):
gonew github.com/kioie/tiny-go-mcp-server/template-http@latest example.com/my-mcp-http my-mcp-http
cd my-mcp-http && go run .Or copy examples/minimal, template/, or template-http/ directly.
Install the example server
Both install paths produce a binary named tiny-go-mcp:
# Installs to $(go env GOPATH)/bin/tiny-go-mcp
go install github.com/kioie/tiny-go-mcp-server/cmd/tiny-go-mcp@latestOr build from source (binary in the repo root):
git clone https://github.com/kioie/tiny-go-mcp-server.git
cd tiny-go-mcp-server
make release # → ./tiny-go-mcpMethod | Binary name | Typical path |
|
|
|
|
|
|
|
|
|
Example tools (reference server)
These tools exist for MCP integration demos, not production logic. Agents should compute math and write greetings in-chat unless they are explicitly testing tool calls.
Tool | When to use | When not to / alternative | Arguments |
| Test that the client can call an addition tool | Real arithmetic → compute locally or use a calculator MCP |
|
| Test subtraction wiring (use instead of | Real arithmetic → compute locally |
|
| Test a text-returning tool (use instead of | User-facing hello → reply in the conversation |
|
Connect AI clients
MCP servers communicate over stdio. Point your client at the compiled binary path.
Template config: examples/mcp-client-config.json (copy and set the absolute path to tiny-go-mcp).
Logging: The protocol uses stdin/stdout. Server logs (if any) go to stderr only. Set TINY_GO_MCP_VERBOSE=1 on the server process to enable startup log lines.
Cursor
Settings → Features → MCP → Add server:
Name:
tiny-go-mcpType:
stdioCommand:
/absolute/path/to/tiny-go-mcp
Or add to .cursor/mcp.json in your project:
{
"mcpServers": {
"tiny-go-mcp": {
"command": "/absolute/path/to/tiny-go-mcp"
}
}
}Claude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"tiny-go-mcp": {
"command": "/absolute/path/to/tiny-go-mcp"
}
}
}Windsurf / Zed / other stdio clients
Use the same shape: command = absolute path to tiny-go-mcp, transport = stdio. Refer to your client’s MCP docs for the config file location.
Tips for LLM-friendly tools
Use clear tool names (
snake_case) and descriptions that say when to use, when not to, and which sibling tool applies — models pick tools from these and often have overlapping options.Add
jsonschematags on struct fields so argument docs appear in the schema.Return human-readable text via
tinymcp.TextResultfor predictable client display.See AGENTS.md for conventions when extending this repo with AI assistants.
Resources and prompts
Register read-only context and reusable prompt templates alongside tools:
if err := tinymcp.RegisterTextResource(server, "file:///info", "info", "Server metadata", "text/plain", "…"); err != nil {
log.Fatal(err)
}
if err := tinymcp.RegisterPrompt(server, "code_review", "Review code", []*mcp.PromptArgument{
{Name: "code", Required: true},
}, func(_ context.Context, req *mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
code := req.Params.Arguments["code"]
if code == "" {
return nil, tinymcp.RequiredPromptArgument("code")
}
return tinymcp.PromptResult("Review", tinymcp.UserPromptMessage("Review:\n"+code)), nil
}); err != nil {
log.Fatal(err)
}Runnable example: examples/resources. For dynamic URI templates use RegisterResourceTemplate.
Package API
server := tinymcp.NewServer("name", "version")
tinymcp.NewServer("name", "version", tinymcp.WithInstructions("…")) // optional SDK config
tinymcp.NewServerWithOptions("name", "version", &mcp.ServerOptions{…})
tinymcp.RegisterTool(server, name, description, handler) // typed handler, auto schema
tinymcp.RegisterTextResource(server, uri, name, desc, mime, text)
tinymcp.RegisterPrompt(server, name, desc, args, handler)
server.Start() // stdio transport
server.StartHTTP(":8080", &tinymcp.HTTPOptions{}) // streamable HTTP
server.StartSSE(":8080", nil) // legacy SSE
tinymcp.StreamableHTTPHandler(server, nil) // mount on custom http.Server
tinymcp.TextResult("message") // tool text helper
tinymcp.TextResource(uri, mime, text) // resource read helper
tinymcp.PromptResult(desc, tinymcp.UserPromptMessage("…")) // prompt helper
server.RawServer() // escape hatch to go-sdk
// v1.2+: panic-at-startup registration or errors.Is sentinels
tinymcp.MustRegisterTool(server, name, description, handler)
errors.Is(err, tinymcp.ErrNilServer) // ErrNilTool, ErrNilHandler, ErrRegistrationFailed
opts := (&tinymcp.HTTPOptions{Stateless: true}).WithMiddleware(requestLogger)
tinymcp.ListenAndServeHTTPContext(ctx, addr, handler) // graceful shutdown; also StartHTTPContext / StartSSEContextDocumentation: pkg.go.dev/github.com/kioie/tiny-go-mcp-server/tinymcp. Upgrading from v1.1.x: docs/MIGRATION-v1.2.md.
Development
Command | Description |
| Run tests with race detector |
| golangci-lint |
| Validate MCP tool descriptions in reference servers |
| Coverage report |
| Dev binary |
| Stripped static binary |
|
|
Smaller binaries (~1.8MB)
After make release, optionally pack with UPX:
upx --best --lzma tiny-go-mcpProject structure
tinymcp/ # Library package
cmd/tiny-go-mcp/ # Reference MCP server
template/ # gonew stdio scaffold
template-http/ # gonew streamable HTTP deploy scaffold
examples/minimal/ # Minimal stdio example
examples/http/ # Streamable HTTP example
examples/http-deploy/ # Deployable HTTP + Smithery URL listing (server card, Render/Fly)
examples/resources/ # Resources + prompts example
examples/mcp-client-config.json # Cursor/Claude-style template
scripts/lint-tools/ # MCP tool description linter (make lint-tools)
docs/ # Guides — see below
server.json # MCP Registry metadata (publish with mcp-publisher)
CHANGELOG.md # Release history
SYSTEM_PROMPT.md # Agent-facing API summary for codegen
.github/workflows/ # CI, lint, CodeQL, releasesKey docs in docs/:
Doc | Purpose |
Step-by-step library setup | |
stdio vs streamable HTTP vs legacy SSE | |
Public API stability policy | |
Upgrade guide from v1.1.x | |
HTTPS via reverse proxy or Go | |
DNS rebinding security advisory | |
Registries and visibility | |
Glama hosting | |
Smithery URL and MCPB listings |
Releases
Tag a semver version (e.g. v1.2.0) to publish stable go get versions and trigger GitHub Releases with cross-platform binaries and multi-arch GHCR images. Release history: CHANGELOG.md. Public API stability: docs/STABILITY.md. Agent-facing API summary: SYSTEM_PROMPT.md. Upgrading from v1.1.x: docs/MIGRATION-v1.2.md.
git tag v1.2.0
git push origin v1.2.0Discovery and registries
See docs/DISCOVERY.md for MCP Registry (server.json), awesome lists, and community directories. Listing copy and launch posts: docs/SUBMISSIONS.md. For Glama hosting with Docker, see docs/GLAMA.md.
Contributing
See CONTRIBUTING.md. For AI codegen outside this repo, see SYSTEM_PROMPT.md. CI runs tests, lint, and CodeQL; Dependabot keeps Go and Actions dependencies updated.
License
MIT — see LICENSE.
Maintenance
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kioie/tiny-go-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server