Skip to content

Commit 2fde524

Browse files
Merge branch 'main' into addCompletion
2 parents 2f08b61 + bc59932 commit 2fde524

File tree

21 files changed

+487
-78
lines changed

21 files changed

+487
-78
lines changed

.github/workflows/readme-check.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: README Check
2+
on:
3+
workflow_dispatch:
4+
pull_request:
5+
paths:
6+
- 'internal/readme/**'
7+
- 'README.md'
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
readme-check:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Set up Go
17+
uses: actions/setup-go@v5
18+
- name: Check out code
19+
uses: actions/checkout@v4
20+
- name: Check README is up-to-date
21+
run: |
22+
cd internal/readme
23+
make
24+
if [ -n "$(git status --porcelain)" ]; then
25+
echo "ERROR: README.md is not up-to-date!"
26+
echo ""
27+
echo "The README.md file differs from what would be generated by running 'make' in internal/readme/."
28+
echo "Please update internal/readme/README.src.md instead of README.md directly,"
29+
echo "then run 'make' in the internal/readme/ directory to regenerate README.md."
30+
echo ""
31+
echo "Changes:"
32+
git status --porcelain
33+
echo ""
34+
echo "Diff:"
35+
git diff
36+
exit 1
37+
fi
38+
echo "README.md is up-to-date"

.github/workflows/test.yml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,25 @@ on:
88

99
permissions:
1010
contents: read
11-
11+
1212
jobs:
13+
lint:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Set up Go
17+
uses: actions/setup-go@v5
18+
- name: Check out code
19+
uses: actions/checkout@v4
20+
- name: Check formatting
21+
run: |
22+
unformatted=$(gofmt -l .)
23+
if [ -n "$unformatted" ]; then
24+
echo "The following files are not properly formatted:"
25+
echo "$unformatted"
26+
exit 1
27+
fi
28+
echo "All Go files are properly formatted"
29+
1330
test:
1431
runs-on: ubuntu-latest
1532
strategy:

CONTRIBUTING.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ This process is similar to the [Go proposal
6868
process](https://github.com/golang/proposal), but is necessarily lighter weight
6969
to accommodate the greater rate of change expected for the SDK.
7070

71+
### Design discussion
72+
73+
For open ended design discussion (anything that doesn't fall into the issue
74+
categories above), use [GitHub
75+
Discussions](https://github.com/modelcontextprotocol/go-sdk/discussions).
76+
Ideally, each discussion should be focused on one aspect of the design. For
77+
example: Tool Binding and Session APIs would be two separate discussions.
78+
When discussions reach a consensus, they should be promoted into proposals.
79+
7180
## Contributing code
7281

7382
The project uses GitHub pull requests (PRs) to review changes.
@@ -96,6 +105,19 @@ copyright header following the format below:
96105
// license that can be found in the LICENSE file.
97106
```
98107

108+
### Updating the README
109+
110+
The top-level `README.md` file is generated from `internal/readme/README.src.md`
111+
and should not be edited directly. To update the README:
112+
113+
1. Make your changes to `internal/readme/README.src.md`
114+
2. Run `make` in the `internal/readme/` directory to regenerate `README.md`
115+
3. Commit both files together
116+
117+
The CI system will automatically check that the README is up-to-date by running
118+
`make` and verifying no changes result. If you see a CI failure about the
119+
README being out of sync, follow the steps above to regenerate it.
120+
99121
## Code of conduct
100122

101123
This project follows the [Go Community Code of Conduct](https://go.dev/conduct).

README.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
<!-- Autogenerated by weave; DO NOT EDIT -->
22
# MCP Go SDK
33

4-
<!-- TODO: update pkgsite links here to point to the modelcontextprotocol
5-
module, once it exists. -->
6-
7-
[![PkgGoDev](https://pkg.go.dev/badge/golang.org/x/tools)](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk)
4+
[![PkgGoDev](https://pkg.go.dev/badge/github.com/modelcontextprotocol/go-sdk)](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk)
85

96
This repository contains an unreleased implementation of the official Go
107
software development kit (SDK) for the Model Context Protocol (MCP).
@@ -15,6 +12,18 @@ proposals, but don't use it in real projects. See the issue tracker for known
1512
issues and missing features. We aim to release a stable version of the SDK in
1613
August, 2025.
1714

15+
## Design
16+
17+
The design doc for this SDK is at [design.md](./design/design.md), which was
18+
initially reviewed at
19+
[modelcontextprotocol/discussions/364](https://github.com/orgs/modelcontextprotocol/discussions/364).
20+
21+
Further design discussion should occur in
22+
[issues](https://github.com/modelcontextprotocol/go-sdk/issues) (for concrete
23+
proposals) or
24+
[discussions](https://github.com/modelcontextprotocol/go-sdk/discussions) for
25+
open-ended discussion. See CONTRIBUTING.md for details.
26+
1827
## Package documentation
1928

2029
The SDK consists of two importable packages:
@@ -95,14 +104,18 @@ type HiParams struct {
95104

96105
func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[HiParams]) (*mcp.CallToolResultFor[any], error) {
97106
return &mcp.CallToolResultFor[any]{
98-
Content: []mcp.Content{&mcp.TextContent{Text: "Hi " + params.Name}},
107+
Content: []mcp.Content{&mcp.TextContent{Text: "Hi " + params.Arguments.Name}},
99108
}, nil
100109
}
101110

102111
func main() {
103112
// Create a server with a single tool.
104113
server := mcp.NewServer("greeter", "v1.0.0", nil)
105-
server.AddTools(mcp.NewServerTool("greet", "say hi", SayHi))
114+
server.AddTools(
115+
mcp.NewServerTool("greet", "say hi", SayHi, mcp.Input(
116+
mcp.Property("name", mcp.Description("the name of the person to greet")),
117+
)),
118+
)
106119
// Run the server over stdin/stdout, until the client disconnects
107120
if err := server.Run(context.Background(), mcp.NewStdioTransport()); err != nil {
108121
log.Fatal(err)
@@ -112,15 +125,6 @@ func main() {
112125

113126
The `examples/` directory contains more example clients and servers.
114127

115-
## Design
116-
117-
The design doc for this SDK is at [design.md](./design/design.md), which was
118-
initially reviewed at
119-
[modelcontextprotocol/discussions/364](https://github.com/orgs/modelcontextprotocol/discussions/364).
120-
121-
Further design discussion should occur in GitHub issues. See CONTRIBUTING.md
122-
for details.
123-
124128
## Acknowledgements
125129

126130
Several existing Go MCP SDKs inspired the development and design of this

design/design.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,10 @@ server.AddReceivingMiddleware(withLogging)
470470
471471
**Differences from mcp-go**: Version 0.26.0 of mcp-go defines 24 server hooks. Each hook consists of a field in the `Hooks` struct, a `Hooks.Add` method, and a type for the hook function. These are rarely used. The most common is `OnError`, which occurs fewer than ten times in open-source code.
472472
473+
#### Rate Limiting
474+
475+
Rate limiting can be configured using middleware. Please see [examples/rate-limiting](<https://github.com/modelcontextprotocol/go-sdk/tree/main/examples/rate-limiting>] for an example on how to implement this.
476+
473477
### Errors
474478
475479
With the exception of tool handler errors, protocol errors are handled transparently as Go errors: errors in server-side feature handlers are propagated as errors from calls from the `ClientSession`, and vice-versa.
@@ -863,7 +867,7 @@ type ServerOptions struct {
863867
}
864868
```
865869
866-
#### Securty Considerations
870+
#### Security Considerations
867871
868872
Implementors of the CompletionHandler MUST adhere to the following security guidelines:
869873
@@ -952,7 +956,7 @@ In addition to the `List` methods, the SDK provides an iterator method for each
952956
953957
# Governance and Community
954958
955-
While the sections above propose an initial implementation of the Go SDK, MCP is evolving rapidly. SDKs need to keep pace, by implementing changes to the spec, fixing bugs, and accomodating new and emerging use-cases. This section proposes how the SDK project can be managed so that it can change safely and transparently.
959+
While the sections above propose an initial implementation of the Go SDK, MCP is evolving rapidly. SDKs need to keep pace, by implementing changes to the spec, fixing bugs, and accommodating new and emerging use-cases. This section proposes how the SDK project can be managed so that it can change safely and transparently.
956960
957961
Initially, the Go SDK repository will be administered by the Go team and Anthropic, and they will be the Approvers (the set of people able to merge PRs to the SDK). The policies here are also intended to satisfy necessary constraints of the Go team's participation in the project.
958962
@@ -980,7 +984,7 @@ A proposal is an issue that proposes a new API for the SDK, or a change to the s
980984
981985
Proposals that are straightforward and uncontroversial may be approved based on GitHub discussion. However, proposals that are deemed to be sufficiently unclear or complicated will be deferred to a regular steering meeting (see below).
982986
983-
This process is similar to the [Go proposal process](https://github.com/golang/proposal), but is necessarily lighter weight to accomodate the greater rate of change expected for the SDK.
987+
This process is similar to the [Go proposal process](https://github.com/golang/proposal), but is necessarily lighter weight to accommodate the greater rate of change expected for the SDK.
984988
985989
### Steering meetings
986990

examples/hello/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type HiArgs struct {
2525
func SayHi(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[HiArgs]) (*mcp.CallToolResultFor[struct{}], error) {
2626
return &mcp.CallToolResultFor[struct{}]{
2727
Content: []mcp.Content{
28-
&mcp.TextContent{Text: "Hi " + params.Name},
28+
&mcp.TextContent{Text: "Hi " + params.Arguments.Name},
2929
},
3030
}, nil
3131
}

examples/rate-limiting/go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module github.com/modelcontextprotocol/go-sdk/examples/rate-limiting
2+
3+
go 1.25
4+
5+
require (
6+
github.com/modelcontextprotocol/go-sdk v0.0.0-20250625185707-09181c2c2e89
7+
golang.org/x/time v0.12.0
8+
)

examples/rate-limiting/go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
2+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
3+
github.com/modelcontextprotocol/go-sdk v0.0.0-20250625185707-09181c2c2e89 h1:kUGBYP25FTv3ZRBhLT4iQvtx4FDl7hPkWe3isYrMxyo=
4+
github.com/modelcontextprotocol/go-sdk v0.0.0-20250625185707-09181c2c2e89/go.mod h1:DcXfbr7yl7e35oMpzHfKw2nUYRjhIGS2uou/6tdsTB0=
5+
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
6+
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
7+
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
8+
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=

examples/rate-limiting/main.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2025 The Go MCP SDK Authors. All rights reserved.
2+
// Use of this source code is governed by an MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"context"
9+
"errors"
10+
"time"
11+
12+
"github.com/modelcontextprotocol/go-sdk/mcp"
13+
"golang.org/x/time/rate"
14+
)
15+
16+
// GlobalRateLimiterMiddleware creates a middleware that applies a global rate limit.
17+
// Every request attempting to pass through will try to acquire a token.
18+
// If a token cannot be acquired immediately, the request will be rejected.
19+
func GlobalRateLimiterMiddleware[S mcp.Session](limiter *rate.Limiter) mcp.Middleware[S] {
20+
return func(next mcp.MethodHandler[S]) mcp.MethodHandler[S] {
21+
return func(ctx context.Context, session S, method string, params mcp.Params) (mcp.Result, error) {
22+
if !limiter.Allow() {
23+
return nil, errors.New("JSON RPC overloaded")
24+
}
25+
return next(ctx, session, method, params)
26+
}
27+
}
28+
}
29+
30+
// PerMethodRateLimiterMiddleware creates a middleware that applies rate limiting
31+
// on a per-method basis.
32+
// Methods not specified in limiters will not be rate limited by this middleware.
33+
func PerMethodRateLimiterMiddleware[S mcp.Session](limiters map[string]*rate.Limiter) mcp.Middleware[S] {
34+
return func(next mcp.MethodHandler[S]) mcp.MethodHandler[S] {
35+
return func(ctx context.Context, session S, method string, params mcp.Params) (mcp.Result, error) {
36+
if limiter, ok := limiters[method]; ok {
37+
if !limiter.Allow() {
38+
return nil, errors.New("JSON RPC overloaded")
39+
}
40+
}
41+
return next(ctx, session, method, params)
42+
}
43+
}
44+
}
45+
46+
func main() {
47+
server := mcp.NewServer("greeter1", "v0.0.1", nil)
48+
server.AddReceivingMiddleware(GlobalRateLimiterMiddleware[*mcp.ServerSession](rate.NewLimiter(rate.Every(time.Second/5), 10)))
49+
server.AddReceivingMiddleware(PerMethodRateLimiterMiddleware[*mcp.ServerSession](map[string]*rate.Limiter{
50+
"callTool": rate.NewLimiter(rate.Every(time.Second), 5), // once a second with a burst up to 5
51+
"listTools": rate.NewLimiter(rate.Every(time.Minute), 20), // once a minute with a burst up to 20
52+
}))
53+
// Run Server logic.
54+
}

examples/sse/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type SayHiParams struct {
2222
func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[SayHiParams]) (*mcp.CallToolResultFor[any], error) {
2323
return &mcp.CallToolResultFor[any]{
2424
Content: []mcp.Content{
25-
&mcp.TextContent{Text: "Hi " + params.Name},
25+
&mcp.TextContent{Text: "Hi " + params.Arguments.Name},
2626
},
2727
}, nil
2828
}

0 commit comments

Comments
 (0)