1: <?php
2:
3: declare(strict_types=1);
4:
5: /**
6: * This file is part of the Nexus MCP SDK package.
7: *
8: * (c) 2026 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9: *
10: * For the full copyright and license information, please view
11: * the LICENSE file that was distributed with this source code.
12: */
13:
14: namespace Nexus\Mcp\Core\Schema\RequestParams;
15:
16: use Nexus\Assert\Assert;
17: use Nexus\Mcp\Core\Schema\RequestMetaObject;
18: use Nexus\Mcp\Core\Schema\Task\TaskMetadata;
19: use Nexus\Mcp\Core\Validation\IdentifierNameValidator;
20:
21: /**
22: * Parameters for a `tools/call` request.
23: *
24: * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#calltoolrequestparams
25: */
26: final readonly class CallToolRequestParams extends TaskAugmentedRequestParams
27: {
28: /**
29: * @var non-empty-string
30: */
31: public string $name;
32:
33: /**
34: * @var null|array<string, mixed>
35: */
36: public ?array $arguments;
37:
38: /**
39: * @param null|array<string, mixed> $arguments
40: */
41: public function __construct(
42: string $name,
43: ?array $arguments = null,
44: ?TaskMetadata $task = null,
45: RequestMetaObject $meta = new RequestMetaObject(),
46: ) {
47: IdentifierNameValidator::validate($name, '"params.name"');
48:
49: if (null !== $arguments) {
50: Assert::that($arguments)->isMap('"params.arguments" must be a string-keyed map.');
51: }
52:
53: $this->name = $name;
54: $this->arguments = $arguments;
55:
56: parent::__construct($task, $meta);
57: }
58:
59: #[\Override]
60: public static function fromArray(array $data): static
61: {
62: Assert::that($data)->hasOffset('name', 'missing the required "name" key.');
63: $name = $data['name'];
64: Assert::that($name)->isString('"params.name" must be a string, {type} given.');
65:
66: $arguments = null;
67:
68: if (\array_key_exists('arguments', $data)) {
69: Assert::that($data['arguments'])
70: ->isArray('"params.arguments" must be an object, {type} given.')
71: ->isMap('"params.arguments" must be a string-keyed object.')
72: ;
73: $arguments = $data['arguments'];
74: }
75:
76: $task = null;
77:
78: if (\array_key_exists('task', $data)) {
79: Assert::that($data['task'])
80: ->isArray('"params.task" must be an object, {type} given.')
81: ->isMap('"params.task" must be a string-keyed object.')
82: ;
83: $task = TaskMetadata::fromArray($data['task']);
84: }
85:
86: $meta = new RequestMetaObject();
87:
88: if (\array_key_exists('_meta', $data)) {
89: Assert::that($data['_meta'])
90: ->isArray('"params._meta" must be an object, {type} given.')
91: ->isMap('"params._meta" must be a string-keyed object.')
92: ;
93: $meta = RequestMetaObject::fromArray($data['_meta']);
94: }
95:
96: return new self($name, $arguments, $task, $meta);
97: }
98:
99: #[\Override]
100: public function toArray(): array
101: {
102: $data = ['name' => $this->name];
103:
104: if ([] !== ($this->arguments ?? [])) {
105: $data['arguments'] = $this->arguments;
106: }
107:
108: return [...parent::toArray(), ...$data];
109: }
110:
111: #[\Override]
112: public function jsonSerialize(): array
113: {
114: return $this->toArray();
115: }
116: }
117: