Skip to content

Conversation

@findleyr
Copy link
Contributor

@findleyr findleyr commented Dec 5, 2025

In the fix for #199, I was overly cautious: I assumed that if the user
provided their own schema, we shouldn't fix up typed nils for them.

But this was wrong: consider that:

  1. If the user provides a schema, it must be an "object" schema.
  2. One way that we recommend customizing schemas is by calling
    jsonschema.For and modifying. It's very confusing that doing
    this would change the treatment of the zero value.

The good news is that any tool that was returning a typed nil is
provably wrong, so this is just a bug that we can and should fix.

Fixes #691

@findleyr findleyr requested review from jba and removed request for jba December 6, 2025 15:55
@fahimfazledev-glitch

This comment was marked as spam.

In the fix for modelcontextprotocol#199, I was overly cautious: I assumed that if the user
provided their own schema, we shouldn't fix up typed nils for them.

But this was wrong: consider that:
1. If the user provides a schema, it must be an "object" schema.
2. One way that we recommend customizing schemas is by calling
   jsonschema.For and modifying. It's very confusing that doing
   this would change the treatment of the zero value.

The good news is that any tool that was returning a typed nil is
provably wrong, so this is just a bug that we can and should fix.

Fixes modelcontextprotocol#691
//
// TODO(rfindley): we really shouldn't ever return 'null' results. Maybe we
// should have a jsonschema.Zero(schema) helper?
func setSchema[T any](sfield *any, rfield **jsonschema.Resolved) (zero any, err error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe add some more documentation around sfield and rfield, and what exactly this function is doing? E.g., it seems like sfield is an inpput, and rfield is an output, in addition to the 2 return variables. I think it might be beneficial to document the type of sfield since it is any but I think this is an any expected to unmarshall into a valid jsonschema object (cf Tool.OutputSchema).

I am also not familiar with the sfield and rfield names but I could be missing some conventions around this.

I could be missing some context around how this function is used, or conventions around these names.

if err != nil {
t.Fatal(err)
t0 := tools.Tools[0]
for _, t1 := range tools.Tools[1:] {
Copy link
Collaborator

Choose a reason for hiding this comment

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

t1 is a confusing name here since it is index 1 or 2.

tn might be slightly better.

maybe it would be even clearer if we iterated over adjacent pairs in this array, then we could use names like i and j and avoid giving explicit indices.

// should have a jsonschema.Zero(schema) helper?
func setSchema[T any](sfield *any, rfield **jsonschema.Resolved) (zero any, err error) {
rt := reflect.TypeFor[T]()
if rt.Kind() == reflect.Pointer {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm on the fence, should we put a comment here explaining the importance of setting rt and zero when sfield != nil? As in, the change in this PR is (I think) making it so we never return a typed nil for pointer elements an rather return a element-typed zero. Is there a good reference as to why we should never return typed nils? From the comment in the PR it sounds like this is always a bug to return typed nils, but why?

if rt.Kind() == reflect.Pointer {
rt = rt.Elem()
zero = reflect.Zero(rt).Interface()
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Somewhat related to my previous comment, should we check if our handling of zero/nil for pointer types is "interfering" with the user provided schema? It sounds like actually the user should never be including the ability to return typed nils in their schema, so maybe this is something we can check at validation time?

its also OK if the answer is "no" and this is too much added complexity, I just wanted to double check if there's any corner cases we could easily identify and flag for the user to make their UX better

Copy link
Contributor

@jba jba left a comment

Choose a reason for hiding this comment

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

Address Markus's comments before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix handling for nil pointers given user-provided output schema

4 participants