From 59e0d94b51aaf6ed0a1d7a58a7d4f768e0343092 Mon Sep 17 00:00:00 2001 From: jaeminbird Date: Thu, 29 Oct 2026 01:54:50 -0400 Subject: [PATCH] [Capability] Check tool names against the spec's 128-character limit and character set --- CHANGELOG.md | 1 + src/Capability/Registry.php | 2 +- src/Capability/Tool/NameValidator.php | 2 +- tests/Unit/Capability/Tool/NameValidatorTest.php | 6 ++++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a936955cb..46f824f28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to `mcp/sdk` will be documented in this file. * Fix tools, prompts and resources sending `content`, `messages` and `contents` as a JSON object instead of an array when the handler returned a non-list array, e.g. the result of `array_filter()`. Named keys in nested results of mixed arrays no longer overwrite each other. * Fix `SecureUrl` rejecting plain http on hosts under the reserved `.localhost` TLD (RFC 6761) and on IPv4 loopback addresses other than `127.0.0.1`, so `ProtectedResourceMetadata`, `OidcDiscovery` and `JwtTokenValidator::fromIssuer()` failed for local development setups like `http://shop.localhost:8080`. Plain http is now accepted for `localhost`, any `*.localhost`, `127.0.0.0/8` and `::1`; every other host still requires https. * Tool, prompt and resource results and `TextContent` encode arrays and objects as compact JSON instead of pretty-printed JSON. +* Fix tool name validation not following the spec's rule (1 to 128 characters of `A-Z`, `a-z`, `0-9`, `_`, `-` and `.`): names of 65 to 128 characters no longer log a warning, while names with a `/` or a trailing newline now do. * Add `Psr6SessionStore` and `Psr6NotificationBus`, which work like `Psr16SessionStore` and `Psr16NotificationBus` over a PSR-6 cache pool. `Builder::setDiscovery()` also accepts a PSR-6 pool as `$cache`. ### Client diff --git a/src/Capability/Registry.php b/src/Capability/Registry.php index f9f91c173..620f7863d 100644 --- a/src/Capability/Registry.php +++ b/src/Capability/Registry.php @@ -119,7 +119,7 @@ public function registerTool(Tool $tool, callable|array|string $handler): ToolRe { if (!$this->nameValidator->isValid($tool->name)) { $this->logger->warning( - \sprintf('Tool name "%s" is invalid. Tool names should only contain letters (a-z, A-Z), numbers, dots, hyphens, underscores, and forward slashes.', $tool->name), + \sprintf('Tool name "%s" is invalid. Tool names should be 1 to 128 characters long and only contain letters (a-z, A-Z), numbers, dots, hyphens and underscores.', $tool->name), ); } diff --git a/src/Capability/Tool/NameValidator.php b/src/Capability/Tool/NameValidator.php index fe9bb0846..231675fd3 100644 --- a/src/Capability/Tool/NameValidator.php +++ b/src/Capability/Tool/NameValidator.php @@ -15,6 +15,6 @@ final class NameValidator { public function isValid(string $name): bool { - return 1 === preg_match('/^[a-zA-Z0-9._\/-]{1,64}$/', $name); + return 1 === preg_match('/^[a-zA-Z0-9._-]{1,128}$/D', $name); } } diff --git a/tests/Unit/Capability/Tool/NameValidatorTest.php b/tests/Unit/Capability/Tool/NameValidatorTest.php index 269be890d..e2daa8499 100644 --- a/tests/Unit/Capability/Tool/NameValidatorTest.php +++ b/tests/Unit/Capability/Tool/NameValidatorTest.php @@ -30,9 +30,9 @@ public static function provideValidNames(): array ['MyTool123'], ['my.tool'], ['my-tool'], - ['my/tool'], ['my_tool-01.02'], ['my_long_toolname_that_is_exactly_sixty_four_characters_long_1234'], + [str_repeat('a', 128)], ]; } @@ -50,7 +50,9 @@ public static function provideInvalidNames(): array ['my@tool'], ['my!tool'], ['my_tool#1'], - ['this_tool_name_is_way_too_long_because_it_exceeds_the_sixty_four_character_limit_set_by_the_validator'], + ['my/tool'], + ["my_tool\n"], + [str_repeat('a', 129)], ]; } }