PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.8
Booking for Appointments and Events Calendar – Amelia v2.4.8
2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / vendor / wordpress / mcp-adapter / includes / Domain / Utils / McpNameSanitizer.php
ameliabooking / vendor / wordpress / mcp-adapter / includes / Domain / Utils Last commit date
AbilityArgumentNormalizer.php 3 months ago ContentBlockHelper.php 3 months ago McpAnnotationMapper.php 3 months ago McpNameSanitizer.php 3 months ago McpValidator.php 3 months ago SchemaTransformer.php 3 months ago
McpNameSanitizer.php
115 lines
1 <?php
2 /**
3 * MCP Name Sanitizer utility for normalizing component names.
4 *
5 * @package McpAdapter
6 */
7
8 declare( strict_types=1 );
9
10 namespace WP\MCP\Domain\Utils;
11
12 use WP_Error;
13
14 /**
15 * Utility class for sanitizing names to MCP-valid format.
16 *
17 * Implements best-effort sanitization per MCP 2025-11-25 spec:
18 * - Length: 1-128 characters
19 * - Charset: A-Za-z0-9_.-
20 *
21 * Used for both tools and prompts (same naming rules).
22 * NOT used for resources (which use URIs as identifiers).
23 *
24 * @since 0.5.0
25 */
26 class McpNameSanitizer {
27
28 /**
29 * Maximum length for MCP tool/prompt names per spec.
30 *
31 * @var int
32 */
33 public const MAX_LENGTH = 128;
34
35 /**
36 * Length of the hash suffix used for truncation uniqueness.
37 *
38 * @var int
39 */
40 public const HASH_LENGTH = 12;
41
42 /**
43 * Maximum characters to keep when truncating (MAX_LENGTH - 1 separator - HASH_LENGTH).
44 *
45 * @var int
46 */
47 public const TRUNCATE_LENGTH = 115;
48
49 /**
50 * Sanitize a name to be MCP-valid for tools and prompts.
51 *
52 * Normalization steps:
53 * 1. Trim whitespace
54 * 2. Replace `/` with `-` (forward slash not allowed in MCP)
55 * 3. If valid, return as-is
56 * 4. Otherwise: transliterate accents, replace invalid chars, collapse hyphens, trim edges
57 * 5. If too long: truncate + add hash suffix for uniqueness
58 * 6. If still invalid/empty: return WP_Error
59 *
60 * @param string $name Original name.
61 *
62 * @return string|\WP_Error Sanitized name or WP_Error if unsalvageable.
63 * @since 0.5.0
64 *
65 */
66 public static function sanitize_name( string $name ) {
67 $original = $name;
68
69 // Step 1: Trim whitespace.
70 $name = trim( $name );
71
72 // Step 2: Replace / with - (forward slash not allowed in MCP).
73 $name = str_replace( '/', '-', $name );
74
75 // Step 3: Early validation - if already valid, return as-is.
76 if ( McpValidator::validate_name( $name ) ) {
77 return $name;
78 }
79
80 // Step 4a: Transliterate accented characters to ASCII equivalents.
81 // Uses WordPress core function: é→e, ü→u, ñ→n, etc.
82 $name = remove_accents( $name );
83
84 // Step 4b: Replace any remaining non-allowed chars with hyphen.
85 $name = (string) preg_replace( '/[^a-zA-Z0-9_.-]/', '-', $name );
86
87 // Step 4c: Collapse consecutive hyphens.
88 $name = (string) preg_replace( '/-+/', '-', $name );
89
90 // Step 4d: Trim leading/trailing hyphens and underscores.
91 $name = trim( $name, '-_' );
92
93 // Step 5: Handle length > 128.
94 if ( strlen( $name ) > self::MAX_LENGTH ) {
95 $hash = substr( md5( $original ), 0, self::HASH_LENGTH );
96 $name = substr( $name, 0, self::TRUNCATE_LENGTH ) . '-' . $hash;
97 }
98
99 // Step 6: Final check - only empty is possible failure after sanitization.
100 // Characters are guaranteed valid (replaced), length is handled (truncated).
101 if ( empty( $name ) ) {
102 return new WP_Error(
103 'mcp_name_invalid',
104 sprintf(
105 /* translators: %s: original ability name */
106 __( 'Unable to derive valid MCP name from: %s', 'mcp-adapter' ),
107 $original
108 )
109 );
110 }
111
112 return $name;
113 }
114 }
115