feat: Add output schema support to MCP tools (#153)
This commit is contained in:
parent
4c3e5e61c7
commit
c0938a19bd
39 changed files with 605 additions and 55 deletions
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
All notable changes to `mcp/sdk` will be documented in this file.
|
All notable changes to `mcp/sdk` will be documented in this file.
|
||||||
|
|
||||||
|
0.3
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Add output schema support to MCP tools
|
||||||
|
|
||||||
0.2.2
|
0.2.2
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,31 @@ final class EnvToolHandler
|
||||||
*
|
*
|
||||||
* @return array<string, string|int> the result, varying by APP_MODE
|
* @return array<string, string|int> the result, varying by APP_MODE
|
||||||
*/
|
*/
|
||||||
#[McpTool(name: 'process_data_by_mode')]
|
#[McpTool(
|
||||||
|
name: 'process_data_by_mode',
|
||||||
|
outputSchema: [
|
||||||
|
'type' => 'object',
|
||||||
|
'properties' => [
|
||||||
|
'mode' => [
|
||||||
|
'type' => 'string',
|
||||||
|
'description' => 'The processing mode used',
|
||||||
|
],
|
||||||
|
'processed_input' => [
|
||||||
|
'type' => 'string',
|
||||||
|
'description' => 'The processed input data',
|
||||||
|
],
|
||||||
|
'original_input' => [
|
||||||
|
'type' => 'string',
|
||||||
|
'description' => 'The original input data (only in default mode)',
|
||||||
|
],
|
||||||
|
'message' => [
|
||||||
|
'type' => 'string',
|
||||||
|
'description' => 'A descriptive message about the processing',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'required' => ['mode', 'message'],
|
||||||
|
]
|
||||||
|
)]
|
||||||
public function processData(string $input): array
|
public function processData(string $input): array
|
||||||
{
|
{
|
||||||
$appMode = getenv('APP_MODE'); // Read from environment
|
$appMode = getenv('APP_MODE'); // Read from environment
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,12 @@ use Mcp\Schema\ToolAnnotations;
|
||||||
class McpTool
|
class McpTool
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string|null $name The name of the tool (defaults to the method name)
|
* @param string|null $name The name of the tool (defaults to the method name)
|
||||||
* @param string|null $description The description of the tool (defaults to the DocBlock/inferred)
|
* @param string|null $description The description of the tool (defaults to the DocBlock/inferred)
|
||||||
* @param ToolAnnotations|null $annotations Optional annotations describing tool behavior
|
* @param ToolAnnotations|null $annotations Optional annotations describing tool behavior
|
||||||
* @param ?Icon[] $icons Optional list of icon URLs representing the tool
|
* @param ?Icon[] $icons Optional list of icon URLs representing the tool
|
||||||
* @param ?array<string, mixed> $meta Optional metadata
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
|
* @param array<string, mixed> $outputSchema Optional JSON Schema object for defining the expected output structure
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public ?string $name = null,
|
public ?string $name = null,
|
||||||
|
|
@ -33,6 +34,7 @@ class McpTool
|
||||||
public ?ToolAnnotations $annotations = null,
|
public ?ToolAnnotations $annotations = null,
|
||||||
public ?array $icons = null,
|
public ?array $icons = null,
|
||||||
public ?array $meta = null,
|
public ?array $meta = null,
|
||||||
|
public ?array $outputSchema = null,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,7 @@ class Discoverer
|
||||||
$name = $instance->name ?? ('__invoke' === $methodName ? $classShortName : $methodName);
|
$name = $instance->name ?? ('__invoke' === $methodName ? $classShortName : $methodName);
|
||||||
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
|
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
|
||||||
$inputSchema = $this->schemaGenerator->generate($method);
|
$inputSchema = $this->schemaGenerator->generate($method);
|
||||||
|
$outputSchema = $this->schemaGenerator->generateOutputSchema($method);
|
||||||
$tool = new Tool(
|
$tool = new Tool(
|
||||||
$name,
|
$name,
|
||||||
$inputSchema,
|
$inputSchema,
|
||||||
|
|
@ -229,6 +230,7 @@ class Discoverer
|
||||||
$instance->annotations,
|
$instance->annotations,
|
||||||
$instance->icons,
|
$instance->icons,
|
||||||
$instance->meta,
|
$instance->meta,
|
||||||
|
$outputSchema,
|
||||||
);
|
);
|
||||||
$tools[$name] = new ToolReference($tool, [$className, $methodName], false);
|
$tools[$name] = new ToolReference($tool, [$className, $methodName], false);
|
||||||
++$discoveredCount['tools'];
|
++$discoveredCount['tools'];
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
namespace Mcp\Capability\Discovery;
|
namespace Mcp\Capability\Discovery;
|
||||||
|
|
||||||
|
use Mcp\Capability\Attribute\McpTool;
|
||||||
use Mcp\Capability\Attribute\Schema;
|
use Mcp\Capability\Attribute\Schema;
|
||||||
use Mcp\Exception\InvalidArgumentException;
|
use Mcp\Exception\InvalidArgumentException;
|
||||||
use Mcp\Server\RequestContext;
|
use Mcp\Server\RequestContext;
|
||||||
|
|
@ -81,6 +82,27 @@ class SchemaGenerator
|
||||||
return $this->buildSchemaFromParameters($parametersInfo, $methodSchema);
|
return $this->buildSchemaFromParameters($parametersInfo, $methodSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a JSON Schema object (as a PHP array) for a method's or function's return type.
|
||||||
|
*
|
||||||
|
* Only returns an outputSchema if explicitly provided in the McpTool attribute.
|
||||||
|
* Per MCP spec, outputSchema should only be present when explicitly provided.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>|null
|
||||||
|
*/
|
||||||
|
public function generateOutputSchema(\ReflectionMethod|\ReflectionFunction $reflection): ?array
|
||||||
|
{
|
||||||
|
// Only return outputSchema if explicitly provided in McpTool attribute
|
||||||
|
$mcpToolAttrs = $reflection->getAttributes(McpTool::class, \ReflectionAttribute::IS_INSTANCEOF);
|
||||||
|
if ($mcpToolAttrs) {
|
||||||
|
$mcpToolInstance = $mcpToolAttrs[0]->newInstance();
|
||||||
|
|
||||||
|
return $mcpToolInstance->outputSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts method-level or function-level Schema attribute.
|
* Extracts method-level or function-level Schema attribute.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ final class ArrayLoader implements LoaderInterface
|
||||||
* description: ?string,
|
* description: ?string,
|
||||||
* annotations: ?ToolAnnotations,
|
* annotations: ?ToolAnnotations,
|
||||||
* icons: ?Icon[],
|
* icons: ?Icon[],
|
||||||
* meta: ?array<string, mixed>
|
* meta: ?array<string, mixed>,
|
||||||
|
* outputSchema: ?array<string, mixed>
|
||||||
* }[] $tools
|
* }[] $tools
|
||||||
* @param array{
|
* @param array{
|
||||||
* handler: Handler,
|
* handler: Handler,
|
||||||
|
|
@ -117,6 +118,7 @@ final class ArrayLoader implements LoaderInterface
|
||||||
annotations: $data['annotations'] ?? null,
|
annotations: $data['annotations'] ?? null,
|
||||||
icons: $data['icons'] ?? null,
|
icons: $data['icons'] ?? null,
|
||||||
meta: $data['meta'] ?? null,
|
meta: $data['meta'] ?? null,
|
||||||
|
outputSchema: $data['outputSchema'] ?? null,
|
||||||
);
|
);
|
||||||
$registry->registerTool($tool, $data['handler'], true);
|
$registry->registerTool($tool, $data['handler'], true);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,4 +111,33 @@ class ToolReference extends ElementReference
|
||||||
|
|
||||||
return [new TextContent($jsonResult)];
|
return [new TextContent($jsonResult)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts structured content from a tool result using the output schema.
|
||||||
|
*
|
||||||
|
* @param mixed $toolExecutionResult the raw value returned by the tool's PHP method
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>|null the structured content, or null if not extractable
|
||||||
|
*
|
||||||
|
* @throws \JsonException if JSON encoding fails for non-Content array/object results
|
||||||
|
*/
|
||||||
|
public function extractStructuredContent(mixed $toolExecutionResult): ?array
|
||||||
|
{
|
||||||
|
if (\is_array($toolExecutionResult)) {
|
||||||
|
return $toolExecutionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_object($toolExecutionResult) && !($toolExecutionResult instanceof Content)) {
|
||||||
|
$jsonResult = json_encode(
|
||||||
|
$toolExecutionResult,
|
||||||
|
\JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR | \JSON_INVALID_UTF8_SUBSTITUTE
|
||||||
|
);
|
||||||
|
|
||||||
|
return json_decode(
|
||||||
|
$jsonResult, true, 512, \JSON_THROW_ON_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ class CallToolResult implements ResultInterface
|
||||||
* content: array<mixed>,
|
* content: array<mixed>,
|
||||||
* isError?: bool,
|
* isError?: bool,
|
||||||
* _meta?: array<string, mixed>,
|
* _meta?: array<string, mixed>,
|
||||||
|
* structuredContent?: array<string, mixed>
|
||||||
* } $data
|
* } $data
|
||||||
*/
|
*/
|
||||||
public static function fromArray(array $data): self
|
public static function fromArray(array $data): self
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,21 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
* properties: array<string, mixed>,
|
* properties: array<string, mixed>,
|
||||||
* required: string[]|null
|
* required: string[]|null
|
||||||
* }
|
* }
|
||||||
|
* @phpstan-type ToolOutputSchema array{
|
||||||
|
* type: 'object',
|
||||||
|
* properties?: array<string, mixed>,
|
||||||
|
* required?: string[]|null,
|
||||||
|
* additionalProperties?: bool|array<string, mixed>,
|
||||||
|
* description?: string
|
||||||
|
* }
|
||||||
* @phpstan-type ToolData array{
|
* @phpstan-type ToolData array{
|
||||||
* name: string,
|
* name: string,
|
||||||
* inputSchema: ToolInputSchema,
|
* inputSchema: ToolInputSchema,
|
||||||
* description?: string|null,
|
* description?: string|null,
|
||||||
* annotations?: ToolAnnotationsData,
|
* annotations?: ToolAnnotationsData,
|
||||||
* icons?: IconData[],
|
* icons?: IconData[],
|
||||||
* _meta?: array<string, mixed>
|
* _meta?: array<string, mixed>,
|
||||||
|
* outputSchema?: ToolOutputSchema
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||||
|
|
@ -38,14 +46,15 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
class Tool implements \JsonSerializable
|
class Tool implements \JsonSerializable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $name the name of the tool
|
* @param string $name the name of the tool
|
||||||
* @param ?string $description A human-readable description of the tool.
|
* @param ?string $description A human-readable description of the tool.
|
||||||
* This can be used by clients to improve the LLM's understanding of
|
* This can be used by clients to improve the LLM's understanding of
|
||||||
* available tools. It can be thought of like a "hint" to the model.
|
* available tools. It can be thought of like a "hint" to the model.
|
||||||
* @param ToolInputSchema $inputSchema a JSON Schema object (as a PHP array) defining the expected 'arguments' for the tool
|
* @param ToolInputSchema $inputSchema a JSON Schema object (as a PHP array) defining the expected 'arguments' for the tool
|
||||||
* @param ?ToolAnnotations $annotations optional additional tool information
|
* @param ?ToolAnnotations $annotations optional additional tool information
|
||||||
* @param ?Icon[] $icons optional icons representing the tool
|
* @param ?Icon[] $icons optional icons representing the tool
|
||||||
* @param ?array<string, mixed> $meta Optional metadata
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
|
* @param ToolOutputSchema|null $outputSchema optional JSON Schema object (as a PHP array) defining the expected output structure
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public readonly string $name,
|
public readonly string $name,
|
||||||
|
|
@ -54,6 +63,7 @@ class Tool implements \JsonSerializable
|
||||||
public readonly ?ToolAnnotations $annotations,
|
public readonly ?ToolAnnotations $annotations,
|
||||||
public readonly ?array $icons = null,
|
public readonly ?array $icons = null,
|
||||||
public readonly ?array $meta = null,
|
public readonly ?array $meta = null,
|
||||||
|
public readonly ?array $outputSchema = null,
|
||||||
) {
|
) {
|
||||||
if (!isset($inputSchema['type']) || 'object' !== $inputSchema['type']) {
|
if (!isset($inputSchema['type']) || 'object' !== $inputSchema['type']) {
|
||||||
throw new InvalidArgumentException('Tool inputSchema must be a JSON Schema of type "object".');
|
throw new InvalidArgumentException('Tool inputSchema must be a JSON Schema of type "object".');
|
||||||
|
|
@ -78,13 +88,23 @@ class Tool implements \JsonSerializable
|
||||||
$data['inputSchema']['properties'] = new \stdClass();
|
$data['inputSchema']['properties'] = new \stdClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($data['outputSchema']) && \is_array($data['outputSchema'])) {
|
||||||
|
if (!isset($data['outputSchema']['type']) || 'object' !== $data['outputSchema']['type']) {
|
||||||
|
throw new InvalidArgumentException('Tool outputSchema must be of type "object".');
|
||||||
|
}
|
||||||
|
if (isset($data['outputSchema']['properties']) && \is_array($data['outputSchema']['properties']) && empty($data['outputSchema']['properties'])) {
|
||||||
|
$data['outputSchema']['properties'] = new \stdClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new self(
|
return new self(
|
||||||
$data['name'],
|
$data['name'],
|
||||||
$data['inputSchema'],
|
$data['inputSchema'],
|
||||||
isset($data['description']) && \is_string($data['description']) ? $data['description'] : null,
|
isset($data['description']) && \is_string($data['description']) ? $data['description'] : null,
|
||||||
isset($data['annotations']) && \is_array($data['annotations']) ? ToolAnnotations::fromArray($data['annotations']) : null,
|
isset($data['annotations']) && \is_array($data['annotations']) ? ToolAnnotations::fromArray($data['annotations']) : null,
|
||||||
isset($data['icons']) && \is_array($data['icons']) ? array_map(Icon::fromArray(...), $data['icons']) : null,
|
isset($data['icons']) && \is_array($data['icons']) ? array_map(Icon::fromArray(...), $data['icons']) : null,
|
||||||
isset($data['_meta']) && \is_array($data['_meta']) ? $data['_meta'] : null
|
isset($data['_meta']) && \is_array($data['_meta']) ? $data['_meta'] : null,
|
||||||
|
isset($data['outputSchema']) && \is_array($data['outputSchema']) ? $data['outputSchema'] : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,7 +115,8 @@ class Tool implements \JsonSerializable
|
||||||
* description?: string,
|
* description?: string,
|
||||||
* annotations?: ToolAnnotations,
|
* annotations?: ToolAnnotations,
|
||||||
* icons?: Icon[],
|
* icons?: Icon[],
|
||||||
* _meta?: array<string, mixed>
|
* _meta?: array<string, mixed>,
|
||||||
|
* outputSchema?: ToolOutputSchema
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
|
|
@ -116,6 +137,9 @@ class Tool implements \JsonSerializable
|
||||||
if (null !== $this->meta) {
|
if (null !== $this->meta) {
|
||||||
$data['_meta'] = $this->meta;
|
$data['_meta'] = $this->meta;
|
||||||
}
|
}
|
||||||
|
if (null !== $this->outputSchema) {
|
||||||
|
$data['outputSchema'] = $this->outputSchema;
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,8 @@ final class Builder
|
||||||
* description: ?string,
|
* description: ?string,
|
||||||
* annotations: ?ToolAnnotations,
|
* annotations: ?ToolAnnotations,
|
||||||
* icons: ?Icon[],
|
* icons: ?Icon[],
|
||||||
* meta: ?array<string, mixed>
|
* meta: ?array<string, mixed>,
|
||||||
|
* outputSchema: ?array<string, mixed>,
|
||||||
* }[]
|
* }[]
|
||||||
*/
|
*/
|
||||||
private array $tools = [];
|
private array $tools = [];
|
||||||
|
|
@ -330,6 +331,7 @@ final class Builder
|
||||||
* @param array<string, mixed>|null $inputSchema
|
* @param array<string, mixed>|null $inputSchema
|
||||||
* @param ?Icon[] $icons
|
* @param ?Icon[] $icons
|
||||||
* @param array<string, mixed>|null $meta
|
* @param array<string, mixed>|null $meta
|
||||||
|
* @param array<string, mixed>|null $outputSchema
|
||||||
*/
|
*/
|
||||||
public function addTool(
|
public function addTool(
|
||||||
callable|array|string $handler,
|
callable|array|string $handler,
|
||||||
|
|
@ -339,6 +341,7 @@ final class Builder
|
||||||
?array $inputSchema = null,
|
?array $inputSchema = null,
|
||||||
?array $icons = null,
|
?array $icons = null,
|
||||||
?array $meta = null,
|
?array $meta = null,
|
||||||
|
?array $outputSchema = null,
|
||||||
): self {
|
): self {
|
||||||
$this->tools[] = compact(
|
$this->tools[] = compact(
|
||||||
'handler',
|
'handler',
|
||||||
|
|
@ -348,6 +351,7 @@ final class Builder
|
||||||
'inputSchema',
|
'inputSchema',
|
||||||
'icons',
|
'icons',
|
||||||
'meta',
|
'meta',
|
||||||
|
'outputSchema',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,16 @@ final class CallToolHandler implements RequestHandlerInterface
|
||||||
|
|
||||||
$result = $this->referenceHandler->handle($reference, $arguments);
|
$result = $this->referenceHandler->handle($reference, $arguments);
|
||||||
|
|
||||||
|
$structuredContent = null;
|
||||||
if (!$result instanceof CallToolResult) {
|
if (!$result instanceof CallToolResult) {
|
||||||
$result = new CallToolResult($reference->formatResult($result));
|
$structuredContent = $reference->extractStructuredContent($result);
|
||||||
|
$result = new CallToolResult($reference->formatResult($result), structuredContent: $structuredContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->debug('Tool executed successfully', [
|
$this->logger->debug('Tool executed successfully', [
|
||||||
'name' => $toolName,
|
'name' => $toolName,
|
||||||
'result_type' => \gettype($result),
|
'result_type' => \gettype($result),
|
||||||
|
'structured_content' => $structuredContent,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return new Response($request->getId(), $result);
|
return new Response($request->getId(), $result);
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,13 @@
|
||||||
|
|
||||||
namespace Mcp\Tests\Conformance;
|
namespace Mcp\Tests\Conformance;
|
||||||
|
|
||||||
use Mcp\Schema\Content\Content;
|
|
||||||
use Mcp\Schema\Content\EmbeddedResource;
|
use Mcp\Schema\Content\EmbeddedResource;
|
||||||
use Mcp\Schema\Content\ImageContent;
|
use Mcp\Schema\Content\ImageContent;
|
||||||
use Mcp\Schema\Content\PromptMessage;
|
use Mcp\Schema\Content\PromptMessage;
|
||||||
use Mcp\Schema\Content\TextContent;
|
use Mcp\Schema\Content\TextContent;
|
||||||
use Mcp\Schema\Content\TextResourceContents;
|
use Mcp\Schema\Content\TextResourceContents;
|
||||||
use Mcp\Schema\Enum\Role;
|
use Mcp\Schema\Enum\Role;
|
||||||
|
use Mcp\Schema\Result\CallToolResult;
|
||||||
use Mcp\Server\Protocol;
|
use Mcp\Server\Protocol;
|
||||||
use Mcp\Server\RequestContext;
|
use Mcp\Server\RequestContext;
|
||||||
|
|
||||||
|
|
@ -26,12 +26,9 @@ final class Elements
|
||||||
public const TEST_IMAGE_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==';
|
public const TEST_IMAGE_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==';
|
||||||
public const TEST_AUDIO_BASE64 = 'UklGRiYAAABXQVZFZm10IBAAAAABAAEAQB8AAAB9AAACABAAZGF0YQIAAAA=';
|
public const TEST_AUDIO_BASE64 = 'UklGRiYAAABXQVZFZm10IBAAAAABAAEAQB8AAAB9AAACABAAZGF0YQIAAAA=';
|
||||||
|
|
||||||
/**
|
public function toolMultipleTypes(): CallToolResult
|
||||||
* @return Content[]
|
|
||||||
*/
|
|
||||||
public function toolMultipleTypes(): array
|
|
||||||
{
|
{
|
||||||
return [
|
return new CallToolResult([
|
||||||
new TextContent('Multiple content types test:'),
|
new TextContent('Multiple content types test:'),
|
||||||
new ImageContent(self::TEST_IMAGE_BASE64, 'image/png'),
|
new ImageContent(self::TEST_IMAGE_BASE64, 'image/png'),
|
||||||
EmbeddedResource::fromText(
|
EmbeddedResource::fromText(
|
||||||
|
|
@ -39,7 +36,7 @@ final class Elements
|
||||||
'{ "test" = "data", "value" = 123 }',
|
'{ "test" = "data", "value" = 123 }',
|
||||||
'application/json',
|
'application/json',
|
||||||
),
|
),
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toolWithLogging(RequestContext $context): string
|
public function toolWithLogging(RequestContext $context): string
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,18 @@
|
||||||
"text": "{\n \"success\": true,\n \"message\": \"Event \\\"Project Deadline\\\" scheduled successfully for \\\"2024-12-15\\\".\",\n \"event_details\": {\n \"title\": \"Project Deadline\",\n \"date\": \"2024-12-15\",\n \"type\": \"reminder\",\n \"time\": \"All day\",\n \"priority\": \"Normal\",\n \"attendees\": [],\n \"invites_will_be_sent\": false\n }\n}"
|
"text": "{\n \"success\": true,\n \"message\": \"Event \\\"Project Deadline\\\" scheduled successfully for \\\"2024-12-15\\\".\",\n \"event_details\": {\n \"title\": \"Project Deadline\",\n \"date\": \"2024-12-15\",\n \"type\": \"reminder\",\n \"time\": \"All day\",\n \"priority\": \"Normal\",\n \"attendees\": [],\n \"invites_will_be_sent\": false\n }\n}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"structuredContent": {
|
||||||
|
"success": true,
|
||||||
|
"message": "Event \"Project Deadline\" scheduled successfully for \"2024-12-15\".",
|
||||||
|
"event_details": {
|
||||||
|
"title": "Project Deadline",
|
||||||
|
"date": "2024-12-15",
|
||||||
|
"type": "reminder",
|
||||||
|
"time": "All day",
|
||||||
|
"priority": "Normal",
|
||||||
|
"attendees": [],
|
||||||
|
"invites_will_be_sent": false
|
||||||
|
}
|
||||||
|
},
|
||||||
"isError": false
|
"isError": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,20 @@
|
||||||
"text": "{\n \"success\": true,\n \"message\": \"Event \\\"Client Call\\\" scheduled successfully for \\\"2024-12-02\\\".\",\n \"event_details\": {\n \"title\": \"Client Call\",\n \"date\": \"2024-12-02\",\n \"type\": \"call\",\n \"time\": \"14:30\",\n \"priority\": \"Normal\",\n \"attendees\": [\n \"client@example.com\"\n ],\n \"invites_will_be_sent\": false\n }\n}"
|
"text": "{\n \"success\": true,\n \"message\": \"Event \\\"Client Call\\\" scheduled successfully for \\\"2024-12-02\\\".\",\n \"event_details\": {\n \"title\": \"Client Call\",\n \"date\": \"2024-12-02\",\n \"type\": \"call\",\n \"time\": \"14:30\",\n \"priority\": \"Normal\",\n \"attendees\": [\n \"client@example.com\"\n ],\n \"invites_will_be_sent\": false\n }\n}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"structuredContent": {
|
||||||
|
"success": true,
|
||||||
|
"message": "Event \"Client Call\" scheduled successfully for \"2024-12-02\".",
|
||||||
|
"event_details": {
|
||||||
|
"title": "Client Call",
|
||||||
|
"date": "2024-12-02",
|
||||||
|
"type": "call",
|
||||||
|
"time": "14:30",
|
||||||
|
"priority": "Normal",
|
||||||
|
"attendees": [
|
||||||
|
"client@example.com"
|
||||||
|
],
|
||||||
|
"invites_will_be_sent": false
|
||||||
|
}
|
||||||
|
},
|
||||||
"isError": false
|
"isError": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,20 @@
|
||||||
"text": "{\n \"success\": true,\n \"message\": \"Event \\\"Office Party\\\" scheduled successfully for \\\"2024-12-20\\\".\",\n \"event_details\": {\n \"title\": \"Office Party\",\n \"date\": \"2024-12-20\",\n \"type\": \"other\",\n \"time\": \"18:00\",\n \"priority\": \"Normal\",\n \"attendees\": [\n \"team@company.com\"\n ],\n \"invites_will_be_sent\": true\n }\n}"
|
"text": "{\n \"success\": true,\n \"message\": \"Event \\\"Office Party\\\" scheduled successfully for \\\"2024-12-20\\\".\",\n \"event_details\": {\n \"title\": \"Office Party\",\n \"date\": \"2024-12-20\",\n \"type\": \"other\",\n \"time\": \"18:00\",\n \"priority\": \"Normal\",\n \"attendees\": [\n \"team@company.com\"\n ],\n \"invites_will_be_sent\": true\n }\n}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"structuredContent": {
|
||||||
|
"success": true,
|
||||||
|
"message": "Event \"Office Party\" scheduled successfully for \"2024-12-20\".",
|
||||||
|
"event_details": {
|
||||||
|
"title": "Office Party",
|
||||||
|
"date": "2024-12-20",
|
||||||
|
"type": "other",
|
||||||
|
"time": "18:00",
|
||||||
|
"priority": "Normal",
|
||||||
|
"attendees": [
|
||||||
|
"team@company.com"
|
||||||
|
],
|
||||||
|
"invites_will_be_sent": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"isError": false
|
"isError": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,21 @@
|
||||||
"text": "{\n \"success\": true,\n \"message\": \"Event \\\"Team Standup\\\" scheduled successfully for \\\"2024-12-01\\\".\",\n \"event_details\": {\n \"title\": \"Team Standup\",\n \"date\": \"2024-12-01\",\n \"type\": \"meeting\",\n \"time\": \"09:00\",\n \"priority\": \"Normal\",\n \"attendees\": [\n \"alice@example.com\",\n \"bob@example.com\"\n ],\n \"invites_will_be_sent\": true\n }\n}"
|
"text": "{\n \"success\": true,\n \"message\": \"Event \\\"Team Standup\\\" scheduled successfully for \\\"2024-12-01\\\".\",\n \"event_details\": {\n \"title\": \"Team Standup\",\n \"date\": \"2024-12-01\",\n \"type\": \"meeting\",\n \"time\": \"09:00\",\n \"priority\": \"Normal\",\n \"attendees\": [\n \"alice@example.com\",\n \"bob@example.com\"\n ],\n \"invites_will_be_sent\": true\n }\n}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"structuredContent": {
|
||||||
|
"success": true,
|
||||||
|
"message": "Event \"Team Standup\" scheduled successfully for \"2024-12-01\".",
|
||||||
|
"event_details": {
|
||||||
|
"title": "Team Standup",
|
||||||
|
"date": "2024-12-01",
|
||||||
|
"type": "meeting",
|
||||||
|
"time": "09:00",
|
||||||
|
"priority": "Normal",
|
||||||
|
"attendees": [
|
||||||
|
"alice@example.com",
|
||||||
|
"bob@example.com"
|
||||||
|
],
|
||||||
|
"invites_will_be_sent": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"isError": false
|
"isError": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,9 @@
|
||||||
"text": "{\n \"success\": true,\n \"message_sent\": \"Welcome, Alice! Welcome to our platform!\"\n}"
|
"text": "{\n \"success\": true,\n \"message_sent\": \"Welcome, Alice! Welcome to our platform!\"\n}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"structuredContent": {
|
||||||
|
"success": true,
|
||||||
|
"message_sent": "Welcome, Alice! Welcome to our platform!"
|
||||||
|
},
|
||||||
"isError": false
|
"isError": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,9 @@
|
||||||
"text": "{\n \"success\": true,\n \"message\": \"Test tool without params\"\n}"
|
"text": "{\n \"success\": true,\n \"message\": \"Test tool without params\"\n}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"structuredContent": {
|
||||||
|
"success": true,
|
||||||
|
"message": "Test tool without params"
|
||||||
|
},
|
||||||
"isError": false
|
"isError": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,11 @@
|
||||||
"text": "{\n \"result\": 50,\n \"operation\": \"10 multiply 5\",\n \"precision\": 2,\n \"within_bounds\": true\n}"
|
"text": "{\n \"result\": 50,\n \"operation\": \"10 multiply 5\",\n \"precision\": 2,\n \"within_bounds\": true\n}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"structuredContent": {
|
||||||
|
"result": 50,
|
||||||
|
"operation": "10 multiply 5",
|
||||||
|
"precision": 2,
|
||||||
|
"within_bounds": true
|
||||||
|
},
|
||||||
"isError": false
|
"isError": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,11 @@
|
||||||
"text": "{\n \"original\": \"Hello World Test\",\n \"formatted\": \"HELLO WORLD TEST\",\n \"length\": 16,\n \"format_applied\": \"uppercase\"\n}"
|
"text": "{\n \"original\": \"Hello World Test\",\n \"formatted\": \"HELLO WORLD TEST\",\n \"length\": 16,\n \"format_applied\": \"uppercase\"\n}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"structuredContent": {
|
||||||
|
"original": "Hello World Test",
|
||||||
|
"formatted": "HELLO WORLD TEST",
|
||||||
|
"length": 16,
|
||||||
|
"format_applied": "uppercase"
|
||||||
|
},
|
||||||
"isError": false
|
"isError": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue