Skip to content

Commit a3e753b

Browse files
committed
mcp: correct the JSON used for unstructured content
Recently, I refactored to fix validation and default application for structured output. However, I used the wrong byte slice for the unstructured output. Fix it to use the same bytes as structured output, with a test. Fixes #475
1 parent 22f86c4 commit a3e753b

File tree

2 files changed

+32
-3
lines changed

2 files changed

+32
-3
lines changed

mcp/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ func toolForErr[In, Out any](t *Tool, h ToolHandlerFor[In, Out]) (*Tool, ToolHan
292292
// https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content.
293293
if res.Content == nil {
294294
res.Content = []Content{&TextContent{
295-
Text: string(outbytes),
295+
Text: string(outJSON),
296296
}}
297297
}
298298
}

mcp/server_test.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,7 @@ func testToolForSchema[In, Out any](t *testing.T, tool *Tool, in string, out Out
512512
Arguments: json.RawMessage(in),
513513
},
514514
}
515-
_, err = goth(context.Background(), ctr)
516-
515+
result, err := goth(context.Background(), ctr)
517516
if wantErrContaining != "" {
518517
if err == nil {
519518
t.Errorf("got nil error, want error containing %q", wantErrContaining)
@@ -525,8 +524,18 @@ func testToolForSchema[In, Out any](t *testing.T, tool *Tool, in string, out Out
525524
} else if err != nil {
526525
t.Errorf("got error %v, want no error", err)
527526
}
527+
528+
if gott.OutputSchema != nil && err == nil && !result.IsError {
529+
// Check that structured content matches exactly.
530+
unstructured := result.Content[0].(*TextContent).Text
531+
structured := string(result.StructuredContent.(json.RawMessage))
532+
if diff := cmp.Diff(unstructured, structured); diff != "" {
533+
t.Errorf("Unstructured content does not match structured content exactly (-unstructured +structured):\n%s", diff)
534+
}
535+
}
528536
}
529537

538+
// TODO: move this to tool_test.go
530539
func TestToolForSchemas(t *testing.T) {
531540
// Validate that toolForErr handles schemas properly.
532541
type in struct {
@@ -558,4 +567,24 @@ func TestToolForSchemas(t *testing.T) {
558567
// Tool sets output schema: that is what's used, and validation happens.
559568
testToolForSchema[in, any](t, &Tool{OutputSchema: outSchema2}, `{"p":3}`, out{true},
560569
inSchema, outSchema2, `want "integer"`)
570+
571+
// Check a slightly more complicated case.
572+
type weatherOutput struct {
573+
Summary string
574+
AsOf time.Time
575+
Source string
576+
}
577+
testToolForSchema[any](t, &Tool{}, `{}`, weatherOutput{},
578+
&schema{Type: "object"},
579+
&schema{
580+
Type: "object",
581+
Required: []string{"Summary", "AsOf", "Source"},
582+
AdditionalProperties: falseSchema,
583+
Properties: map[string]*schema{
584+
"Summary": {Type: "string"},
585+
"AsOf": {Type: "string"},
586+
"Source": {Type: "string"},
587+
},
588+
},
589+
"")
561590
}

0 commit comments

Comments
 (0)