@@ -11,6 +11,7 @@ import (
1111 "fmt"
1212 "reflect"
1313
14+ "github.com/modelcontextprotocol/go-sdk/internal/util"
1415 "github.com/modelcontextprotocol/go-sdk/jsonschema"
1516)
1617
@@ -89,7 +90,7 @@ func newServerTool[In, Out any](t *Tool, h ToolHandlerFor[In, Out]) (*serverTool
8990func setSchema [T any ](sfield * * jsonschema.Schema , rfield * * jsonschema.Resolved ) error {
9091 var err error
9192 if * sfield == nil {
92- * sfield , err = jsonschema . For [T ]()
93+ * sfield , err = SchemaFor [T ]()
9394 }
9495 if err != nil {
9596 return err
@@ -125,6 +126,61 @@ func unmarshalSchema(data json.RawMessage, resolved *jsonschema.Resolved, v any)
125126 return nil
126127}
127128
129+ // SchemaFor returns a JSON Schema for type T.
130+ // It is like [jsonschema.For], but also uses "mcp" struct field tags
131+ // for property descriptions.
132+ //
133+ // For example, the call
134+ //
135+ // SchemaFor[struct{ B int `mcp:"desc"` }]()
136+ //
137+ // returns a schema with this value for "properties":
138+ //
139+ // {"B": {"type": "integer", "description": "desc"}}
140+ func SchemaFor [T any ]() (* jsonschema.Schema , error ) {
141+ // Infer the schema based on "json" tags alone.
142+ s , err := jsonschema .For [T ]()
143+ if err != nil {
144+ return nil , err
145+ }
146+
147+ // Add descriptions from "mcp" tags.
148+ if err := addDescriptions (reflect .TypeFor [T ](), s ); err != nil {
149+ return nil , err
150+ }
151+ return s , nil
152+ }
153+
154+ func addDescriptions (t reflect.Type , s * jsonschema.Schema ) error {
155+ for t .Kind () == reflect .Pointer {
156+ t = t .Elem ()
157+ }
158+ if t .Kind () != reflect .Struct {
159+ return nil
160+ }
161+
162+ for i := range t .NumField () {
163+ f := t .Field (i )
164+ info := util .FieldJSONInfo (f )
165+ ps := s .Properties [info .Name ]
166+ if tag , ok := f .Tag .Lookup ("mcp" ); ok {
167+ if ps == nil {
168+ return fmt .Errorf ("mcp tag on struct field %s.%s, which is not in schema" , t , f .Name )
169+ }
170+ if tag == "" {
171+ return fmt .Errorf ("empty mcp tag on struct field %s.%s" , t , f .Name )
172+ }
173+ ps .Description = tag
174+ }
175+ // Recurse on sub-schemas.
176+ if ps != nil {
177+ addDescriptions (f .Type , ps )
178+ }
179+
180+ }
181+ return nil
182+ }
183+
128184// schemaJSON returns the JSON value for s as a string, or a string indicating an error.
129185func schemaJSON (s * jsonschema.Schema ) string {
130186 m , err := json .Marshal (s )
0 commit comments