Skip to content

Commit 8dd9a81

Browse files
authored
mcp: panic if AddTool method is given a nil InputSchema (#157)
The spec requires an input schema for every tool.
1 parent 94b88a2 commit 8dd9a81

File tree

3 files changed

+14
-8
lines changed

3 files changed

+14
-8
lines changed

mcp/mcp_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ func TestCancellation(t *testing.T) {
659659
return nil, nil
660660
}
661661
_, cs := basicConnection(t, func(s *Server) {
662-
s.AddTool(&Tool{Name: "slow"}, slowRequest)
662+
s.AddTool(&Tool{Name: "slow", InputSchema: &jsonschema.Schema{}}, slowRequest)
663663
})
664664
defer cs.Close()
665665

mcp/server.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"encoding/json"
1313
"fmt"
1414
"iter"
15-
"log"
1615
"maps"
1716
"net/url"
1817
"path/filepath"
@@ -132,13 +131,18 @@ func (s *Server) RemovePrompts(names ...string) {
132131
}
133132

134133
// AddTool adds a [Tool] to the server, or replaces one with the same name.
135-
// The tool's input schema must be non-nil.
136134
// The Tool argument must not be modified after this call.
135+
//
136+
// The tool's input schema must be non-nil. For a tool that takes no input,
137+
// or one where any input is valid, set [Tool.InputSchema] to the empty schema,
138+
// &jsonschema.Schema{}.
137139
func (s *Server) AddTool(t *Tool, h ToolHandler) {
138-
// TODO(jba): This is a breaking behavior change. Add before v0.2.0?
139140
if t.InputSchema == nil {
140-
log.Printf("mcp: tool %q has a nil input schema. This will panic in a future release.", t.Name)
141-
// panic(fmt.Sprintf("adding tool %q: nil input schema", t.Name))
141+
// This prevents the tool author from forgetting to write a schema where
142+
// one should be provided. If we papered over this by supplying the empty
143+
// schema, then every input would be validated and the problem wouldn't be
144+
// discovered until runtime, when the LLM sent bad data.
145+
panic(fmt.Sprintf("adding tool %q: nil input schema", t.Name))
142146
}
143147
if err := addToolErr(s, t, h); err != nil {
144148
panic(err)

mcp/server_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"testing"
1212

1313
"github.com/google/go-cmp/cmp"
14+
"github.com/modelcontextprotocol/go-sdk/jsonschema"
1415
)
1516

1617
type testItem struct {
@@ -230,6 +231,7 @@ func TestServerPaginateVariousPageSizes(t *testing.T) {
230231
}
231232

232233
func TestServerCapabilities(t *testing.T) {
234+
tool := &Tool{Name: "t", InputSchema: &jsonschema.Schema{}}
233235
testCases := []struct {
234236
name string
235237
configureServer func(s *Server)
@@ -299,7 +301,7 @@ func TestServerCapabilities(t *testing.T) {
299301
{
300302
name: "With tools",
301303
configureServer: func(s *Server) {
302-
s.AddTool(&Tool{Name: "t"}, nil)
304+
s.AddTool(tool, nil)
303305
},
304306
wantCapabilities: &serverCapabilities{
305307
Completions: &completionCapabilities{},
@@ -313,7 +315,7 @@ func TestServerCapabilities(t *testing.T) {
313315
s.AddPrompt(&Prompt{Name: "p"}, nil)
314316
s.AddResource(&Resource{URI: "file:///r"}, nil)
315317
s.AddResourceTemplate(&ResourceTemplate{URITemplate: "file:///rt"}, nil)
316-
s.AddTool(&Tool{Name: "t"}, nil)
318+
s.AddTool(tool, nil)
317319
},
318320
serverOpts: ServerOptions{
319321
SubscribeHandler: func(ctx context.Context, sp *SubscribeParams) error {

0 commit comments

Comments
 (0)