client: Prefer structuredContent in toolJSON #14

Merged
linus merged 1 commits from client/tooljson-structured into develop 2026-09-04 23:45:26 -05:00
2 changed files with 94 additions and 0 deletions
Showing only changes of commit bc50f3fd6b - Show all commits
+7
View File
@@ -101,6 +101,13 @@ func toolJSON(res *mcp.CallToolResult) (json.RawMessage, error) {
if err := res.GetError(); err != nil {
return nil, err
}
if res.StructuredContent != nil {
b, err := json.Marshal(res.StructuredContent)
if err != nil {
return nil, err
}
return json.RawMessage(b), nil
}
var b []byte
for _, c := range res.Content {
t, ok := c.(*mcp.TextContent)
+87
View File
@@ -0,0 +1,87 @@
package client
import (
"encoding/json"
"errors"
"testing"
mcp "github.com/modelcontextprotocol/go-sdk/mcp"
)
func TestToolJSON(t *testing.T) {
t.Parallel()
tests := []struct {
name string
res *mcp.CallToolResult
want string
}{
{
name: "structured-only",
res: &mcp.CallToolResult{
StructuredContent: map[string]any{"symbol": "MU"},
},
want: `{"symbol":"MU"}`,
},
{
name: "text JSON",
res: &mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{Text: `{"symbol":"MU"}`}},
},
want: `{"symbol":"MU"}`,
},
{
name: "text non-JSON + structured",
res: &mcp.CallToolResult{
StructuredContent: json.RawMessage(`{"symbol":"MU"}`),
Content: []mcp.Content{&mcp.TextContent{Text: "not json"}},
},
want: `{"symbol":"MU"}`,
},
{
name: "empty",
res: &mcp.CallToolResult{},
want: `{}`,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := toolJSON(tc.res)
if err != nil {
t.Fatal(err)
}
if string(got) != tc.want {
t.Fatalf("got %s want %s", got, tc.want)
}
})
}
}
func TestToolJSON_nilRes(t *testing.T) {
t.Parallel()
_, err := toolJSON(nil)
if err == nil || err.Error() != "empty tool result" {
t.Fatalf("%v", err)
}
}
func TestToolJSON_getError(t *testing.T) {
t.Parallel()
inner := errors.New("tool failed")
res := &mcp.CallToolResult{}
res.SetError(inner)
_, err := toolJSON(res)
if !errors.Is(err, inner) {
t.Fatalf("%v", err)
}
}
func TestToolJSON_nonJSONText(t *testing.T) {
t.Parallel()
_, err := toolJSON(&mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{Text: "not json"}},
})
if err == nil || err.Error() != "non-json tool result" {
t.Fatalf("%v", err)
}
}