This file is for AI coding agents. Read it before working on this repository.
go-mcp is a zero-dependency Model Context Protocol server framework for Go. It lets you build MCP-compatible servers that expose tools, resources, and prompts to AI clients (Claude Desktop, Cursor, etc.) — as a single Go binary with zero external dependencies.
stdio (os.Stdin/os.Stdout)
│
▼
newline-delimited JSON-RPC 2.0 ← one message per line (MCP stdio framing)
│
▼
Server.run() ← dispatch loop
├── unparseable line → -32700 / -32600, loop keeps serving
├── oversized line → -32600, remainder discarded
├── "initialize" → legacy handshake (version negotiated)
├── "notifications/initialized" → consumed silently
├── "server/discover" → 2026-07-28 capability probe
├── "ping" → empty result (legacy clients)
├── "tools/list" → registered tools metadata
├── "tools/call" → dispatch to Tool.Handler
├── "resources/list" → registered resources metadata
├── "resources/read" → dispatch to Resource.Handler
├── "resources/templates/list" → empty catalog (spec-compliant)
├── "prompts/list" → registered prompts metadata
└── "prompts/get" → dispatch to Prompt.Handler
| File | Purpose |
|---|---|
gomcp/types.go |
Tool, Resource, Prompt, InputSchema, handler signatures |
gomcp/jsonrpc.go |
JSON-RPC 2.0 request/response/error types |
gomcp/protocol.go |
Protocol versions, _meta negotiation, pagination |
gomcp/path.go |
SafeJoin — path-traversal-safe filesystem helper |
gomcp/server.go |
Server struct, Run(), all JSON-RPC method handlers |
gomcp/httpserver.go |
MCP Streamable HTTP transport (Handler, ListenAndServe, Serve) |
gomcp/client.go |
MCP client (Client interface, NewHTTPClient, NewStdioClient) |
gomcp/server_test.go |
Unit + integration tests (pipe-based) |
gomcp/protocol_test.go |
2026-07-28 + security tests |
gomcp/httpserver_test.go, gomcp/client_test.go, gomcp/http_e2e_test.go |
HTTP transport, client, and loopback E2E tests |
gomcp/e2e_test.go |
Subprocess E2E test |
examples/greet/main.go |
Canonical example MCP server |
- Zero dependencies. Only Go stdlib —
encoding/json,bufio,context,fmt,io,os. Never add a third-party import to go.mod. - Interfaces over structs. Handler signatures use
context.Context+ maps for extensibility. Future: typed generics. - Tests use pipes. Integration tests simulate stdio with
io.Pipe(). E2E tests spawn a real subprocess viaos/exec. - Error codes follow JSON-RPC 2.0.
-32700= parse error (broken JSON),-32600= invalid request (well-formed JSON that is not a Request object, idnull),-32601= method not found,-32602= invalid params,-32000= application error. - Bad input never kills the loop. A malformed line is answered in-band and the server keeps serving;
RunWithIOreturns only on EOF or a read/write failure. - Inbound messages are size-capped. One line may carry at most
Server.MaxRequestBytesbytes (defaultDefaultMaxRequestBytes, 10 MiB; negative disables — not recommended). An oversized line is answered with-32600(id null), its remainder discarded, and the loop keeps serving — a single line can never exhaust memory. - Go naming. Exported types are PascalCase. Unexported internals are camelCase. Test functions are
TestXxx. - Protocol versions. Default is
2026-07-28. Legacyinitializestill works and echoes2024-11-05,2025-03-26, or2025-11-25when the client asks for them. 2026-only fields (resultType,ttlMs,cacheScope, result_meta) are emitted only when the request declares2026-07-28. - Handlers must not kill the loop. A panicking or timed-out handler is answered in-band; registration maps are mutex-protected.
# All tests
go test ./gomcp/ -v
# E2E only (requires Go in PATH)
go test ./gomcp/ -run TestE2E -vsrv := gomcp.NewServer("my-server", "1.0.0")
srv.AddTool(gomcp.Tool{
Name: "echo",
Description: "Echo back the message",
InputSchema: gomcp.InputSchema{
Type: "object",
Properties: map[string]gomcp.Property{
"message": {Type: "string"},
},
},
Handler: func(ctx context.Context, args map[string]any) (string, error) {
return args["message"].(string), nil
},
})
srv.Run() // blocks on stdio- Simple. ~350 lines of library code. Readable by humans and agents alike.
- Fast. Zero-allocation JSON decoding where possible. Tiny binary.
- Agent-first. Built for AI agents that need to expose Go-side tools. The AGENTS.md you're reading now is part of the product.
- Go-native. Idiomatic Go, not a TypeScript port. Uses Go's strengths: interfaces, zero-deps compilation, single-binary deploy.