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
Paul Carleton 67bd3f2e2b
mcp: add automatic DNS rebinding protection for localhost servers (#760)
## Summary

Add DNS rebinding protection that is automatically enabled when requests
arrive via localhost (127.0.0.1, [::1]). This protects against malicious
websites using DNS rebinding to interact with local MCP servers.

(note: this was a claude assisted PR, mostly wanted to see how difficult
passing this test would be for this SDK)

## Design Goal: Secure by Default

The primary goal is to make it difficult to run a localhost server
without these protections by mistake. There are other approaches that
could provide secure defaults (e.g., a helper for `ListenAndServe` that
does the localhost check), but using `http.LocalAddrContextKey` for
runtime detection seemed like the most backwards compatible approach and
least likely to be disabled by accident.

With this implementation:
- **No code changes required** - existing servers get protection
automatically
- **No opt-in needed** - protection activates based on the connection's
local address
- **Explicit opt-out** - users must deliberately set
`DisableLocalhostProtection: true`

## Changes

- Add `DisableLocalhostProtection` option to `StreamableHTTPOptions`
- Add `isLocalhostAddr` and `isLocalhostHost` helper functions  
- Validate Host header at start of `ServeHTTP`, rejecting non-localhost
Host headers with 403 Forbidden

## How it works

The protection uses `http.LocalAddrContextKey` to detect the
connection's local address at runtime. When a request arrives via
localhost (127.0.0.1 or [::1]), the handler validates that the Host
header also matches a localhost value. If not, the request is rejected
with 403 Forbidden.

This approach means:
- Protection is enabled for requests arriving via localhost, regardless
of whether the server listens on `127.0.0.1` or `0.0.0.0`
- Requests arriving via non-localhost IPs (e.g., external network
requests) are **not** affected

### Edge case: Reverse proxies

If a reverse proxy (e.g., Envoy, nginx) runs on the same host and
forwards requests to the MCP server via localhost while preserving the
original Host header, those requests would be rejected. In this case,
users should either:
1. Set `DisableLocalhostProtection: true`
2. Configure the proxy to rewrite the Host header to localhost

## Testing

- Added unit tests for `isLocalhostAddr` and `isLocalhostHost` helper
functions
- Added integration tests for the full protection flow
- Verified against the MCP conformance test suite:
  - `localhost-host-rebinding-rejected`: PASS
  - `localhost-host-valid-accepted`: PASS

## Related

- Spec:
https://modelcontextprotocol.io/specification/2025-11-25/basic/security_best_practices#local-mcp-server-compromise
- TypeScript SDK implementation: `localhostHostValidation()` middleware
- Conformance test: `dns-rebinding-protection` scenario

---------

Co-authored-by: Maciek Kisiel <mkisiel@google.com>
2026-02-13 16:23:32 +01:00
.devcontainer feat(devcontainer): Adds Dev Container configuration (#154) 2025-07-30 12:54:41 -04:00
.github mcp: finalize cleanup of Go 1.23, make Go version support explicit 2026-02-06 12:50:01 +01:00
auth auth: add OAuth 2.0 Protected Resource Metadata handler 2025-12-08 14:54:52 -05:00
conformance mcp: add automatic DNS rebinding protection for localhost servers (#760) 2026-02-13 16:23:32 +01:00
design mcp: introduce Requests (#267) 2025-08-12 17:49:50 -04:00
docs perf: add schema caching to avoid repeated reflection (#685) 2026-01-20 20:16:46 -05:00
examples examples: bind auth-middleware server to localhost by default (#784) 2026-02-11 10:02:17 +01:00
internal mcp: add automatic DNS rebinding protection for localhost servers (#760) 2026-02-13 16:23:32 +01:00
jsonrpc all: expose JSON-RPC error codes, and support URLElicitationRequired errors (#655) 2025-12-01 11:29:17 -05:00
mcp mcp: add automatic DNS rebinding protection for localhost servers (#760) 2026-02-13 16:23:32 +01:00
oauthex oauthex: fix content type check in getJSON (#721) 2025-12-12 09:44:26 -05:00
scripts examples: bind auth-middleware server to localhost by default (#784) 2026-02-11 10:02:17 +01:00
.gitignore .gitignore: add 2025-08-11 08:33:50 -04:00
CONTRIBUTING.md chore: update licensing to Apache 2.0 for new contributions (#750) 2026-01-28 09:17:41 +01:00
copyright_test.go mcp: update JSON marshaling to not HTML-escape messages (#769) 2026-01-30 17:13:30 +01:00
go.mod chore: update dependencies to newest versions, require Go 1.24 2026-01-29 10:30:43 +01:00
go.sum chore: update dependencies to newest versions, require Go 1.24 2026-01-29 10:30:43 +01:00
LICENSE chore: update licensing to Apache 2.0 for new contributions (#750) 2026-01-28 09:17:41 +01:00
README.md mcp: finalize cleanup of Go 1.23, make Go version support explicit 2026-02-06 12:50:01 +01:00
ROADMAP.md chore: add ROADMAP.md (#788) 2026-02-13 10:39:53 +01:00
SECURITY.md SECURITY.md: add a security policy (#682) 2025-12-05 16:00:32 -05:00

MCP Go SDK

Open in GitHub Codespaces

PkgGoDev

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.2.0+ 2025-06-18 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

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.