fix(mcp): preserve structured plugin tool errors (#3815)
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package mcp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/kandev/kandev/internal/mcp/plugintools"
|
||||
mcplib "github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPluginToolPreservesStructuredResultAndErrorStatus(t *testing.T) {
|
||||
for _, isError := range []bool{false, true} {
|
||||
name := "success"
|
||||
if isError {
|
||||
name = "error"
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
structured := map[string]any{"status": "uncertain", "recipient": "U01234567", "duplicate": true}
|
||||
backend := &testBackend{response: map[string]any{
|
||||
"text": "Check delivery before retrying.", "structured_content": structured, "is_error": isError,
|
||||
}}
|
||||
server := New(backend, "session-1", "task-1", 10005, newTestLogger(t), "", false, ModeTask)
|
||||
definition := plugintools.Definition{
|
||||
PluginID: "notifications", LocalName: "notify", ExposedName: plugintools.ExposedName("notifications", "notify"),
|
||||
Description: "Notify a user", InputSchema: []byte(`{"type":"object"}`),
|
||||
Surfaces: []string{plugintools.SurfaceKanban},
|
||||
}
|
||||
require.NoError(t, server.SetPluginTools(plugintools.Snapshot{
|
||||
Generation: "g", Revision: 1, Tools: []plugintools.Definition{definition},
|
||||
}))
|
||||
|
||||
result := callTool(t, server, definition.ExposedName, map[string]any{})
|
||||
require.Equal(t, isError, result.IsError)
|
||||
require.Equal(t, structured, result.StructuredContent)
|
||||
require.Len(t, result.Content, 1)
|
||||
require.Equal(t, "Check delivery before retrying.", result.Content[0].(mcplib.TextContent).Text)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginToolErrorOmitsNilStructuredContent(t *testing.T) {
|
||||
backend := &testBackend{response: map[string]any{
|
||||
"text": "Check delivery before retrying.", "structured_content": nil, "is_error": true,
|
||||
}}
|
||||
server := New(backend, "session-1", "task-1", 10005, newTestLogger(t), "", false, ModeTask)
|
||||
definition := plugintools.Definition{
|
||||
PluginID: "notifications", LocalName: "notify", ExposedName: plugintools.ExposedName("notifications", "notify"),
|
||||
Description: "Notify a user", InputSchema: []byte(`{"type":"object"}`),
|
||||
Surfaces: []string{plugintools.SurfaceKanban},
|
||||
}
|
||||
require.NoError(t, server.SetPluginTools(plugintools.Snapshot{
|
||||
Generation: "g", Revision: 1, Tools: []plugintools.Definition{definition},
|
||||
}))
|
||||
|
||||
result := callTool(t, server, definition.ExposedName, map[string]any{})
|
||||
serialized, err := json.Marshal(result)
|
||||
require.NoError(t, err)
|
||||
require.NotContains(t, string(serialized), `"structuredContent"`)
|
||||
}
|
||||
@@ -989,7 +989,11 @@ func (s *Server) registerPluginTools() {
|
||||
return nil, err
|
||||
}
|
||||
if result.IsError {
|
||||
return mcp.NewToolResultError(result.Text), nil
|
||||
response := mcp.NewToolResultError(result.Text)
|
||||
if result.StructuredContent != nil {
|
||||
response.StructuredContent = result.StructuredContent
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
if result.StructuredContent != nil {
|
||||
return mcp.NewToolResultStructured(result.StructuredContent, result.Text), nil
|
||||
|
||||
Reference in New Issue
Block a user