1616use Mcp \Schema \Content \Content ;
1717use Mcp \Schema \Content \EmbeddedResource ;
1818use Mcp \Schema \Content \ImageContent ;
19+ use Mcp \Schema \Content \StructuredContent ;
1920use Mcp \Schema \Content \TextContent ;
2021use Mcp \Schema \JsonRpc \Response ;
2122use Mcp \Schema \JsonRpc \ResultInterface ;
@@ -49,6 +50,7 @@ class CallToolResult implements ResultInterface
4950 */
5051 public function __construct (
5152 public readonly array $ content ,
53+ public readonly ?StructuredContent $ structuredContent = null ,
5254 public readonly bool $ isError = false ,
5355 ) {
5456 foreach ($ this ->content as $ item ) {
@@ -63,59 +65,73 @@ public function __construct(
6365 *
6466 * @param array<TextContent|ImageContent|AudioContent|EmbeddedResource> $content The content of the tool result
6567 */
66- public static function success (array $ content ): self
68+ public static function success (array $ content, ? StructuredContent $ structuredContent = null ): self
6769 {
68- return new self ($ content , false );
70+ return new self ($ content , $ structuredContent , false );
6971 }
7072
7173 /**
7274 * Create a new CallToolResult with error status.
7375 *
7476 * @param array<TextContent|ImageContent|AudioContent|EmbeddedResource> $content The content of the tool result
7577 */
76- public static function error (array $ content ): self
78+ public static function error (array $ content, ? StructuredContent $ structuredContent = null ): self
7779 {
78- return new self ($ content , true );
80+ return new self ($ content , $ structuredContent , true );
7981 }
8082
8183 /**
82- * @param array{
83- * content: array<TextContentData|ImageContentData|AudioContentData|EmbeddedResourceData>,
84- * isError?: bool,
85- * } $data
84+ * @param array<int, TextContent|ImageContent|AudioContent|EmbeddedResource|StructuredContent> $data
8685 */
8786 public static function fromArray (array $ data ): self
8887 {
89- if (!isset ($ data ['content ' ]) || !\is_array ($ data ['content ' ])) {
90- throw new InvalidArgumentException ('Missing or invalid "content" array in CallToolResult data. ' );
91- }
92-
9388 $ contents = [];
89+ $ structuredContent = null ;
90+ $ isError = false ;
9491
95- foreach ($ data ['content ' ] as $ item ) {
96- $ contents [] = match ($ item ['type ' ] ?? null ) {
97- 'text ' => TextContent::fromArray ($ item ),
98- 'image ' => ImageContent::fromArray ($ item ),
99- 'audio ' => AudioContent::fromArray ($ item ),
100- 'resource ' => EmbeddedResource::fromArray ($ item ),
92+ foreach ($ data as $ item ) {
93+ if (!$ item instanceof Content) {
94+ throw new InvalidArgumentException ('Provided array must be an array of Content objects. ' );
95+ }
96+ if ('structured ' === $ item ->type ) {
97+ $ structuredContent = $ item ;
98+ continue ;
99+ }
100+ $ contents [] = match ($ item ->type ) {
101+ // TODO this should be enum, also `resource_link` missing.
102+ // We shouldn't rely on user input for type and just use instanceof instead
103+ 'text ' , 'audio ' , 'image ' , 'resource ' => $ item ,
101104 default => throw new InvalidArgumentException (\sprintf ('Invalid content type in CallToolResult data: "%s". ' , $ item ['type ' ] ?? null )),
102105 };
106+
107+ if ('text ' === $ item ->type && $ item instanceof TextContent) {
108+ $ isError = $ item ->isError ;
109+ }
103110 }
104111
105- return new self ($ contents , $ data [ ' isError ' ] ?? false );
112+ return new self ($ contents , $ structuredContent , $ isError );
106113 }
107114
108115 /**
109116 * @return array{
110- * content: array<TextContent|ImageContent|AudioContent|EmbeddedResource>,
117+ * content: array<TextContentData|ImageContentData|AudioContentData|EmbeddedResourceData>,
118+ * structuredContent?: mixed[],
111119 * isError: bool,
112120 * }
113121 */
114122 public function jsonSerialize (): array
115123 {
116- return [
117- 'content ' => $ this ->content ,
118- 'isError ' => $ this ->isError ,
119- ];
124+ $ result ['content ' ] = [];
125+ foreach ($ this ->content as $ item ) {
126+ $ result ['content ' ][] = $ item ->jsonSerialize ();
127+ }
128+
129+ $ result ['isError ' ] = $ this ->isError ;
130+
131+ if ($ this ->structuredContent ) {
132+ $ result ['structuredContent ' ] = $ this ->structuredContent ->jsonSerialize ();
133+ }
134+
135+ return $ result ;
120136 }
121137}
0 commit comments