mark3labs/mcp-go: A Go SDK for Building MCP Servers
A Go implementation of the Model Context Protocol (MCP), enabling seamless integration between LLM applications and external data sources and tools.
At a glance
- What is it?
- mcp-go wraps the Model Context Protocol in Go types so you can register tools, resources and prompts without hand-writing JSON-RPC. It is a good fit for Go services that need to expose capabilities to LLM clients over stdio, but the README itself flags that the implementation only aims at full spec coverage.
- Who is it for?
- Adopt mcp-go if you are writing a Go process that must expose tools or resources to an MCP client and you want the protocol framing handled for you. Do not adopt it if you need a client-side SDK in another language, or if you require every capability in the MCP specification to be present today; the README states that some advanced capabilities are still in progress.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap mcp-go fills for Go services
MCP defines a wire protocol between an LLM application and a process that supplies data or actions. Implementing that protocol by hand means writing JSON-RPC framing, capability negotiation, tool schema serialisation and request dispatch. mcp-go exists so a Go developer does not have to. The README describes it as high-level and easy to use, and the opening example is roughly twenty lines: create a server, register one tool named hello_world, start it on stdio. The intended audience is Go engineers who already have a service, a database client or an internal API and want an LLM client to call into it. The README frames MCP servers as roughly analogous to web APIs, with Resources compared to GET endpoints, Tools to POST endpoints, and Prompts as reusable interaction templates. That framing is the clearest statement of scope in the material: this is a server-side library, not a general purpose agent framework.
What the server API actually does
The central type is created by server.NewMCPServer, which takes a server name, a version string and a variadic list of options. Two options appear in the README examples: server.WithToolCapabilities(false) and server.WithRecovery(). The first is a capability flag passed at construction; the second installs panic recovery, which matters because a tool handler that panics would otherwise take down the process serving the client. Tools are declared with mcp.NewTool and a chain of option functions. mcp.WithDescription sets the tool description, mcp.WithString and mcp.WithNumber declare parameters, mcp.Required marks a parameter mandatory, mcp.Enum constrains a string parameter to a fixed set, and mcp.Description documents an individual parameter. Registration is a single call, s.AddTool(tool, handler). The handler signature is func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error). Inside it, the README uses typed accessors: request.RequireString, request.RequireFloat. Results are constructed with mcp.NewToolResultText for a text payload and mcp.NewToolResultError for a failure. Note that a handler returning NewToolResultError with a nil error is the documented way to report a tool-level failure, which is distinct from returning a Go error. The README does not explain that distinction explicitly, and it is the kind of thing worth confirming against the package documentation before you build error handling around it.
Getting a server running: install and first launch
Installation is a single Go module fetch: go get github.com/mark3labs/mcp-go. The README does not pin a minimum Go version, so check go.mod in the repository if your toolchain is old. A minimal server needs two imports, github.com/mark3labs/mcp-go/mcp and github.com/mark3labs/mcp-go/server. Construct the server with server.NewMCPServer("Demo", "1.0.0", server.WithToolCapabilities(false)), register at least one tool, then call server.ServeStdio(s) and print the returned error. The README's calculator example adds server.WithRecovery() alongside the tool capability option and shows the full handler, including argument extraction with RequireString and RequireFloat and a divide-by-zero guard that returns mcp.NewToolResultError("cannot divide by zero"). The README also has a Transports section in its table of contents, and it lists OAuth Protected Resource Metadata, session management, request hooks and tool handler middleware as extras. Those sections are named but their contents are not in the material supplied here, so the exact configuration keys for OAuth and for non-stdio transports cannot be confirmed from this text. Treat the table of contents as a map of what exists, not as documentation of how to configure it.
Sessions, hooks and middleware as extension points
The README's extras list is where the library stops being a thin wrapper. Session management is broken into basic session handling, per-session tools, tool filtering and working with context. Per-session tools and tool filtering together imply that the tool set a client sees can vary by connection rather than being fixed at startup, which is a meaningful design difference from a static registry. Request hooks and tool handler middleware give two separate interception points: hooks at the request level, middleware around the tool handler. The distinction matters if you need to log every incoming request versus wrap only tool execution. None of these mechanisms are shown with code in the supplied README, so the API shape is unverified here. The Regenerating Server Code entry in the table of contents suggests some part of the server surface is generated, which is relevant to anyone who plans to fork or patch the library. If you intend to depend on per-session tool filtering, budget time to read the source, because the README names the feature without demonstrating it.
Protocol version coverage and the completeness caveat
The README states that mcp-go implements MCP specification version 2025-11-25, with backward compatibility for 2025-06-18, 2025-03-26 and 2024-11-05. Four supported revisions is a concrete claim and a useful one: it means an older client is not automatically out of scope. The same README undercuts the completeness claim in two places. The key features list says the project aims to provide a full implementation of the core MCP specification, with the word aims carrying an explicit footnote that reads emphasis on aims. A warning block then states that MCP Go is under active development, as is the MCP specification itself, and that core features are working but some advanced capabilities are still in progress. That is unusually honest for a README and it should shape how you evaluate the project. The release history is consistent with the warning: v0.58.0 in August 2026, a v1.0.0-beta.1 two days later, and v1.0.0 in early September 2026. Reaching 1.0.0 signals API stability intent, but the pre-1.0 line ran long and the beta window before the stable tag was short. If your integration depends on a capability the README does not demonstrate, assume it may be one of the advanced features still in progress.
Where mcp-go is the wrong choice
The most obvious mismatch is direction. Everything shown here is server construction: NewMCPServer, AddTool, ServeStdio. If you are building the LLM application side and need to connect out to third-party MCP servers, the README as supplied does not demonstrate a client. A second mismatch is language. If your existing tooling is Python or TypeScript, adopting mcp-go means running a separate Go binary alongside it and wiring that binary into the client, which adds a process boundary and a deployment artifact. A third case is a throwaway script. The library's value is in protocol handling and session management; for a single tool invoked once, the boilerplate of a server, a tool declaration and a handler may cost more than it saves. Finally, the README's own warning is the strongest reason to hesitate: if your requirement list includes a capability that is not in the examples, you cannot conclude from this material that it is implemented. The absence of an explicit feature matrix in the README is a real gap for anyone doing adoption due diligence.
How this differs from a hand-rolled JSON-RPC layer
The alternative to mcp-go is not another Go MCP library so much as writing the protocol layer yourself against the MCP specification. The difference in approach is concrete. Hand-rolling means you own the JSON-RPC envelope, the initialise handshake, capability advertisement, tool schema generation and dispatch by tool name. With mcp-go, schema generation comes from the option chain on mcp.NewTool, and dispatch comes from s.AddTool mapping a name to a handler. The typed accessors are the second difference: RequireString and RequireFloat return an error rather than forcing you to assert types out of a generic map, so argument validation happens at the call site. The trade-off is that you inherit the library's opinions about handler signatures and result construction. If you need a transport or a protocol revision the library does not cover, you are either contributing upstream or bypassing the library. For a standard stdio server exposing a handful of tools, the library removes a category of work that has nothing to do with your actual product. For anything unusual at the protocol level, that same abstraction becomes the thing you fight.
Licence, maintenance and upgrade cost
mcp-go is MIT licensed, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is a permissive arrangement and it is the same licence most Go infrastructure libraries use, so it rarely blocks adoption. This is not legal advice; read the LICENSE file in the repository if the distinction matters to your organisation. On maintenance, the release cadence visible in the material is rapid: v0.58.0, then v1.0.0-beta.1, then v1.0.0 within about three weeks. Rapid minor releases before 1.0.0 usually mean breaking changes were still landing, so anyone who adopted during the v0.5x line has already absorbed churn. Post-1.0.0 the expectation is that the exported API stabilises, but the README's statement that the MCP specification itself is under active development means protocol-level changes will keep arriving regardless of the library's own version policy. Practically, pin your module version in go.mod rather than tracking main, and read the release notes before bumping, because a specification revision can change behaviour even when the Go API looks unchanged.
Editorial conclusion
Adopt mcp-go if you are writing a Go process that must expose tools or resources to an MCP client and you want the protocol framing handled for you. Do not adopt it if you need a client-side SDK in another language, or if you require every capability in the MCP specification to be present today; the README states that some advanced capabilities are still in progress. Before committing, verify that the spec version you target matches the versions listed in the README, and check whether the transport you need is implemented rather than planned.
Community notes