Skip to content

Nested structs not correctly flattened in JSON schema #437

@unbekanntes-pferd

Description

@unbekanntes-pferd

Describe the bug
Nested structs not correctly flattened for JSON schema:
See code example below - in short: having a nested struct produces the correct JSON string but incorrect JSON schema via tool registration.

To Reproduce
Steps to reproduce the behavior:

package main

import (
	"context"
	"log"
	"github.com/modelcontextprotocol/go-sdk/mcp"
)

// Foo represents a base struct
type Foo struct {
	ID   string `json:"id"`
	Name string `json:"name"`
	Type string `json:"type"`
}

// Bar embeds Foo
type Bar struct {
	*Foo                        // Embedded - should flatten in JSON
	Extra string `json:"extra"` // Additional field
}

// Response contains array of embedded structs
type Response struct {
	Data []Bar `json:"data"`
}

// Input for the tool
type Input struct {
	Count int `json:"count"`
}

// TestTool demonstrates the embedded struct schema bug
func TestTool(ctx context.Context, req *mcp.CallToolRequest, input Input) (*mcp.CallToolResult, Response, error) {
	// Create test data with embedded structs
	response := Response{
		Data: []Bar{
			{
				Foo: &Foo{
					ID:   "foo1",
					Name: "Test Foo 1",
					Type: "test",
				},
				Extra: "additional data 1",
			},
			{
				Foo: &Foo{
					ID:   "foo2", 
					Name: "Test Foo 2",
					Type: "test",
				},
				Extra: "additional data 2",
			},
		},
	}

	return nil, response, nil
}

func main() {
	ctx := context.Background()
	clientTransport, serverTransport := mcp.NewInMemoryTransports()

	server := mcp.NewServer(&mcp.Implementation{Name: "bug-repro", Version: "v0.0.1"}, nil)
	
	// This should work but will fail with schema validation error
	// because SDK expects {"Foo": {...}, "extra": "..."} 
	// but Go produces {"id": "...", "name": "...", "type": "...", "extra": "..."}
	mcp.AddTool(server, &mcp.Tool{
		Name:        "test_embedded_struct",
		Description: "Test tool that demonstrates embedded struct schema bug",
	}, TestTool)

	serverSession, err := server.Connect(ctx, serverTransport, nil)
	if err != nil {
		log.Fatal(err)
	}

	client := mcp.NewClient(&mcp.Implementation{Name: "client"}, nil)
	clientSession, err := client.Connect(ctx, clientTransport, nil)
	if err != nil {
		log.Fatal(err)
	}

	// This call will fail with schema validation error
	res, err := clientSession.CallTool(ctx, &mcp.CallToolParams{
		Name:      "test_embedded_struct",
		Arguments: map[string]any{"count": 2},
	})
	if err != nil {
		log.Printf("ERROR (demonstrates the bug): %v", err)
	} else {
		log.Printf("Success: %+v", res)
	}

	clientSession.Close()
	serverSession.Wait()
}

Expected behavior
Embedded structs are flattened (as with JSON string) in JSON schema.

Logs
Output of above:

2025/09/09 16:51:15 ERROR (demonstrates the bug): calling "tools/call": tool output: validating
        &{[{0x14000282660 additional data 1} {0x14000282690 additional data 2}]}
against
         {"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","required":["Foo","extra"],"properties":{"Foo":{"type":["null","object"],"required":["id","name","type"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"}},"additionalProperties":false},"extra":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false}:
 validating root: validating /properties/data: validating /properties/data/items: validating /properties/data/items/additionalProperties: not: validated against <anonymous schema>

Additional context
N/A

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingrelease blockerThis issue blocks the release milestone with which it is associated.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions