| 42 | * @see https://modelcontextprotocol.io/specification/2025-06-18/basic/index#meta |
| 43 | */ |
| 44 | const normalizeSegment = (segment: string): string | null => { |
| 45 | if (!segment) return null; |
| 46 | let normalized = segment.trim().toLowerCase(); |
| 47 | if (!normalized) return null; |
| 48 | |
| 49 | const schemeIndex = normalized.indexOf("://"); |
| 50 | if (schemeIndex !== -1) { |
| 51 | normalized = normalized.slice(schemeIndex + 3); |
| 52 | } |
| 53 | |
| 54 | const stopChars = ["?", "#", ":"]; |
| 55 | let endIndex = normalized.length; |
| 56 | stopChars.forEach((char) => { |
| 57 | const idx = normalized.indexOf(char); |
| 58 | if (idx !== -1 && idx < endIndex) { |
| 59 | endIndex = idx; |
| 60 | } |
| 61 | }); |
| 62 | |
| 63 | return normalized.slice(0, endIndex) || null; |
| 64 | }; |
| 65 | |
| 66 | /** |
| 67 | * Splits a normalized prefix into dot-separated labels and validates each label |