feat: Add outputSchema to the tool definition - #208
Conversation
There was a problem hiding this comment.
Thanks for this @azhur!
It's a solid and tested code but I think this requires a little more work to get better type safety. Don't worry about backward incompatible updates, it's fine at this point, please see my comment below.
There was a problem hiding this comment.
We shouldn't commit the generated-docs files, the release process does that
| def inputJson(schema: Json): Tool[Json] = Tool[Json](name, description, ToolSchema.Raw(schema), summon[Decoder[Json]], None, annotations) | ||
|
|
||
| /** A tool with a known input type `I`, ready to be given its handling logic. */ | ||
| case class Tool[I]( |
There was a problem hiding this comment.
I think we should reflect the structured output in tool types for compile time safety, like the following
tool("adder").input[In] // Tool[In, Unit]
.handle(i => ToolResult.text("5")) // ok
.handle(i => ToolResult.structured(Sum(5))) // does not compile
tool("adder").input[In].output[Sum] // Tool[In, Sum]
.handle(i => ToolResult.structured(Sum(5))) // ok
.handle(i => ToolResult.error("boom")) // ok
.handle(i => ToolResult.text("5")) // does not compile
my suggestion will be for the Tool[I] to become Tool[I, O] where Tool[I, Unit] represents a tool without structured output.
There was a problem hiding this comment.
thanks for the review and type-safety suggestion.
Done — Tool[I, O] as suggested, but with a dedicated NoOutput type instead of Unit, since Unit lets value discarding silently accept ToolResult.structured(x) (warning only, without -Werror) and ship structuredContent {}.
tool("adder").input[In].handle(i => ToolResult.structured(Sum(5))) // Tool[In, Unit]: Sum(5) discarded, structuredContent = {}There was a problem hiding this comment.
When result.content is missing but result.structuredContent is defined we should dump it's json text representation to content as MCP protocol recommends. Please also add a test for this case. https://modelcontextprotocol.io/specification/2026-07-28/server/tools#structured-content.
| /** The structured output type of a tool that returns none. A distinct type rather than `Unit`, which value discarding would let any | ||
| * structured result conform to. | ||
| */ | ||
| sealed trait NoOutput |
There was a problem hiding this comment.
How about we call it NoStructuredOutput?
There was a problem hiding this comment.
it was my initial choice but then i decided to make it shorter, renamed back to NoStructuredOutput
| backend.close() | ||
| ``` | ||
|
|
||
| ### Structured output |
There was a problem hiding this comment.
I am trying to keep README short, details are in the documentation, I think this can be removed
see #206