Skip to content

Commit c6490a3

Browse files
committed
Add ToolSchema and StringType
1 parent 83948a2 commit c6490a3

File tree

4 files changed

+475
-0
lines changed

4 files changed

+475
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of the Nexus MCP SDK package.
7+
*
8+
* (c) 2025 John Paul E. Balandan, CPA <[email protected]>
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\Schema\Tool\ToolSchema;
15+
16+
/**
17+
* The `string` type is used for validating strings/texts containing Unicode characters.
18+
*
19+
* @extends ToolSchema<string, array{
20+
* type: 'string',
21+
* description?: non-empty-string,
22+
* title?: non-empty-string,
23+
* minLength?: int<0, max>,
24+
* maxLength?: int<0, max>,
25+
* pattern?: non-empty-string,
26+
* default?: string
27+
* }>
28+
*/
29+
final class StringType extends ToolSchema
30+
{
31+
/**
32+
* @var null|int<0, max>
33+
*/
34+
private ?int $minLength = null;
35+
36+
/**
37+
* @var null|int<0, max>
38+
*/
39+
private ?int $maxLength = null;
40+
41+
/**
42+
* @var null|non-empty-string
43+
*/
44+
private ?string $pattern = null;
45+
46+
public function minLength(int $minLength): self
47+
{
48+
if ($minLength < 0) {
49+
throw new \InvalidArgumentException('The minimum length must be a non-negative integer.');
50+
}
51+
52+
$this->minLength = $minLength;
53+
54+
return $this;
55+
}
56+
57+
public function maxLength(int $maxLength): self
58+
{
59+
if ($maxLength < 0) {
60+
throw new \InvalidArgumentException('The maximum length must be a non-negative integer.');
61+
}
62+
63+
$this->maxLength = $maxLength;
64+
65+
return $this;
66+
}
67+
68+
/**
69+
* @param non-empty-string $pattern
70+
*/
71+
public function pattern(string $pattern): self
72+
{
73+
set_error_handler(static function (int $errno, string $errstr): bool {
74+
$errstr = str_replace('preg_match(): Compilation failed: ', '', $errstr);
75+
76+
throw new \InvalidArgumentException(\sprintf('Invalid regex pattern: %s', ucfirst($errstr)), $errno);
77+
});
78+
79+
try {
80+
preg_match(\sprintf('/%s/uD', $pattern), '');
81+
$this->pattern = $pattern;
82+
} finally {
83+
restore_error_handler();
84+
}
85+
86+
return $this;
87+
}
88+
89+
#[\Override]
90+
public function toArray(): array
91+
{
92+
if (isset($this->minLength, $this->maxLength) && $this->minLength > $this->maxLength) {
93+
throw new \LogicException('The minimum length cannot be greater than the maximum length.');
94+
}
95+
96+
if (isset($this->default, $this->minLength) && \strlen($this->default) < $this->minLength) {
97+
throw new \LogicException('The default value length cannot be less than the minimum length.');
98+
}
99+
100+
if (isset($this->default, $this->maxLength) && \strlen($this->default) > $this->maxLength) {
101+
throw new \LogicException('The default value length cannot be greater than the maximum length.');
102+
}
103+
104+
return array_filter([
105+
'type' => 'string',
106+
'description' => $this->description,
107+
'title' => $this->title,
108+
'minLength' => $this->minLength,
109+
'maxLength' => $this->maxLength,
110+
'pattern' => $this->pattern,
111+
'default' => $this->default,
112+
], static fn(mixed $value): bool => null !== $value);
113+
}
114+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of the Nexus MCP SDK package.
7+
*
8+
* (c) 2025 John Paul E. Balandan, CPA <[email protected]>
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\Schema\Tool\ToolSchema;
15+
16+
use Nexus\Mcp\Schema\Arrayable;
17+
18+
/**
19+
* A JSON schema object defining the expected parameters for the tool or the structure of the tool's output
20+
* returned in the `structuredContent` field of a `CallToolResult`.
21+
*
22+
* @template T
23+
* @template U of array<string, mixed>
24+
*
25+
* @implements Arrayable<U>
26+
*/
27+
abstract class ToolSchema implements \JsonSerializable, Arrayable
28+
{
29+
/**
30+
* @var null|non-empty-string
31+
*/
32+
protected ?string $title = null;
33+
34+
/**
35+
* @var null|non-empty-string
36+
*/
37+
protected ?string $description = null;
38+
39+
/**
40+
* @var null|T
41+
*/
42+
protected mixed $default = null;
43+
44+
private bool $required = false;
45+
46+
/**
47+
* @param non-empty-string $name
48+
*/
49+
protected function __construct(
50+
public readonly string $name,
51+
) {}
52+
53+
/**
54+
* @param non-empty-string $name
55+
*/
56+
public static function fromString(string $name): StringType
57+
{
58+
return new StringType($name);
59+
}
60+
61+
/**
62+
* @param non-empty-string $title
63+
*/
64+
public function title(string $title): static
65+
{
66+
$this->title = $title;
67+
68+
return $this;
69+
}
70+
71+
/**
72+
* @param non-empty-string $description
73+
*/
74+
public function description(string $description): static
75+
{
76+
$this->description = $description;
77+
78+
return $this;
79+
}
80+
81+
/**
82+
* @param T $default
83+
*/
84+
public function default(mixed $default): static
85+
{
86+
$this->default = $default;
87+
88+
return $this;
89+
}
90+
91+
public function required(): static
92+
{
93+
$this->required = true;
94+
95+
return $this;
96+
}
97+
98+
public function isRequired(): bool
99+
{
100+
return $this->required;
101+
}
102+
103+
/**
104+
* @return template-type<static, Arrayable, 'T'>
105+
*/
106+
#[\Override]
107+
public function jsonSerialize(): array
108+
{
109+
return $this->toArray();
110+
}
111+
}

0 commit comments

Comments
 (0)