Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/server/auth-middleware/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
)

require (
github.com/google/jsonschema-go v0.2.3 // indirect
github.com/google/jsonschema-go v0.2.4-0.20250922144851-e08864c65371 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
)

Expand Down
4 changes: 2 additions & 2 deletions examples/server/auth-middleware/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeD
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/jsonschema-go v0.2.3 h1:dkP3B96OtZKKFvdrUSaDkL+YDx8Uw9uC4Y+eukpCnmM=
github.com/google/jsonschema-go v0.2.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/google/jsonschema-go v0.2.4-0.20250922144851-e08864c65371 h1:e1VCqWtKpTYBOBhPcgGV5whTlMFpTbH5Ghm56wpxBsk=
github.com/google/jsonschema-go v0.2.4-0.20250922144851-e08864c65371/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
Expand Down
2 changes: 1 addition & 1 deletion examples/server/rate-limiting/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
)

require (
github.com/google/jsonschema-go v0.2.3 // indirect
github.com/google/jsonschema-go v0.2.4-0.20250922144851-e08864c65371 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
)

Expand Down
4 changes: 2 additions & 2 deletions examples/server/rate-limiting/go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/jsonschema-go v0.2.3 h1:dkP3B96OtZKKFvdrUSaDkL+YDx8Uw9uC4Y+eukpCnmM=
github.com/google/jsonschema-go v0.2.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/google/jsonschema-go v0.2.4-0.20250922144851-e08864c65371 h1:e1VCqWtKpTYBOBhPcgGV5whTlMFpTbH5Ghm56wpxBsk=
github.com/google/jsonschema-go v0.2.4-0.20250922144851-e08864c65371/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
Expand Down
73 changes: 47 additions & 26 deletions examples/server/toolschemas/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@
if err := json.Unmarshal(req.Params.Arguments, &input); err != nil {
return errf("failed to unmarshal arguments: %v", err), nil
}
if err := t.inputSchema.Validate(input); err != nil {
if err := validateStruct(input, t.inputSchema); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't right: once we re-marshal, we're no longer validating the original JSON.

For example, suppose the input contains "foo": 0, and the struct has omitempty for the Foo field, and "foo" is required. Then the original input is valid, but the re-marshalled input is not.

This is why we should expose helpers for this...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point!

return errf("invalid input: %v", err), nil
}
output := Output{Greeting: "Hi " + input.Name}
if err := t.outputSchema.Validate(output); err != nil {
if err := validateStruct(output, t.outputSchema); err != nil {
return errf("tool produced invalid output: %v", err), nil
}
outputJSON, err := json.Marshal(output)
Expand All @@ -75,6 +75,50 @@
}, nil
}

// validateStruct validates x against schema by first changing the struct to
// a map[string]any, then validating that.
func validateStruct(x any, res *jsonschema.Resolved) error {
data, err := json.Marshal(x)
if err != nil {
return err
}
var m map[string]any
if err := json.Unmarshal(data, &m); err != nil {
return err
}
return res.Validate(m)
}

var (
inputSchema = &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"name": {Type: "string", MaxLength: jsonschema.Ptr(10)},
},
}
outputSchema = &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"greeting": {Type: "string"},
},
}
)

func newManualGreeter() (*manualGreeter, error) {
resIn, err := inputSchema.Resolve(nil)
if err != nil {
return nil, err
}
resOut, err := outputSchema.Resolve(nil)
if err != nil {
return nil, err
}
return &manualGreeter{
inputSchema: resIn,
outputSchema: resOut,
}, nil
}

func main() {
server := mcp.NewServer(&mcp.Implementation{Name: "greeter"}, nil)

Expand All @@ -90,30 +134,7 @@
//
// We don't need to do all this work: below, we use jsonschema.For to start
// from the default schema.
var (
manual manualGreeter
err error
)
inputSchema := &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"name": {Type: "string", MaxLength: jsonschema.Ptr(10)},
},
}
manual.inputSchema, err = inputSchema.Resolve(nil)
if err != nil {
log.Fatal(err)
}
outputSchema := &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"greeting": {Type: "string"},
},
}
manual.outputSchema, err = outputSchema.Resolve(nil)
if err != nil {
log.Fatal(err)
}
manual, err := newManualGreeter()

Check failure on line 137 in examples/server/toolschemas/main.go

View workflow job for this annotation

GitHub Actions / lint

this value of err is never used (SA4006)
server.AddTool(&mcp.Tool{
Name: "manual greeting",
InputSchema: inputSchema,
Expand Down
31 changes: 31 additions & 0 deletions examples/server/toolschemas/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2025 The Go MCP SDK Authors. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package main

import (
"context"
"encoding/json"
"testing"

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

func TestGreet(t *testing.T) {
manual, err := newManualGreeter()
if err != nil {
t.Fatal(err)
}
res, err := manual.greet(context.Background(), &mcp.CallToolRequest{
Params: &mcp.CallToolParamsRaw{
Arguments: json.RawMessage(`{"name": "Bob"}`),
},
})
if err != nil {
t.Fatal(err)
}
if res.IsError {
t.Fatalf("tool error: %q", res.Content[0].(*mcp.TextContent).Text)
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.23.0
require (
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/google/go-cmp v0.7.0
github.com/google/jsonschema-go v0.2.3
github.com/google/jsonschema-go v0.2.4-0.20250922144851-e08864c65371
github.com/yosida95/uritemplate/v3 v3.0.2
golang.org/x/tools v0.34.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/jsonschema-go v0.2.3 h1:dkP3B96OtZKKFvdrUSaDkL+YDx8Uw9uC4Y+eukpCnmM=
github.com/google/jsonschema-go v0.2.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/google/jsonschema-go v0.2.4-0.20250922144851-e08864c65371 h1:e1VCqWtKpTYBOBhPcgGV5whTlMFpTbH5Ghm56wpxBsk=
github.com/google/jsonschema-go v0.2.4-0.20250922144851-e08864c65371/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
Expand Down
Loading