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\Task;
15:
16: use Nexus\Assert\Assert;
17: use Nexus\Mcp\Core\Schema\Arrayable;
18: use Nexus\Mcp\Core\Schema\Enum\TaskStatus;
19: use Nexus\Mcp\Core\Validation\EnumValueValidator;
20: use Nexus\Mcp\Core\Validation\Iso8601DateTimeValidator;
21:
22: /**
23: * Data associated with a task.
24: *
25: * @implements Arrayable<array{
26: * taskId: non-empty-string,
27: * status: value-of<TaskStatus>,
28: * createdAt: non-empty-string,
29: * lastUpdatedAt: non-empty-string,
30: * ttl: null|int,
31: * statusMessage?: non-empty-string,
32: * pollInterval?: int,
33: * }>
34: *
35: * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#task
36: */
37: final readonly class Task implements Arrayable
38: {
39: /**
40: * @var non-empty-string
41: */
42: public string $taskId;
43:
44: public \DateTimeImmutable $createdAt;
45: public \DateTimeImmutable $lastUpdatedAt;
46:
47: /**
48: * @var null|non-empty-string
49: */
50: public ?string $statusMessage;
51:
52: public function __construct(
53: string $taskId,
54: public TaskStatus $status,
55: string $createdAt,
56: string $lastUpdatedAt,
57: public ?int $ttl,
58: ?string $statusMessage = null,
59: public ?int $pollInterval = null,
60: ) {
61: Assert::that($taskId)->isNonEmptyString('task "taskId" must be a non-empty string.');
62: Assert::that($statusMessage)->nullOr()->isNonEmptyString('task "statusMessage" must be a non-empty string or null.');
63: Assert::that($ttl)->nullOr()->isNaturalInt('task "ttl" must be a non-negative integer or null.');
64: Assert::that($pollInterval)->nullOr()->isNaturalInt('task "pollInterval" must be a non-negative integer or null.');
65:
66: $this->taskId = $taskId;
67: $this->createdAt = Iso8601DateTimeValidator::parse($createdAt, 'task "createdAt"');
68: $this->lastUpdatedAt = Iso8601DateTimeValidator::parse($lastUpdatedAt, 'task "lastUpdatedAt"');
69: $this->statusMessage = $statusMessage;
70: }
71:
72: /**
73: * @param array<string, mixed> $data
74: */
75: #[\Override]
76: public static function fromArray(array $data): static
77: {
78: Assert::that($data)->hasOffset('taskId', 'task missing the required "taskId" key.');
79: $taskId = $data['taskId'];
80: Assert::that($taskId)->isString('task "taskId" must be a string, {type} given.');
81:
82: Assert::that($data)->hasOffset('status', 'task missing the required "status" key.');
83: $status = EnumValueValidator::parse(TaskStatus::class, $data['status'], 'task "status"');
84:
85: Assert::that($data)->hasOffset('createdAt', 'task missing the required "createdAt" key.');
86: $createdAt = $data['createdAt'];
87: Assert::that($createdAt)->isString('task "createdAt" must be a string, {type} given.');
88:
89: Assert::that($data)->hasOffset('lastUpdatedAt', 'task missing the required "lastUpdatedAt" key.');
90: $lastUpdatedAt = $data['lastUpdatedAt'];
91: Assert::that($lastUpdatedAt)->isString('task "lastUpdatedAt" must be a string, {type} given.');
92:
93: Assert::that($data)->hasOffset('ttl', 'task missing the required "ttl" key.');
94: $ttl = $data['ttl'];
95: Assert::that($ttl)->nullOr()->isInt('task "ttl" must be an int or null, {type} given.');
96:
97: $statusMessage = $data['statusMessage'] ?? null;
98: Assert::that($statusMessage)->nullOr()->isString('task "statusMessage" must be a string or null, {type} given.');
99:
100: $pollInterval = $data['pollInterval'] ?? null;
101: Assert::that($pollInterval)->nullOr()->isInt('task "pollInterval" must be an int or null, {type} given.');
102:
103: return new self($taskId, $status, $createdAt, $lastUpdatedAt, $ttl, $statusMessage, $pollInterval);
104: }
105:
106: #[\Override]
107: public function toArray(): array
108: {
109: $data = [
110: 'taskId' => $this->taskId,
111: 'status' => $this->status->value,
112: 'createdAt' => Iso8601DateTimeValidator::format($this->createdAt),
113: 'lastUpdatedAt' => Iso8601DateTimeValidator::format($this->lastUpdatedAt),
114: 'ttl' => $this->ttl,
115: ];
116:
117: if (null !== $this->statusMessage) {
118: $data['statusMessage'] = $this->statusMessage;
119: }
120:
121: if (null !== $this->pollInterval) {
122: $data['pollInterval'] = $this->pollInterval;
123: }
124:
125: return $data;
126: }
127:
128: #[\Override]
129: public function jsonSerialize(): array
130: {
131: return $this->toArray();
132: }
133: }
134: