Mirror of https://github.com/modelcontextprotocol/go-sdk — The official Go SDK for Model Context Protocol servers and clients. Maintained in collaboration with Google.
  • Go 99.7%
  • Shell 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Anton Dziatkovskii 810e6cb751
docs: make the protocol.md table of contents resolve (#1196)
Hi — I am an AI agent (Claude), working as Anton Dzyatkovsky's synthetic
co-founder. Same author as #1159 (dead MRTR links in `client.md`), same
genre, but this one has a cause worth naming rather than five links
worth patching.

**AI disclosure** (per
[AI_POLICY.md](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/AI_POLICY.md)):
this contribution — the investigation, the diff, the test and this
description — was written by Claude Code running autonomously; Anton is
the accountable human and reachable on this thread. Every measurement
quoted below was produced by running the thing, not inferred: the id
tables are scraped from the two rendered surfaces, the test's slug
function was checked against 31 of GitHub's real ids, and the failure
output is a real run against the pre-fix tree. Any reply from this
account is written the same way unless it says otherwise. I edited only
`internal/docs/**` and regenerated, per `AGENTS.md`.

## What is broken

Five table-of-contents entries in `docs/protocol.md` point at anchors
that no heading produces. They are dead on **both** surfaces — GitHub's
render of the file, and the published site.

| ToC entry links to | heading actually gets |
|---|---|
| `#discovery-(server/discover)` | `discovery-serverdiscover` |
| `#per-request-meta-keys` | `per-request-_meta-keys` |
| `#per-response-meta-keys` | `per-response-_meta-keys` |
| `#subscriptions-(subscriptions/listen)` |
`subscriptions-subscriptionslisten` |
| `#sse-transport-(legacy)` | `sse-transport-legacy` |

Right-hand column is scraped, not derived: `user-content-*` ids from
GitHub's rendered `docs/protocol.md`, and `<h* id=...>` from
`https://go.sdk.modelcontextprotocol.io/protocol`. Four of the five are
dead on the live site too; `sse-transport-legacy` is not in the
currently deployed build, so I could only confirm that one on GitHub.

## Why

`%toc` and the renderer slug the same heading by different rules, and
they disagree on exactly the punctuation these headings use:

* **weave** keeps `(`, `)` and `/`, and drops `_`
* **GitHub and python-markdown's `toc`** drop `(`, `)` and `/`, and keep
`_`

So the two agree on plain words and part ways the moment a heading
carries a method name in parentheses or a `_meta` field. This is a
class, not five typos: any future heading with those characters gets a
dead ToC entry, silently — the docs regenerate fine, `docs-check`
passes, and only a reader clicking the ToC finds out.

Someone already hit this, by hand: `internal/docs/server.src.md` links
to `protocol.md#subscriptions-subscriptionslisten`, i.e. the real
renderer id, not the one the ToC uses. That cross-link is the odd one
out today; the ToC is what is wrong.

## The fix

The characters have to leave the headings, because weave computes the
ToC and it is not in this repo. Each of the five sections already names
its RPC or field in its first sentence, so the heading loses nothing:

| was | becomes | the name is still in the first sentence |
|---|---|---|
| Discovery (``server/discover``) | **Discovery** | "the
`server/discover` RPC lets a client discover…" |
| Per-request ``_meta`` keys | **Per-request metadata keys** | "carries
these keys inside its `_meta` map" |
| Per-response ``_meta`` keys | **Per-response metadata keys** |
"servers SHOULD identify themselves on every response" |
| Subscriptions (``subscriptions/listen``) | **Subscriptions** |
"`subscriptions/listen` replaces the legacy…" |
| SSE Transport (legacy) | **Legacy SSE Transport** | "Before the
streamable transport, the 2024-11-05 spec…" |

Plus the one hand-written cross-link in `server.src.md`, updated to
`protocol.md#subscriptions`.

**The cost, stated plainly:** renaming a heading changes its id, so any
external deep link to `#discovery-serverdiscover` or
`#per-request-_meta-keys` breaks. Those ids are only reachable today by
someone who scrolled and copied the permalink — the ToC never produced
them — so I think the trade is worth it, but it is your call. **The
alternative is to fix the slug in weave**
(`golang.org/x/example/internal/cmd/weave`) and leave the headings
alone. I am happy to take it there instead if you would rather keep the
ids; say the word and I will close this.

## The guard

`internal/docs/toc_test.go` — reads the generated docs and checks every
`%toc` entry against the id its heading will actually get. No network,
no new dependency.

The slug function in it is validated, not asserted: run over all 31
headings of the current `docs/protocol.md`, it reproduces **31 of 31**
of the ids GitHub actually emitted for that file (and 30 of 31 on the
live site — the miss is the not-yet-deployed SSE section above).

Behaviour on the pre-fix tree, which is the point of it:

```
--- FAIL: TestTOCAnchorsResolve
    protocol.md: table-of-contents entry "Discovery (`server/discover`)" points at #discovery-(server/discover),
      which no heading produces (want #discovery-serverdiscover); drop (, ), / and _ from the heading
    ... and the other four, each named
```

All five, by name, with the id they should have had. On this branch it
passes.

## Runs

`go generate ./...` → no diff (idempotent, so `docs-check` stays green)
· `go vet ./...` clean · `go build ./...` clean · `go test ./...` → 14
packages ok, 0 failures, 26 without tests.

Docs and one new test only; no SDK code touched.

Co-authored-by: Anton Dziatkovskii <194927794+tonydzi@users.noreply.github.com>
2026-08-25 09:26:21 +02:00
.agents/skills/fix-bug chore: configure a simple AGENTS.md file and a skill for fixing GitHu… (#810) 2026-02-19 15:22:12 +01:00
.devcontainer feat(devcontainer): Adds Dev Container configuration (#154) 2025-07-30 12:54:41 -04:00
.github Disable scheduled nightly runs on forks (#1083) 2026-08-05 13:50:58 +02:00
auth auth: add ScopeFilter hook to AuthorizationCodeHandlerConfig (#1044) 2026-07-31 10:35:49 +02:00
conformance chore: update conformance (#1114) 2026-07-27 17:19:11 +02:00
design feat: multi-round-trip request implementation (SEP-2322) (#950) 2026-05-29 09:29:34 +02:00
docs docs: make the protocol.md table of contents resolve (#1196) 2026-08-25 09:26:21 +02:00
examples mcp: Allow registration of custom JSON-RPC methods (#956) 2026-06-25 23:13:17 +02:00
internal docs: make the protocol.md table of contents resolve (#1196) 2026-08-25 09:26:21 +02:00
jsonrpc all: expose JSON-RPC error codes, and support URLElicitationRequired errors (#655) 2025-12-01 11:29:17 -05:00
mcp mcp: add docs for tier 1 assessment (#1195) 2026-08-24 12:00:59 +02:00
oauthex oauthex: add MatchesResource helper (RFC 9728/8707 audience comparison) (#970) 2026-06-16 15:20:09 +02:00
scripts ci: fix nightly runs (#1086) 2026-07-14 16:24:47 +02:00
.gitignore .gitignore: add 2025-08-11 08:33:50 -04:00
AGENTS.md chore: configure a simple AGENTS.md file and a skill for fixing GitHu… (#810) 2026-02-19 15:22:12 +01:00
CONTRIBUTING.md mcp: add docs for tier 1 assessment (#1195) 2026-08-24 12:00:59 +02:00
copyright_test.go mcp: update JSON marshaling to not HTML-escape messages (#769) 2026-01-30 17:13:30 +01:00
go.mod feat: multi-round-trip request implementation (SEP-2322) (#950) 2026-05-29 09:29:34 +02:00
go.sum feat: multi-round-trip request implementation (SEP-2322) (#950) 2026-05-29 09:29:34 +02:00
LICENSE chore: update licensing to Apache 2.0 for new contributions (#750) 2026-01-28 09:17:41 +01:00
mkdocs.yaml Add documentation backed by mkdocs (#883) 2026-04-09 14:25:43 +02:00
README.md mcp: add documentation for new protocol version (#1019) 2026-06-23 17:07:38 +02:00
ROADMAP.md chore: add ROADMAP.md (#788) 2026-02-13 10:39:53 +01:00
SECURITY.md chore: update SECURITY.md to use GitHub Security Advisories (#809) 2026-02-18 22:24:53 +01:00

MCP Go SDK

Open in GitHub Codespaces

PkgGoDev OpenSSF Scorecard

This repository contains an implementation of the official Go software development kit (SDK) for the Model Context Protocol (MCP).

Package / Feature documentation

The SDK consists of several importable packages:

The SDK endeavors to implement the full MCP spec. The docs/ directory contains feature documentation, mapping the MCP spec to the packages above.

Version Compatibility

The following table shows which versions of the Go SDK support which versions of the MCP specification:

SDK Version Latest MCP Spec All Supported MCP Specs
v1.7.0+ 2026-07-28 2026-07-28, 2025-11-25*, 2025-06-18, 2025-03-26, 2024-11-05
v1.4.0 - v1.6.1 2025-11-25* 2025-11-25*, 2025-06-18, 2025-03-26, 2024-11-05
v1.2.0 - v1.3.1 2025-11-25** 2025-11-25**, 2025-06-18, 2025-03-26, 2024-11-05
v1.0.0 - v1.1.0 2025-06-18 2025-06-18, 2025-03-26, 2024-11-05

* Client side OAuth has experimental support.

** Partial support for 2025-11-25 (client side OAuth and Sampling with tools not available).

The roots, sampling, and logging features are deprecated as of protocol version 2026-07-28 by SEP-2577. The SDK continues to support them for compatibility during the deprecation window (at least twelve months). See the individual feature documentation for migration guidance.

New releases of the SDK target only supported versions of Go. See https://go.dev/doc/devel/release#policy for more information.

Getting started

To get started creating an MCP server, create an mcp.Server instance, add features to it, and then run it over an mcp.Transport. For example, this server adds a single simple tool, and then connects it to clients over stdin/stdout:

package main

import (
	"context"
	"log"

	"github.com/modelcontextprotocol/go-sdk/mcp"
)

type Input struct {
	Name string `json:"name" jsonschema:"the name of the person to greet"`
}

type Output struct {
	Greeting string `json:"greeting" jsonschema:"the greeting to tell to the user"`
}

func SayHi(ctx context.Context, req *mcp.CallToolRequest, input Input) (
	*mcp.CallToolResult,
	Output,
	error,
) {
	return nil, Output{Greeting: "Hi " + input.Name}, nil
}

func main() {
	// Create a server with a single tool.
	server := mcp.NewServer(&mcp.Implementation{Name: "greeter", Version: "v1.0.0"}, nil)
	mcp.AddTool(server, &mcp.Tool{Name: "greet", Description: "say hi"}, SayHi)
	// Run the server over stdin/stdout, until the client disconnects.
	if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil {
		log.Fatal(err)
	}
}

To communicate with that server, create an mcp.Client and connect it to the corresponding server, by running the server command and communicating over its stdin/stdout:

package main

import (
	"context"
	"log"
	"os/exec"

	"github.com/modelcontextprotocol/go-sdk/mcp"
)

func main() {
	ctx := context.Background()

	// Create a new client, with no features.
	client := mcp.NewClient(&mcp.Implementation{Name: "mcp-client", Version: "v1.0.0"}, nil)

	// Connect to a server over stdin/stdout.
	transport := &mcp.CommandTransport{Command: exec.Command("myserver")}
	session, err := client.Connect(ctx, transport, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer session.Close()

	// Call a tool on the server.
	params := &mcp.CallToolParams{
		Name:      "greet",
		Arguments: map[string]any{"name": "you"},
	}
	res, err := session.CallTool(ctx, params)
	if err != nil {
		log.Fatalf("CallTool failed: %v", err)
	}
	if res.IsError {
		log.Fatal("tool failed")
	}
	for _, c := range res.Content {
		log.Print(c.(*mcp.TextContent).Text)
	}
}

The examples/ directory contains more example clients and servers.

Contributing

We welcome contributions to the SDK! Please see CONTRIBUTING.md for details of how to contribute.

Acknowledgements / Alternatives

Several third party Go MCP SDKs inspired the development and design of this official SDK, and continue to be viable alternatives, notably mcp-go, originally authored by Ed Zynda. We are grateful to Ed as well as the other contributors to mcp-go, and to authors and contributors of other SDKs such as mcp-golang and go-mcp. Thanks to their work, there is a thriving ecosystem of Go MCP clients and servers.

License

This project is licensed under Apache 2.0 for new contributions, with existing code under MIT - see the LICENSE file for details.