Model or dataset
mark3labs/mcp-go avatar
mark3labs/mcp-go

mark3labs/mcp-go: a Go implementation of the Model Context Protocol

A Go implementation of the Model Context Protocol (MCP), enabling seamless integration between LLM applications and external data sources and tools.

9,151 stars890 forksGoMIT

At a glance

What is it?
mcp-go gives Go developers a high-level way to build MCP servers and clients, with tool registration, stdio and HTTP transports, and session hooks. It is a young library at v1.0.0, and the README is honest that the specification is still moving.
Who is it for?
Adopt mcp-go when you want to expose Go functions as MCP tools without writing protocol plumbing yourself, and when stdio or the in-process server is enough. Do not adopt it if you need a stability commitment the project does not make: the README calls the library and the specification both under development, and the module pins Go 1.25.5.
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 last received commits 6 days ago.
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 29, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What mcp-go solves for Go teams wiring tools into LLM clients

The Model Context Protocol defines how an LLM application discovers and calls external capabilities. Implementing that by hand means framing JSON-RPC messages, tracking capability negotiation, and mapping request payloads onto Go functions. mcp-go exists to remove that layer. The README describes it as "a Go implementation of the Model Context Protocol (MCP)", and the stated aim is to be "high-level and easy to use".

The audience is narrow and specific: Go engineers who already have internal services, filesystems or data stores and want an MCP client to reach them. The README frames MCP servers as exposing data through Resources, functionality through Tools, and interaction patterns through Prompts, and compares Resources to GET endpoints and Tools to POST endpoints. If you are writing a TypeScript or Python agent and only need a client, this library is not aimed at you, even though a client/ directory exists in the repository. The primary path in the documentation is server construction.

The repository also ships a mcptest/ package and an e2e/ directory, which suggests the maintainers treat testability as part of the library rather than something you bolt on. The README does not document what mcptest/ contains.

How mcp-go works: server, tool registration and handlers

A server is created with server.NewMCPServer, which takes a name, a version and functional options. The README example passes server.WithToolCapabilities(false) and, in the quickstart, server.WithRecovery(). Tools are declared with mcp.NewTool and a chain of mcp.WithString, mcp.WithNumber, mcp.Required, mcp.Description and mcp.Enum calls. Each tool is bound to a handler with s.AddTool.

The handler signature is func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error). Arguments are read through typed accessors such as request.RequireString and request.RequireFloat, which return an error when the argument is missing or the wrong type. Results are constructed with mcp.NewToolResultText or, for failures, mcp.NewToolResultError. That split matters: a tool-level error is returned as a normal result the model can read, while a Go error propagates differently. The quickstart demonstrates this by returning mcp.NewToolResultError("cannot divide by zero") rather than a Go error.

Transport is chosen at the end. server.ServeStdio(s) runs the server over standard input and output, which is the pattern most desktop MCP clients expect. The README's Extras section lists Transports, OAuth Protected Resource Metadata, Session Management, Request Hooks and Tool Handler Middleware. Session management includes per-session tools, tool filtering and working with context, so a single server process can present different tools to different connections. Hooks and middleware give you interception points around requests and tool calls. The README does not spell out the execution order between hooks and middleware.

Installing mcp-go and building a first tool

Installation is a single module fetch. The module path is github.com/mark3labs/mcp-go, and go.mod declares go 1.25.5, so a toolchain at least that new is required.

bash
go get github.com/mark3labs/mcp-go

The README quickstart builds a calculator tool. The server is created with recovery enabled so a panicking handler does not take the process down, and the tool declares an operation plus two numbers.

go
s := server.NewMCPServer(
    "Calculator Demo",
    "1.0.0",
    server.WithToolCapabilities(false),
    server.WithRecovery(),
)

calculatorTool := mcp.NewTool("calculate",
    mcp.WithDescription("Perform basic arithmetic operations"),
    mcp.WithString("operation",
        mcp.Required(),
        mcp.Description("The operation to perform (add, subtract, multiply, divide)"),
        mcp.Enum("add", "subtract", "multiply", "divide"),
    ),
    mcp.WithNumber("x", mcp.Required(), mcp.Description("First number")),
    mcp.WithNumber("y", mcp.Required(), mcp.Description("Second number")),
)

The handler reads arguments with the typed accessors and returns either a text result or a tool error. Note that the divide branch returns a tool error instead of a Go error, which keeps the failure visible to the model.

go
s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
    op, err := request.RequireString("operation")
    if err != nil {
        return mcp.NewToolResultError(err.Error()), nil
    }
    x, err := request.RequireFloat("x")
    if err != nil {
        return mcp.NewToolResultError(err.Error()), nil
    }
    y, err := request.RequireFloat("y")
    if err != nil {
        return mcp.NewToolResultError(err.Error()), nil
    }
    if op == "divide" && y == 0 {
        return mcp.NewToolResultError("cannot divide by zero"), nil
    }
    return mcp.NewToolResultText(fmt.Sprintf("%.2f", x+y)), nil
})

Finally the server is started over stdio. Once that call returns, the process is serving MCP on stdin and stdout, so anything else you print to stdout will corrupt the stream.

go
if err := server.ServeStdio(s); err != nil {
    fmt.Printf("Server error: %v\n", err)
}

The repository's examples/ directory is the better starting point for anything beyond this: examples/typed_tools/, examples/structured_input_and_output/, examples/elicitation/, examples/sampling_server/ and examples/in_process/ each cover a different surface. The README does not walk through any of them.

Where mcp-go gets in your way

The README carries its own warning: "MCP Go is under active development, as is the MCP specification itself. Core features are working but some advanced capabilities are still in progress." The feature list marks completeness with an asterisk and the parenthetical "(\*emphasis on *aims*)". Treat that as the maintainers telling you the surface is not frozen, even at v1.0.0.

The version matrix is the practical consequence. mcp-go implements specification 2025-11-25 and keeps backward compatibility for 2025-06-18, 2025-03-26 and 2024-11-05. If your MCP client negotiates an older revision, behaviour will differ from a client on the newest one, and the README does not enumerate which features degrade across those revisions.

Two smaller constraints are easy to miss. First, go.mod requires Go 1.25.5, which will rule out older build images and CI runners until they are updated. Second, stdio transport means stdout is the protocol channel; any library in your process that writes to stdout will break the session. The README does not document a mitigation.

Finally, a library like this is the wrong tool when your integration is a single HTTP call to one service. The MCP layer adds a client, a protocol handshake and a capability model. For one endpoint behind one API key, a plain handler is less machinery.

mcp-go against the official Go SDK and FastMCP

The relevant comparison is with the official Go SDK for MCP, which is the other Go option people search for. The difference is one of positioning rather than protocol: mcp-go is a third-party implementation maintained under mark3labs, while the official SDK is maintained alongside the specification. That matters when a new revision lands, because the official SDK has a shorter path from specification change to release. mcp-go's answer is the compatibility range it advertises, covering four specification revisions at once.

The second comparison is FastMCP, which is Python. There the difference is the language runtime, not the API shape. If your existing services are Go binaries you want to ship as a single static executable, mcp-go keeps you in one toolchain and one build. If your team already lives in Python and wants decorator-style tool definitions, FastMCP is the shorter route and mcp-go offers nothing there.

Within Go, the deciding question is how much you depend on the newest protocol features. mcp-go bundles session management, request hooks, tool handler middleware, OAuth Protected Resource Metadata and a client package in one module, which is more than a bare protocol implementation. The README does not publish a feature-by-feature comparison against either alternative, so the honest way to choose is to build the same tool against both and diff the handler code.

Maintenance, licensing and the cost of upgrading

The repository is not archived. The last push was on 2026-09-02, and v1.0.0 was released the same day, following v1.0.0-beta.1 on 2026-08-12 and v0.58.0 on 2026-08-11. The jump from 0.58.0 to 1.0.0 within a month, with a beta in between, is a signal about how quickly the public API moved in that window. If you adopted a 0.x version, budget for a migration pass rather than a version bump.

Licensing is MIT, which permits commercial and closed-source use with the usual requirement to preserve the copyright notice and licence text. That is a permissive baseline and creates no copyleft obligation on your own code. It says nothing about the MCP specification itself or about any trademark; for those questions the LICENSE file and the specification site are the sources, not this article.

The dependency list in go.mod is short: google/jsonschema-go, google/uuid, rogpeppe/go-internal, santhosh-tekuri/jsonschema/v6, spf13/cast, stretchr/testify and yosida95/uritemplate/v3, plus indirect entries for x/text, x/tools and yaml.v3. A small dependency surface keeps the upgrade cost of the library itself low. The recurring cost is the specification: each new revision the library adopts is a chance for your handler behaviour to shift, and the README does not promise a deprecation window.

Editorial conclusion

Adopt mcp-go when you want to expose Go functions as MCP tools without writing protocol plumbing yourself, and when stdio or the in-process server is enough. Do not adopt it if you need a stability commitment the project does not make: the README calls the library and the specification both under development, and the module pins Go 1.25.5. Verify first which MCP specification revision your client negotiates, since mcp-go implements 2025-11-25 with backward compatibility for 2025-06-18, 2025-03-26 and 2024-11-05, and check the examples directory for a transport that matches your deployment.

Frequently asked questions

What does mark3labs/mcp-go do exactly?

It is a Go implementation of the Model Context Protocol, letting you build servers that expose Resources, Tools and Prompts to LLM applications. The README describes it as high-level, with the protocol details and server management handled for you.

Is mcp-go the same as the official Go SDK?

No. mcp-go is a third-party implementation maintained under mark3labs, while the official SDK is maintained alongside the specification. The README does not compare the two feature by feature.

How does mcp-go compare to FastMCP?

FastMCP is Python and mcp-go is Go, so the difference is the runtime and toolchain rather than the protocol. mcp-go keeps a Go service in one build; FastMCP suits teams already working in Python.

What is MCP versus a plain API?

The README compares MCP Resources to GET endpoints and Tools to POST endpoints, but the protocol is designed specifically for LLM interactions. A plain API does not carry capability negotiation or tool discovery.

What does MCP stand for?

Model Context Protocol. The README links to modelcontextprotocol.io and describes it as a way to expose data and functionality to LLM applications in a standardized way.

Does ChatGPT use MCP?

The mcp-go README does not describe which LLM applications consume MCP servers, so it cannot answer this. It only covers how to build MCP servers and clients in Go.

Official sources

  1. License: MIT
  2. mark3labs/mcp-go on GitHub
  3. Project website
  4. README
  5. Releases
For maintainers

Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mark3labs-mcp-go.svg)](https://hysenlabs.com/projects/mark3labs-mcp-go)
Community notes

Community notes