@@ -3,6 +3,7 @@ package mcp
3
3
import (
4
4
"encoding/json"
5
5
"fmt"
6
+ "github.com/invopop/jsonschema"
6
7
"reflect"
7
8
"regexp"
8
9
"strconv"
@@ -20,17 +21,16 @@ import (
20
21
type Server struct {
21
22
transport Transport
22
23
Tools map [string ]* ToolType
23
- serverCapabilities ServerCapabilities
24
24
serverInstructions * string
25
25
serverName string
26
26
serverVersion string
27
27
}
28
28
29
29
type ToolType struct {
30
- Name string
31
- Description string
32
- Handler func (CallToolRequestParamsArguments ) (ToolResponse , error )
33
- Arguments interface {}
30
+ Name string
31
+ Description string
32
+ Handler func (CallToolRequestParamsArguments ) (ToolResponse , error )
33
+ ToolInputSchema * jsonschema. Schema
34
34
}
35
35
36
36
type ToolResponse struct {
@@ -62,6 +62,31 @@ func (s *Server) Tool(name string, description string, handler any) error {
62
62
63
63
argumentType := handlerType .In (0 )
64
64
65
+ reflector := jsonschema.Reflector {
66
+ BaseSchemaID : "" ,
67
+ Anonymous : true ,
68
+ AssignAnchor : false ,
69
+ AllowAdditionalProperties : true ,
70
+ RequiredFromJSONSchemaTags : false ,
71
+ DoNotReference : true ,
72
+ ExpandedStruct : true ,
73
+ FieldNameTag : "" ,
74
+ IgnoredTypes : nil ,
75
+ Lookup : nil ,
76
+ Mapper : nil ,
77
+ Namer : nil ,
78
+ KeyNamer : nil ,
79
+ AdditionalFields : nil ,
80
+ CommentMap : nil ,
81
+ }
82
+
83
+ inputSchema := reflector .ReflectFromType (argumentType )
84
+ //marshalJSON, err := inputSchema.MarshalJSON()
85
+ //if err != nil {
86
+ // return err
87
+ //}
88
+ //println(string(marshalJSON))
89
+
65
90
wrappedHandler := func (arguments CallToolRequestParamsArguments ) (ToolResponse , error ) {
66
91
// We're going to json serialize the arguments and unmarshal them into the correct type
67
92
jsonArgs , err := json .Marshal (arguments )
@@ -97,21 +122,95 @@ func (s *Server) Tool(name string, description string, handler any) error {
97
122
}
98
123
99
124
s .Tools [name ] = & ToolType {
100
- Name : name ,
101
- Description : description ,
102
- Handler : wrappedHandler ,
125
+ Name : name ,
126
+ Description : description ,
127
+ Handler : wrappedHandler ,
128
+ ToolInputSchema : inputSchema ,
103
129
}
104
130
105
131
return nil
106
132
}
107
133
134
+ //func getToolInputSchema(argumentType reflect.Type) (ToolInputSchema, error) {
135
+ // var schema ToolInputSchema
136
+ // switch argumentType.Kind() {
137
+ // case reflect.Ptr:
138
+ // argumentType = dereferenceReflectType(argumentType)
139
+ // return getToolInputSchema(argumentType)
140
+ // case reflect.Array, reflect.Slice:
141
+ // // We need to get the type of the elements
142
+ // elementType := argumentType.Elem()
143
+ //
144
+ // case reflect.Struct:
145
+ // // If it's a struct then we need to get the schema for each field
146
+ // schema.Required = []string{}
147
+ // m := make(map[string]interface{})
148
+ // for i := 0; i < argumentType.NumField(); i++ {
149
+ // field := argumentType.Field(i)
150
+ // // If it's not a pointer then add it to the required fields
151
+ // if field.Type.Kind() != reflect.Ptr {
152
+ // schema.Required = append(schema.Required, field.Name)
153
+ // }
154
+ // // Dereference the type
155
+ // t := dereferenceReflectType(field.Type)
156
+ // fieldSchema, err := getToolInputSchema(t)
157
+ // if err != nil {
158
+ // return ToolInputSchema{}, err
159
+ // }
160
+ // m[field.Name] = fieldSchema.Properties
161
+ // }
162
+ // schema.Properties = m
163
+ // default:
164
+ // if !isStandardJSONSchemaType(argumentType) {
165
+ // return ToolInputSchema{}, fmt.Errorf("unknown type: %s", argumentType.String())
166
+ // }
167
+ // // If it's not a struct or a pointer then it's a standard JSON schema type
168
+ // t, err := convertGoTypeToJSONSchemaType(argumentType)
169
+ // if err != nil {
170
+ // return ToolInputSchema{}, err
171
+ // }
172
+ // schema.Type = t
173
+ // }
174
+ // return schema, nil
175
+ //}
176
+ //
177
+ //func convertGoTypeToJSONSchemaType(argumentType reflect.Type) (string, error) {
178
+ // switch argumentType.Kind() {
179
+ // case reflect.Array, reflect.Slice:
180
+ // return "array", nil
181
+ // case reflect.Map, reflect.Struct:
182
+ // return "object", nil
183
+ // case reflect.String:
184
+ // return "string", nil
185
+ // case reflect.Bool:
186
+ // return "boolean", nil
187
+ // case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
188
+ // return "integer", nil
189
+ // case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
190
+ // return "integer", nil
191
+ // case reflect.Float32, reflect.Float64:
192
+ // return "number", nil
193
+ // default:
194
+ // return "", fmt.Errorf("unknown type: %s", argumentType.String())
195
+ // }
196
+ //}
197
+ //
198
+ //func isStandardJSONSchemaType(t reflect.Type) bool {
199
+ // switch t.String() {
200
+ // case "string", "bool", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "array", "slice", "map", "ptr":
201
+ // return true
202
+ // default:
203
+ // return false
204
+ // }
205
+ //}
206
+
108
207
func (s * Server ) Serve () error {
109
208
protocol := NewProtocol (nil )
110
209
111
210
protocol .SetRequestHandler ("initialize" , func (req JSONRPCRequest , _ RequestHandlerExtra ) (interface {}, error ) {
112
211
return InitializeResult {
113
212
Meta : nil ,
114
- Capabilities : s .serverCapabilities ,
213
+ Capabilities : s .generateCapabilities () ,
115
214
Instructions : s .serverInstructions ,
116
215
ProtocolVersion : "2024-11-05" ,
117
216
ServerInfo : Implementation {
@@ -121,9 +220,57 @@ func (s *Server) Serve() error {
121
220
}, nil
122
221
})
123
222
223
+ // Definition for a tool the client can call.
224
+ type ToolRetType struct {
225
+ // A human-readable description of the tool.
226
+ Description * string `json:"description,omitempty" yaml:"description,omitempty" mapstructure:"description,omitempty"`
227
+
228
+ // A JSON Schema object defining the expected parameters for the tool.
229
+ InputSchema interface {} `json:"inputSchema" yaml:"inputSchema" mapstructure:"inputSchema"`
230
+
231
+ // The name of the tool.
232
+ Name string `json:"name" yaml:"name" mapstructure:"name"`
233
+ }
234
+
235
+ protocol .SetRequestHandler ("tools/list" , func (req JSONRPCRequest , _ RequestHandlerExtra ) (interface {}, error ) {
236
+ m := map [string ]interface {}{
237
+ "tools" : func () []ToolRetType {
238
+ var tools []ToolRetType
239
+ for _ , tool := range s .Tools {
240
+ tools = append (tools , ToolRetType {
241
+ Name : tool .Name ,
242
+ Description : & tool .Description ,
243
+ InputSchema : tool .ToolInputSchema ,
244
+ })
245
+ }
246
+ return tools
247
+ }(),
248
+ }
249
+ marshalled , err := json .Marshal (m )
250
+ if err != nil {
251
+ return nil , err
252
+ }
253
+ println (string (marshalled ))
254
+ return m , nil
255
+ })
256
+
124
257
return protocol .Connect (s .transport )
125
258
}
126
259
260
+ func (s * Server ) generateCapabilities () ServerCapabilities {
261
+ f := false
262
+ return ServerCapabilities {
263
+ Tools : func () * ServerCapabilitiesTools {
264
+ if s .Tools == nil {
265
+ return nil
266
+ }
267
+ return & ServerCapabilitiesTools {
268
+ ListChanged : & f ,
269
+ }
270
+ }(),
271
+ }
272
+ }
273
+
127
274
func validateHandler (handler any ) error {
128
275
handlerValue := reflect .ValueOf (handler )
129
276
handlerType := handlerValue .Type ()
0 commit comments